Как преобразовать большое десятичное число, хранящееся в виде строки, в двоичную строку, например:
'31314232352342341239081370934702357023470' => '10101101110101000011001101011101101001100010100111111100001011'
@AndreasRejbrand Я ничего не пробовал, потому что ничего не нашел. Все ваши ссылки для совершенно разных вещей. Мое десятичное число слишком велико, чтобы его можно было преобразовать в целое число, а ваши ссылки преобразуют целые числа в двоичные.
Не "совсем другой". Нисколько! :) Я мог бы написать для вас функцию позже сегодня, если кто-то не опередит меня, но, строго говоря, это не совсем то, как следует использовать переполнение стека.
@AndreasRejbrand Преобразование целого числа в двоичное очень просто - просто цикл получает последний бит с «и 1», а затем целое число shr 1. Преобразование шестнадцатеричного числа в двоичное также очень просто - каждая шестнадцатеричная цифра состоит всего из 4 двоичных цифр. Но с десятичной строкой я не вижу простых путей.
На самом деле, это совсем не сложно. Вы можете просто сделать это очень наивно так же, как вы делаете это с ручкой и бумагой. Но я напишу для вас простую функцию позже сегодня, если только кто-то не опередит меня или Q не будет закрыт.
Вы можете попробовать что-то вроде rvelthuis.de/programs/bigdecimals.html , которое является частью всего github.com/rvelthuis/DelphiBigNumbers
Ваш пример должен быть правильным?
@TomBrunberg Нет, это неправильно. Калькулятор Windows не мог преобразовать такое большое число.
Как я отметил в комментарии, сделать наивную реализацию такой функции совсем не сложно — вам просто нужно создать процедуру, которая делает то, что вы сделали бы сами, используя ручку и бумагу.
Итак, используя деление в длину, я разработал следующий (довольно неэффективный) код:
function DecStrToBinStr(const S: string): string;
procedure DivMod2Str(const S: string; out AQuotient: string; out ARemainder: Integer);
function Digit(C: Char): Integer;
begin
Result := Ord(C) - Ord('0');
end;
function DigitChar(D: Integer): Char;
begin
Result := Char(Ord('0') + D);
end;
function NumDig(AIndex: Integer): Integer;
begin
Result := Digit(S[AIndex]);
end;
begin
SetLength(AQuotient, S.Length);
ARemainder := 0;
if AQuotient = '' then
Exit;
var Q := NumDig(1);
for var i := 1 to S.Length do
begin
if not InRange(Ord(S[i]), Ord('0'), Ord('9')) then
raise Exception.Create('Invalid decimal number.');
ARemainder := Ord(Odd(Q));
Q := Q div 2;
AQuotient[i] := DigitChar(Q);
if i < S.Length then
Q := 10*ARemainder + NumDig(Succ(i));
end;
while (AQuotient.Length > 1) and (AQuotient[1] = '0') do
Delete(AQuotient, 1, 1);
end;
const
BitStrs: array[Boolean] of Char = ('0', '1');
begin
if S = '' then
Exit('');
var L := TList<Boolean>.Create;
try
var T := S;
var R := 0;
repeat
var Q: string;
DivMod2Str(T, Q, R);
L.Add(R = 1);
T := Q;
until T = '0';
SetLength(Result, L.Count);
for var i := 1 to Result.Length do
Result[i] := BitStrs[L[L.Count - i]];
finally
L.Free;
end;
end;
Это правильная, но уж точно не самая эффективная реализация.
Например, в соответствии с этой процедурой десятичное число
30347386718195039666223058436176179389328210368626940040845691245726092139866985
13829421448918578266312873948380914263473944921553341261772026398226410631065331
7294059719089452218
записывается как
11101111101001011110010001001010010100100011011010110111111000101000001111010111
00001000000111111000010100100001111100011101001010101110100101101001110100100100
01001010100110001111110111100001100111111111110101111011001001010011101000010010
00001100000001110100000101111111101111011010010011101000001000100111111010100011
10110000001010011110000101101101011101101010101011100010000011000111110010100001
01011010111110101010111100011110100100010110011110011001000100000111001110111010
01110101010100100010100001011101101001011110010110000100111010001101111000100011
111010110000001111111010010111010
в двоичном формате.
Вместо промежуточного списка я бы добавил '0'
и '1'
прямо в список DecStrToBinStr
result
. Также нельзя было назвать DivMod2Str
с (T, T, R)
? И быть функцией, которая могла бы сразу вернуть R
? Да, это какая-то придирка. ;-) Я просто хочу меньше многословия. И еще комментарии в коде.
@AmigoJack: я согласен с промежуточным списком. Я просто был ленив. (T, T, R)
невозможно без некоторых других изменений.
Что вы пробовали? Подобные вопросы задавались много раз. См., например, stackoverflow.com/questions/21361627/… , stackoverflow.com/questions/59548148/… , stackoverflow.com/questions/31697957/…