【问题标题】:Binary String to Decimal String二进制字符串转十进制字符串
【发布时间】:2011-07-11 22:39:45
【问题描述】:

下午好,

在语言最大的整数类型中,您将如何将字符数多于位的二进制字符串转换为十进制字符串?换句话说,假设你有字符串

111001101001110100100(...)1001001111011100100

而且你不能先将它转换为整数,你会如何以 10 为底编写它?

非常感谢。

【问题讨论】:

  • 我不清楚“您不能先将其转换为整数”是什么意思。它一个整数,至少,它是一个以 2 为底的整数的表示形式。如果您的意思是要从一个整数到相同整数的以 10 为基数的表示,而没有实现有问题的整数,我认为你会不走运。

标签: algorithm base


【解决方案1】:

您可以使用如下算法:

// 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'

X 除以 10 的欧几里得除法计算如下:

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

【讨论】:

  • 这是一个非常好的答案。它适用于任何基础,只需将基础(上面代码中的 10)换成其他的。例如,使用 8 进行二进制到八进制的转换。
【解决方案2】:

10 不是 2 的幂,因此二进制表示中任何位置的数字都可能影响十进制表示中的最低有效位。您必须存储整个十进制表示来转换位字符串。

如果你找不到适合你的语言的长十进制数据类/库,你可以自己构建它,这并不难。只需存储足够的十进制数字,例如作为一个列表,并做数学。你只需要添加这个任务,所以它非常容易实现。

【讨论】:

    【解决方案3】:

    以 10 为基数编写您自己的算术运算。只需要加法。 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)))
    

    这使用整数列表来表示以 10 为底的数字。列表项对应于以 10 为底的数字的数字。索引 0 的项目对应个位,索引 1 的项目对应十位,依此类推。

    【讨论】:

    • 如果你使用 Python 3,它内置了任意长度的整数 :)
    • @9000:每个版本的 Python 都内置了任意精度的整数。我只是使用 Python 符号来描述算法。
    • 是的,你总是可以import decimal,但是在 Py3k 中,纯整数在需要时可以迁移到任意精度。顺便说一句,+1 的解释。
    • @9000:每个版本的 Python 都内置了任意精度整数,早在 decimal 模块出现之前。上面的代码实际上是使用它们来生成示例字符串(3**120 对于机器精度整数来说太大了)。
    【解决方案4】:

    我会使用任意精度的数字 (bignum) 库,例如 GMP

    GMP 有一个“gmp_scanf”函数,可以满足您的要求。

    【讨论】:

    • "(...) 假设 (...) 不能先将其转换为整数 (...)"
    • @Miguel - 一个好的 bignum 库应该有相应的实用程序。例如:gmplib.org/manual-4.3.2/…
    • 您无法将其转换为 机器 整数,但任意精度的 bignum 都不是机器整数(顺便说一句,不必是整数)。
    【解决方案5】:

    假设您没有任意精度的数学包可供使用,但您确实有 一组基本的字符串操作例程,您可以执行以下操作:

    构造一个2的幂列表,然后反向解构二进制字符串 通过为字符串中的每个“1”位添加适当的 2 次方,一次订购一位。

    您需要执行此操作的唯一任意精度算术函数是加法,这是相当公平的 使用长手算术很容易实现。

    假设您确实实现了一个名为的任意算术加法函数: ADD 将 2 个包含十进制数字的字符串作为输入并返回十进制和 作为一个字符串。比如:

      SumString = ADD(DecimalString1, DecimalString2)
    

    SumString 是一串十进制数字,表示DecimalString1DecimalString2 之和。

    Step1:构造一个 2 的幂列表,如下所示:

      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 
    

    注意:以上假设数组/字符串是从 1 开始的(而不是从零开始的)。

    第 2 步:解构 BitString,不断累积总和:

      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 */  
    

    如何构建任意精度的ADD函数?它是这样的:

      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  
    

    假设内置字符串函数:

    • reverse(String):逆序返回字符串
    • length(String):返回给定字符串的长度
    • concat(String, String):返回两个字符串的串联
    • substr(String, start, length):从 start 处返回字符串的子字符串,长度为 1 个字符(从 1 开始)
    • CtoI(String):返回给定字符的十进制整数值(例如,'1' = 1,'2' = 2,...)
    • ItoC(Integer):返回整数的十进制字符表示(例如,1 = '1'、2 = '2'、...)
    • copies(count, string):返回 count 连接的字符串副本

    【讨论】:

      猜你喜欢
      • 2017-03-22
      • 2016-02-26
      • 2019-08-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-02-23
      相关资源
      最近更新 更多