【问题标题】:Algorithm to find the Binary in Terms of 1 and 2 for an Integer用 1 和 2 查找整数的二进制的算法
【发布时间】:2018-09-15 09:05:28
【问题描述】:

问题

在开发虚拟确定性有限自动机时,我正在尝试创建一种算法,该算法可以从十进制值中输出唯一的二进制字符串。二进制的十进制值是通过将 2 的适当幂乘以 1 或 2 来找到的。例如,

    19 becomes:
    1    2    1    1

自:

    2^3  2^2  2^1  2^0
    1    2    1    1
  * __________________
    8  + 8  + 2  + 1

尝试

尝试 1

我尝试了多种算法,但这个算法最接近:

def decToBin2(dec):
    bin = ''
    while dec > 0:
        bin = str(dec % 2) + bin
        dec = dec/2
    return bin

但是,使用此函数的二进制解决方案包含 0不应出现。因此,我一直在挣扎。

尝试 2

Rory Daulton 在这个问题上帮了我很多忙,下面是他的解决方案的实现和测试运行。但是,对于几个整数,它会失败。

def decToBin2(dec):
    if dec == 0:
        return ''

    bin = ''
    # Find the largest power of 2 that is less than dec
    fac = 0
    while 2**(fac) <= dec:
        fac = fac + 1
    fac -= 1

    # Subtract that power of 2 and add 1
    dec = dec - 2**(fac) + 1

    # Convert to binary, but 0s become 1s and 1s become 2s
    while dec > 0:
        bin = str(dec % 2 + 1) + bin
        dec = dec/2

    # Pad the left side with 1s
    while len(bin) < fac:
        bin = '1' + bin

    return bin

测试运行:

✓ 0 = 0 : 
✗ 1 != 2 : 2
✓ 2 = 2 : 2
✗ 3 != 5 : 21
✓ 4 = 4 : 12
✓ 5 = 5 : 21
✓ 6 = 6 : 22
✗ 7 != 11 : 211
✓ 8 = 8 : 112
✓ 9 = 9 : 121
✓ 10 = 10 : 122
✓ 11 = 11 : 211
✓ 12 = 12 : 212
✓ 13 = 13 : 221
✓ 14 = 14 : 222
✗ 15 != 23 : 2111
✓ 16 = 16 : 1112
✓ 17 = 17 : 1121
✓ 18 = 18 : 1122
✓ 19 = 19 : 1211
✓ 20 = 20 : 1212
✓ 21 = 21 : 1221
✓ 22 = 22 : 1222
✓ 23 = 23 : 2111
✓ 24 = 24 : 2112
✓ 25 = 25 : 2121
✓ 26 = 26 : 2122
✓ 27 = 27 : 2211
✓ 28 = 28 : 2212
✓ 29 = 29 : 2221
✓ 30 = 30 : 2222
✗ 31 != 47 : 21111
✓ 32 = 32 : 11112
✓ 33 = 33 : 11121
✓ 34 = 34 : 11122
✓ 35 = 35 : 11211
✓ 36 = 36 : 11212
✓ 37 = 37 : 11221
✓ 38 = 38 : 11222
✓ 39 = 39 : 12111
✓ 40 = 40 : 12112
✓ 41 = 41 : 12121
✓ 42 = 42 : 12122
✓ 43 = 43 : 12211
✓ 44 = 44 : 12212
✓ 45 = 45 : 12221
✓ 46 = 46 : 12222
✓ 47 = 47 : 21111
✓ 48 = 48 : 21112
✓ 49 = 49 : 21121
✓ 50 = 50 : 21122
✓ 51 = 51 : 21211
✓ 52 = 52 : 21212
✓ 53 = 53 : 21221
✓ 54 = 54 : 21222
✓ 55 = 55 : 22111
✓ 56 = 56 : 22112
✓ 57 = 57 : 22121
✓ 58 = 58 : 22122
✓ 59 = 59 : 22211
✓ 60 = 60 : 22212
✓ 61 = 61 : 22221
✓ 62 = 62 : 22222
✗ 63 != 95 : 211111
✓ 64 = 64 : 111112
✓ 65 = 65 : 111121
✓ 66 = 66 : 111122
✓ 67 = 67 : 111211
✓ 68 = 68 : 111212
✓ 69 = 69 : 111221
✓ 70 = 70 : 111222
✓ 71 = 71 : 112111
✓ 72 = 72 : 112112
✓ 73 = 73 : 112121
✓ 74 = 74 : 112122
✓ 75 = 75 : 112211
✓ 76 = 76 : 112212
✓ 77 = 77 : 112221
✓ 78 = 78 : 112222
✓ 79 = 79 : 121111
✓ 80 = 80 : 121112
✓ 81 = 81 : 121121
✓ 82 = 82 : 121122
✓ 83 = 83 : 121211
✓ 84 = 84 : 121212
✓ 85 = 85 : 121221
✓ 86 = 86 : 121222
✓ 87 = 87 : 122111
✓ 88 = 88 : 122112
✓ 89 = 89 : 122121
✓ 90 = 90 : 122122
✓ 91 = 91 : 122211
✓ 92 = 92 : 122212
✓ 93 = 93 : 122221
✓ 94 = 94 : 122222
✓ 95 = 95 : 211111
✓ 96 = 96 : 211112
✓ 97 = 97 : 211121
✓ 98 = 98 : 211122
✓ 99 = 99 : 211211
✓ 100 = 100 : 211212

有用的片段

