-1

How to convert big decimal stored as string into a binary string, eg:

'31314232352342341239081370934702357023470' => '10101101110101000011001101011101101001100010100111111100001011'

Tom
  • 2,962
  • 3
  • 39
  • 69
  • What have you tried? Questions similar to this one have been asked many times. See, for instance, https://stackoverflow.com/questions/21361627/converting-decimal-integer-to-binary-how-and-why-it-works-the-way-it-does, https://stackoverflow.com/questions/59548148/delphi-a-fast-way-to-convert-hex-string-to-binary-string, https://stackoverflow.com/questions/31697957/how-to-make-inttobin-function-return-96bits-binary-number – Andreas Rejbrand Nov 20 '22 at 13:56
  • @AndreasRejbrand I haven't tried anything because I didn't find anything. All your links are for completely different things. My decimal is too big to be converted into Integer and your links convert Integers to binary. – Tom Nov 20 '22 at 14:00
  • Not "*completely* different". Not at all! :) I could write a function for you later today, unless someone else beats me to it, but strictly speaking this isn't really how Stack Overflow should be used. – Andreas Rejbrand Nov 20 '22 at 14:02
  • @AndreasRejbrand Converting an Integer to binary is super easy- just a loop getting last bit with "and 1" and then Integer shr 1. Converting hex to bin is also super easy- every hex digit is just 4 binary digits. But with decimal string I see no easy ways. – Tom Nov 20 '22 at 14:14
  • 1
    Actually, it isn't hard at all. You can just do it very naïvely the same way you would do it using pen and paper. But I'll write a simple function for you later today, unless someone else beats me to it or the Q is closed. – Andreas Rejbrand Nov 20 '22 at 14:16
  • 1
    You could try something like http://www.rvelthuis.de/programs/bigdecimals.html that is part of the entire https://github.com/rvelthuis/DelphiBigNumbers – Ron Maupin Nov 20 '22 at 14:51
  • Is your example supposed to be correct? – Tom Brunberg Nov 20 '22 at 15:15
  • @TomBrunberg No, it's not correct. Windows' Calculator couldn't convert number that big. – Tom Nov 20 '22 at 15:46

1 Answers1

4

As I noted in a comment, making a naïve implementation of a function like this isn't at all difficult -- you merely need to make a routine that does what you would do yourself using pen and paper.

So, using long division, I devised the following (rather inefficient) code:

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;

It is correct, but certainly not the most efficient implementation.

For instance, according to this routine, the decimal number

30347386718195039666223058436176179389328210368626940040845691245726092139866985
13829421448918578266312873948380914263473944921553341261772026398226410631065331
7294059719089452218

is written as

11101111101001011110010001001010010100100011011010110111111000101000001111010111
00001000000111111000010100100001111100011101001010101110100101101001110100100100
01001010100110001111110111100001100111111111110101111011001001010011101000010010
00001100000001110100000101111111101111011010010011101000001000100111111010100011
10110000001010011110000101101101011101101010101011100010000011000111110010100001
01011010111110101010111100011110100100010110011110011001000100000111001110111010
01110101010100100010100001011101101001011110010110000100111010001101111000100011
111010110000001111111010010111010

in binary.

Andreas Rejbrand
  • 105,602
  • 8
  • 282
  • 384
  • Instead of an intermediate list I would have added `'0'` and `'1'` directly to `DecStrToBinStr`'s `result`. Also couldn't `DivMod2Str` be called with `(T, T, R)`? And be a function that could return `R` right away? Yes, this is kind of nit-picking. ;-) I just tend to want less verbosity. And more comments in code. – AmigoJack Nov 21 '22 at 01:40
  • 2
    @AmigoJack: I agree regarding the intermediate list. I was merely being lazy. `(T, T, R)` isn't possible without a few other changes. – Andreas Rejbrand Nov 21 '22 at 08:04