Search code examples
delphipascallazarus

Big Decimal String to Binary String


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

'31314232352342341239081370934702357023470' => '10101101110101000011001101011101101001100010100111111100001011'


Solution

  • 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.