要测试您的求解函数,您可以将二进制字符串输入到我编写的这个函数中,该函数将 2 的每个幂乘以它的权重。

def binToDec(bin):
    if bin == '':
        return 0
    return binToDec(bin[1:]) + (2**(len(bin) - 1) * int(bin[0]))

提前谢谢你!

【问题讨论】:

    标签: algorithm math binary automata


    【解决方案1】:

    您的问题接近于找到数字的标准 (0/1) 二进制表示,所以让我们使用它。这是一个算法——我会把代码留给你。

    首先,考虑小于 2 的幂的数字。这是序列 1、3、7、15、31 等 - 您可以通过将前一个数字相乘再加一个来找到下一个数字。找出这个序列中小于或等于给定数的最大数。对于您的 19 示例,即 15。请注意您的数字在序列中的位置。在您的示例中,15 是序列中的第 4 个数字,因此请记住 4。

    然后从给定的数字中减去该数字。这里我们得到 19 - 15,即 4。

    将计算出的数字转换为标准二进制——有多种众所周知的方法可以做到这一点,这在 Python 中是微不足道的。在第一步中用任何需要的零作为前缀,以获得与其他数字(序列中的位置)相同的位数。这里我们得到 100,我们想要 4 个二进制数字,所以我们得到 0100。

    最后,将该二进制文件中的每个 1 替换为 2,将每个 0 替换为 1。这里我们得到 1211,这就是我们想要的结果。

    该算法的工作原理基本上是注意从您想要的表示中的每个数字中减去 1 会产生一个标准二进制数,它与给定数字以一种简单的方式不同。

    我的算法中的一个特殊情况是,当给定数字小于 2 的幂时,它的标准二进制表示中没有零。因此它的标准二进制也是它的特殊二进制,我们最终只使用它的标准二进制表示。在我的算法中,我们将给定的数字更改为零,获取一串零,然后将其转换为一串一,这是正确的。 (编辑此答案以处理这种特殊情况。)

    【讨论】:

    • 感谢您的解决方案,罗里!我尝试实现你的算法并且它有效......在大多数情况下(我编辑了我的问题)。有什么我想念的吗?
    • 失败的情况是二进制字符串增加长度,输出2作为MSB而不是1。
    • 谢谢!我已经找到了一个我将很快发布的解决方案。最后一件事:介意用数学术语解释Then subtract that number from your given number. Here we get 19 - 15 which is 4.这行吗?为什么你这样做是为了得到新的“加权”二进制?
    • @AnthonyKrivonos 逻辑如下:我们试图将您的问题简化为众所周知的将数字转换为二进制形式的问题。为此,我们将总长度为L12 序列拆分为两个数字的总和:A1 = 长度为@的仅1 的序列987654328@ 以及01 的序列,这显然只是某个数字的二进制表示(B)。而前者只是一个2^L-1。所以B = N - A1 我们知道如何转换它。剩下的就是找到L,获取并转换B,并添加A1,即在每个位置添加1
    • @AnthonyKrivonos:您的加权二进制由 1 和 2 组成。如果我们从每个数字中减去 1,我们最终会得到一个由 0 和 1 组成的数字,这是常规的二进制,我们知道该怎么做。所以我们从给定的数字中减去数字1111(或不同的长度)。二进制中的数字1111 比2 的幂小一。你可以通过向它加一来看到:除了新的溢出位之外,你最终得到的都是零——得到10000。这种数字是 2 的幂,在这种特殊情况下是 2**4。清楚吗?
    【解决方案2】:

    我想出了一个更简单的解决方案。

    代码

    def decToBin2(dec):
        bin = ''
        while dec > 0:
            summand = 2 if dec % 2 == 0 else 1
            bin = str(summand) + bin
            dec = (dec - summand)/2
        return bin
    

    说明:

    假设一个整数 d 将被转换为二进制表示和一个空字符串 b。如果 d 为偶数,则令整数 m 为 2(即 d mod 2 等于 0)。否则,令整数 m 为 1。将 m 连接到 b 的开头 (b = mb)。然后,从 b 中减去 m 并将该解除以 2。当 b 大于 0 时重复上述步骤。

    示例:

    dec = 11
    11 = ___ * 2 + ___ becomes:
    11 = 5 * 2 + 1 <- LSB
    5 = 2 * 2 + 1
    2 = 0 * 2 + 2 <- MSB
    bin = 211
    

    【讨论】:

    • 如果您仔细考虑一下,您可能会注意到从逻辑上讲您的解决方案与@RoryDaulton 相同。您刚刚将两(三)个循环合并为一个。在 Rory 的解决方案中,第一个循环用于计算功率,第二个循环进行转换,该循环中的主线是 summand = dec % 2,在逻辑上与 summand = 1 if dec % 2 == 1 else 0 相同,第三个循环用于加回 @987654325 @。如果您尝试合并第二个和第三个循环,您将得到summand = (1 if (dec - 1) % 2 == 1 else 0) + 1,这在逻辑上等同于您拥有的行。现在你不需要第一个循环了。
    • 当然,尽管在逻辑上是等价的,但恕我直言,您的代码比 Rory 的原始解决方案要简单得多。我可能会将这个答案标记为已接受,即使它是你的(是的,这在 SO 是允许的)。
    猜你喜欢
    • 1970-01-01
    • 2013-05-23
    • 1970-01-01
    • 1970-01-01
    • 2018-03-18
    • 1970-01-01
    • 2013-03-11
    • 1970-01-01
    • 2018-08-03
    相关资源
    最近更新 更多