【问题标题】:How to convert a string that represents a decimal number to a string that represents its binary form?如何将表示十进制数的字符串转换为表示其二进制形式的字符串?
【发布时间】:2021-02-12 17:34:45
【问题描述】:

以字符串s="556852144786" 为例,它表示十进制数n=556852144786。是否有直接算法将其转换为s1="1000000110100110...",其中1000000110100110... 是n 的二进制表示?

【问题讨论】:

    标签: string binary decimal base-conversion


    【解决方案1】:

    我假设您正在寻找一种直接对字符串进行操作的算法,而不是转换为目标语言支持的任何整数并使用它们?

    有多种方法可以做到这一点。这里有两个,但如果你眯着眼睛看的话,它们几乎是相同的算法。

    方法一:将十进制字符串反复除以二

    在这种方法中,我们重复地将原始十进制字符串除以 2(使用十进制算术),并跟踪余数:这些余数以相反的顺序为您提供结果的位。 这是该算法在 Python 中的样子。它缺少is_nonzero 和divide_by_two 的定义。我们稍后会提供这些。

    def dec_to_bin(s):
        """
        Convert decimal string s to binary, using only string operations.
        """
        bits = ""
        while is_nonzero(s):
            s, bit = divide_by_two(s)
            bits += bit
        # The above builds up the binary string in reverse.
        return bits[::-1]
    

    该算法以相反的顺序生成位,所以我们需要一个最终的反转来给出生成的二进制字符串。

    divide_by_two 函数采用十进制字符串 s 并返回一个新的十进制字符串,表示商 s / 2 以及余数。余数是单个位,再次表示为字符串 - "0" 或 "1"。它遵循通常的逐位学校教授的从左到右的除法方法:每一步都涉及将一个数字以及从上一步引入的进位除以二。这是那个函数:

    def divide_by_two(s):
        """
        Divide the number represented by the decimal string s by 2,
        giving a new decimal string quotient and a remainder bit.
        """
        quotient = ""
        bit = "0"
        for digit in s:
            quotient_digit, bit = divide_digit_by_two(bit, digit)
            quotient += quotient_digit
        return quotient, bit
    

    我们还需要定义divide_digit_by_two,它接受一个数字加上一个十进位位,然后除以二得到一个数字商和一个位余数。此时,所有输入和输出都是长度为 1 的字符串。在这里我们作弊并使用整数运算,但只有 20 种可能的不同输入组合,因此我们可以轻松地使用查找表来代替。

    def divide_digit_by_two(bit, digit):
        """
        Divide a single digit (with tens carry) by two, giving
        a digit quotient and a single bit remainder.
        """
        digit, bit = divmod(int(bit) * 10 + int(digit), 2)
        return str(digit), str(bit)
    

    您可以将divide_digit_by_two 视为一种原始算术运算,它交换不同基数的两位数:它将以10 * bit + digit 表示的小于20 的非负整数转换为以@987654335 表示的相同值@。

    我们仍然缺少一个定义:is_nonzero。当且仅当十进制字符串完全由零组成时,十进制字符串才表示零。这是一个快速的 Python 测试。

    def is_nonzero(s):
        """
        Determine whether the decimal string s represents zero or not.
        """
        return s.strip('0') != ''
    

    现在我们已经准备好所有的位,我们可以测试了:

    >>> dec_to_bin("18")
    '10010'
    >>> dec_to_bin("556852144786")
    '1000000110100110111110010110101010010010'
    >>> format(556852144786, 'b')  # For comparison
    '1000000110100110111110010110101010010010'
    

    方法2:将二进制字符串反复乘以10

    这是第一种方法的变体:我们不是重复除法,而是逐位(从左到右)处理传入的十进制字符串。我们从一个表示值0 的空二进制字符串开始,每次处理一个数字时,我们乘以10(在二进制表示中)并加上该数字表示的值。和以前一样,最方便的方法是按照 little-endian 顺序(最低有效位在前)构建二进制字符串,然后在最后反转以获得传统的 big-endian 表示。这是顶级函数:

    def dec_to_bin2(s):
        """
        Convert decimal string s to binary, using only string operations.
    
        Digit-by-digit variant.
        """
        bits = ""
        for digit in s:
            bits = times_10_plus(bits, digit)
        return bits[::-1]
    

    times_10_plus 函数的工作是获取一个二进制字符串和一个数字,并生成一个新的二进制字符串,表示将原始值乘以十,再将二进制数字的值相加的结果。它看起来像这样:

    def times_10_plus(bits, digit):
        """
        Multiply the value represented by a binary string by 10, add a digit,
        and return the result as a binary string.
        """
        result_bits = ""
        for bit in bits:
            digit, result_bit = divide_digit_by_two(bit, digit)
            result_bits += result_bit
        while digit != "0":
            digit, result_bit = divide_digit_by_two("0", digit)
            result_bits += result_bit
        return result_bits
    

    请注意,我们使用完全与以前相同的算术原语divide_digit_by_two,但现在我们的想法略有不同:它将一位乘以十,并添加一个进位数字, 并将其转换为一个新位(结果的最低有效位)以及一个新的进位数字。

    效率说明

    为了清楚起见,我留下了一些 Python 级别的低效率问题。特别是,在构建字符串时,构建一个位或数字列表,然后在最后与 str.join 操作连接会更有效。另请注意,根据实现语言,就地修改数字字符串或位字符串可能更有意义,而不是在每一步生成新字符串。我将必要的更改留给您。

    【讨论】:

      猜你喜欢
      • 2011-08-03
      • 2021-04-22
      • 2013-11-26
      • 1970-01-01
      • 2016-01-10
      • 2019-05-14
      • 1970-01-01
      • 2015-04-23
      • 2014-12-05
      相关资源
      最近更新 更多