【问题标题】:Doubling binary digits二进制数字加倍
【发布时间】:2011-02-25 02:42:06
【问题描述】:

如何将整数中的多个二进制数字加倍?例如,如果 bin(x)="1001",则 bin(y) 必须为“11000011”。有没有智能快速的算法?

更新:这是一个优雅的解决方案:

''.join([''.join(i) for i in zip(X,X)])

其中 X 是 bin(int_x)[2:]

但是,我对更快的方法和任何大小的整数感兴趣。也许算术变换应该会有所帮助。

【问题讨论】:

  • @Daniel Trebbien:感谢您的澄清。我的错。
  • 非对称输入的输出应该是什么,例如输入 8 (b1000) 应该给出 3 (b00000011) 还是 192 (b11000000)?
  • 如果输入是 b0 + 2*b1 + 4*b2 + 8*b3 + ... 那么我认为@psihodelia 想要 b0 + 2*b0 + 4*b1 + 8*b1 + 16*b2 + 32*b2 + ...
  • 使用 INTERCAL - 它是基本运算符之一。 DO :1 <- :1¢:1
  • 为了优雅,''.join(chain(*zip(X, X))) 怎么样?记得from itertools import chain:]

标签: python algorithm math binary


【解决方案1】:

这是一种应该相当快的方法:将您的数字转换为二进制字符串,然后将结果重新解释为以 4 为底。现在要确保所有 '1' 都正确加倍,请将结果乘以 3。

>>> x = 9
>>> bin(x)
'0b1001'
>>> y = int(bin(x)[2:], 4)*3
>>> bin(y)
'0b11000011'

【讨论】:

  • 不错的一个!我花了一些时间才得到它。
【解决方案2】:

(参考http://graphics.stanford.edu/~seander/bithacks.html#Interleave64bitOps):

如果您的号码低于 256,您可以使用

@magic
def double_digits_holger8(x):
    m = (x * 0x0101010101010101 & 0x8040201008040201) * 0x0102040810204081
    return ((m >> 49) & 0x5555) | ((m >> 48) & 0xAAAA)

如果低于 65536,

@more_magic
def double_digits_binmag16(x):
    x = (x | x << 8) & 0x00FF00FF
    x = (x | x << 4) & 0x0F0F0F0F
    x = (x | x << 2) & 0x33333333
    x = (x | x << 1) & 0x55555555
    return x | x << 1

与其他解决方案比较(函数必须取整数并返回整数才能公平比较):

Method        Time per 256 calls
--------------------------------
Do nothing        46.2 usec 
Holger8          256   usec
BinMag16         360   usec
Mark             367   usec # http://stackoverflow.com/questions/2928886/doubling-binary-digits/2929198#2929198
Max              720   usec # http://stackoverflow.com/questions/2928886/doubling-binary-digits/2928938#2928938
Peter          1.08    msec # http://stackoverflow.com/questions/2928886/doubling-binary-digits/2928973#2928973
Phiµµ w/o Log  1.11    msec # http://stackoverflow.com/questions/2928886/doubling-binary-digits/2929106#2929106
Jim16          1.26    msec # http://stackoverflow.com/questions/2928886/doubling-binary-digits/2929038#2929038
Elegant        1.66    msec # int(''.join([''.join(i) for i in zip(X,X)]),2)
More Elegant   2.05    msec # int(''.join(chain(*zip(X, X))), 2)

基准源代码可以在http://gist.github.com/417172找到。

【讨论】:

  • +1 获得更多魔力。你可以去掉一些分号。 ;p
  • 我对任何大小的长整数的通用方法更感兴趣。
  • 使用“magic”和“more_magic”装饰器有什么特别的原因吗?查看您的代码,他们似乎只是传递了函数(值)而没有实际对其进行任何操作。我认为您还不如将“magic”和“more_magic”作为 cmets 我错了吗?
  • @KennyTM:啊,我明白了。感谢您的链接。我想我会保留它的书签。
【解决方案3】:

仅使用整数算术的直接解决方案是:

def doubledigits(n):
    result = 0
    power = 1
    while n > 0:
        if n%2==1:
            result += 3*power
        power *= 4
        n //= 2
    return result

【讨论】:

  • 它不如使用字符串优雅(更多代码),但也可能更快(特别是因为它很容易移植到 c)。
  • @Matthieu:只有真正用 C 语言编写才会更快。
  • 可能(我没有对其进行基准测试)因为与内置操作相比,python 中的手动循环非常慢。
  • 我说过,我对“优雅”等于“更少代码”的观点提出异议。这是一种危险的思维方式。简洁不一定与清晰相同。 (也就是说,Mark Dickinson 的回答非常好。)
【解决方案4】:

any_number - 整数

str(n) - 从 int 生成字符串。

str::replace(pattern,replaced_value) - 将字符串中的所有模式替换为replaced_value。

int(str) - 从字符串中生成 int。

n=any_number
result_number = int(str(n).replace("0","00").replace("1","11"))

【讨论】:

  • 我不确定它是否很快,但它很优雅。没有注意到它,但是当我不介意速度时,我通常使用python。无论如何,为什么这不应该很快? str::replace 方法在一次遍历中替换所有条目。所以这里有两次遍历,2只是常数,复杂度还是O(N)
  • @Max:O-complexity 并不能说明速度,它基本上衡量的是你的算法如何扩展。
  • 哦,抱歉,没有看到 Peter Milley 的解决方案。
  • 你可以像''.join([c*2 for c in str(n)])这样的任何字符串加倍
  • IMO,Max 的解决方案是最优雅的。我认为没有必要为此使用复杂的功能,除非用例需要。
【解决方案5】:
$ python2.6
Python 2.6.5 (r265:79063, Mar 25 2010, 14:13:28)
>>> def dd(n): return eval("0b" + "".join(d * 2 for d in str(bin(n))[2:]))
...
>>> dd(9)
195

【讨论】:

  • 我知道eval是邪恶的,如果你不需要将结果转换为十进制,你就不需要它。
  • 您根本不需要使用evaleval("0b" + ...)int(..., 2) 相同
【解决方案6】:
y = 0;
for(i = 15; i  >= 0; i--) {
    if((1 << i) & x) {
       y |= 3;
    }
    y <<= 2;
}

【讨论】:

    【解决方案7】:
    def doubledigits(x):
        from math import log
        print (bin(x))
        numdigits = x.bit_length()
        result = 1 << (numdigits*2)
        for i in range(numdigits, -1, -1):
            mask = 1 << i
            if (x & mask > 0):
                rmask = 0b11 << (2*i)
                result = result | rmask
        return result
    

    应该这样做。

    【讨论】:

    • 将此解决方案与上述 Peter Milley 的解决方案进行比较。哪个更好看?
    • 不适用于 x = 0。只需使用 x.bit_length() 而不是 log。
    • @unbeli 在这个问题上将您的评论与其他人进行比较 - 哪个更好? :P 嘿,就我而言,至少他给出了一个可行的解决方案!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-10
    相关资源
    最近更新 更多