开发者

Binary String to Decimal String

Good afternoon,

How would you go about converting to a decimal string a binary string with more characters than bits in a language's largest integer type? In other words, supposing that you have the string

1110011开发者_如何学编程01001110100100(...)1001001111011100100

and that you can't convert it to an integer first, how would you go about writing it in base 10?

Thank you very much.


You can use an algorithm like:

// X is the input
while ( X != "0" )
  compute X' and R such that X = 10 * X' + R  (Euclidean division, see below)
  output R    // least significant decimal digit first
  X = X'

The Euclidean division of X by 10 is computed like this:

R = 0  // remainder in 0..9
X' = ""
for (b in bits of X)  // msb to lsb
  R = 2*R + b
  if R >= 10
    X' += "1"
    R -= 10
  else
    X' += "0"

Remove leading "0" from X'
The remainder is R in 0..9


Write your own arithmetic in base 10. Only addition is needed. Example implementation in Python:

from math import log, ceil

def add(a, b):
    """Add b to a in decimal representation."""
    carry = 0
    for i in range(len(b)):
        carry, a[i] = divmod(a[i] + b[i] + carry, 10)
    while carry:
        i += 1
        carry, a[i] = divmod(a[i] + carry, 10)

# an example string
s = bin(3 ** 120)[2:]

# reserve enough decimal digits
res = [0] * int(ceil(len(s) * log(2) / log(10)))

# convert
for c in s:
    add(res, res)
    if c == "1":
        add(res, [1])

#print output
print str.join("", map(str, reversed(res)))

This uses lists of intergers to represent numbers in base 10. The list items correspond to the digits of the base 10 number. The item at index 0 corresponds to the ones, the item at index 1 to the tens, and so on.


10 is not a power of 2, thus a digit at any place of a binary representation may affect the least significant digit in the decimal representation. You have to store the entire decimal representation to transform the bit string.

If you can't find a long decimal data class / library for your language, you can construct it yourself, it's not hard. Just store enough decimal digits, e.g. as a list, and do the math. You only need addition for this task, so it's extra easy to implement.


I'd use an arbitrary precision numeric (bignum) library, like GMP.

GMP has a "gmp_scanf" function that does just what you are asking for.


Assuming that you do not have an arbitrary precision math package at your disposal, but you do have a set of basic string manipulation routines, you could do the following:

Construct a list of powers of 2 then deconstruct the binary string in reverse order one bit at a time by adding in the appropriate power of 2 for every '1' bit in the string.

The only arbitrary precision arithmetic function you need to do this is addition, and this is fairly easy to implement using long-hand arithmetic.

Suppose you did implement an arbitrary arithmetic add function called: ADD taking 2 strings containing decimal numbers as input and returning the decimal sum as a string. Something like:

  SumString = ADD(DecimalString1, DecimalString2)

SumString is a string of decimal digits representing the sum of DecimalString1 and DecimalString2.

Step1: Construct a powers of 2 list as follows:

  BitString is string           /* String of '1' and '0' values... */
  BitString = '111001101001110100100(...)1001001111011100100' /* or whatever... */

  PowerOf2 is array of string  /* Array of strings containing powers of 2 */
  PowerOf2[1] = '1'            /* 2**0 to get things started... */
  /* Build as many powers of 2 as there are 'bits' in the input string */   
  for i from 2 to length(BitString) by +1  
    PowerOf2[i] = ADD(PowerOf2[i-1], PowerOf2[i-1])  
    end 

Note: Above assumes arrays/strings are 1 based (as opposed to zero based).

Step 2: Deconstruct the BitString accumulating the sum as you go:

  DecimalValue is string        /* Decimal value of BitString */
  BitString is string           /* Your input set of bits as a string... */
  ReverseBitString is string    /* Reversed input */

  DecimalValue = ''             /* Result */  
  BitString = '111001101001110100100(...)1001001111011100100' /* or whatever... */  
  ReverseBitString = reverse(BitString) /* Reverse so we process lsb to msb */  

  for i from 1 to length(ReverseBitString) by +1  
     if substr(ReverseBitString, i, 1) == '1' then  /* Bit at position i */  
        DecimalValue = ADD(DecimalValue, PowerOf2[i])  
        end   
     end    

  if DecimalValue = '' then DecimalValue = '0' /* bit string was all zero */   
  Display DecimalValue /* This is the result */  

How to build an arbitrary precision ADD function? It goes something like:

  function ADD (DecVal1 is string, DecVal2 is string) return string  
     SumVal is string   
     Rev1 is string  
     Rev2 is string      
     DigitSum is integer
     CarryDigit is integer

     SumVal = ''               /* Result so far... */
     Rev1 = reverse(DecVal1)   /* Reverse digit order */
     Rev2 = reverse(DecVal2)   /* Reverse digit order */

     /* Pad shorter reversed sting with trailing zeros... */
     if length(Rev1) > length(Rev2) then
        Rev2 = concat(Rev2, copies(length(Rev1) - length(Rev2), '0')
        end
     else
        Rev1 = concat(Rev1, copies(length(Rev2) - length(Rev1), '0')
        end

     /* Sum by digit position, least to most significant */
     CarryDigit = 0    
     for i from 1 to length(Rev1) by + 1
        DigitSum = CtoI(substr(Rev1, i, 1)) + CtoI(substr(Rev2, i, 1)) + CarryDigit
        if DigitSum > 9 then
           DigitSum = DigitSum - 10
           CarryDigit = 1
           end
        else
           CarryDigit = 0
           end 

        SumVal = concat(ItoC(DigitSum), SumVal)
        end

      if CarryDigit > 0 then
        SumVal = concat(ItoC(CarryDigit), SumVal)
        end

      return SumVal  

Assumed built in string functions:

  • reverse(String): Returns the string in reverse order
  • length(String): Returns length of a given string
  • concat(String, String): Returns concatenation of two strings
  • substr(String, start, length): Returns substring of string from start for length characters (1 based)
  • CtoI(String): Returns decimal integer value of given character (eg. '1' = 1, '2' = 2, ...)
  • ItoC(Integer): Returns decimal character representation of integer (eg. 1 = '1', 2 = '2', ...)
  • copies(count, string): Returns count concatinated copies of string


Here you go...

void toBCD1( char *p ) {
    const int decSize = 120; // Arbitrary limit of 10^119.
    static binByte decDgt[ decSize ]; // decimal digits as binary 'nibbles'.
    int curPow10 = 0;

    memset( decDgt, 0, sizeof(decDgt) );

    for( char *cp = p; *cp; cp++ ) {

        for( int ii = curPow10; ii >= 0; ii-- ) {
            if( decDgt[ ii ] >= 5 ) // Algorithm step
                decDgt[ ii ] += 3;

            decDgt[ ii ] <<= 1;

            if( decDgt[ ii ] & 0x10 ) { // Carry high bit?
                decDgt[ ii + 1 ] |= 0x1;
                if( ii == curPow10 ) // new power of 10?
                    curPow10++;
                decDgt[ ii ] &= 0xF; // dealing in 'nibbles'
            }
        }
        decDgt[ 0 ] |= ( *cp == '1' ); // truth value 0 or 1
    }
    for( int ii = curPow10; ii >= 0; ii-- )
        putchar( decDgt[ ii ] + '0' );
    putchar( '\n' );
}

void demo_toBCD( void ) {
    char *bp =  "11100110"
                "10011101"
                "00100100"
                "10011110"
                "11100100"
                "01001001"
                "11101110"
                "01000100"
                "10011110"
                "11100100";
    toBCD1( bp );
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