你能在“for循环”中使用位移操作吗?

3

我有如下使用位移的C语言循环,我想要在Python中重新实现。

n = 64
for(int stride = n>>1; stride >0; stride >>=1)
   {...

那么这个循环在 Python 中会是什么样子呢?

我知道 n>>1 代表除以 2,但我觉得用 range() 很难模拟它。


1
我认为你的C代码有错误。那个循环是无限的,因为“stride”永远不会降到零以下,但是循环在它降到零之前不会退出... - Blair
@Blair,你说得对,我把我的例子简化得太多了。我会进行更正。 - Framester
8个回答

5

简单思考:

>>> n = 64
>>> while n:
...     print n
...     n = n >> 1
...
64
32
16
8
4
2
1

5

Amadan的回答非常准确。

如果您经常使用此模式,我建议将其提取为一个简单的生成函数以便在for循环中重复使用:

>>> def strider(n):
...     stride = n >> 1
...     while stride > 0:
...         yield stride
...         stride >>= 1
...
>>> for n in strider(64):
...     print n
...
32
16
8
4
2
1

3

所有的 for(;;) 循环都可以重写为 while 循环,反之亦然。

n = 64
stride = n >> 1
while stride > 0:
    # stuff
    stride >>= 1

编辑以反映原始更改


1
这与问题中的原始代码匹配,即一个无限循环。但要注意... - Blair
确实如此。我只是展示了一般的重写方法(即句法等价性),完全忽略了语义。 - Amadan
@Amadan,我已将原始条件从>=0更改为>0。 - Framester
@Amadan - 是的,我意识到了。我只是添加了一条注释,以确保未来的读者知道这一点。 - Blair

1

脑海中首先浮现的是:

while stride>0:
   # do your stuff
   stride>>=1

我认为在这种情况下尝试使用for循环并不是一个好主意。在Python中,for循环的工作方式类似于其他语言中的for-each循环。它们作用于序列。虽然我们可以轻松地将步幅值的范围转换为序列,但在我看来,使用while循环更简单、更自然地表达了这个想法。


这与问题中的原始代码匹配,即一个无限循环。但要注意... - Blair
@Blair:我自己完全忽略了那个错误。感谢你指出来。我已经更新了答案。 - MAK

0

由于您没有太多的迭代:

for stride in [32, 16, 8, 4, 2, 1, 0]:
  # ...

我知道,但是一个C整数能持续多少个连续的移位呢? :) - Tugrul Ates
@junjanes - 在我的电脑上,使用“long long”数据类型可以处理64位。按照您的建议写出来有点不方便。此外,它仅适用于固定的起始值(即,如果n的初始值取决于其他代码,则您的解决方案将无法很好地适应)。 - Blair

0

你可以编写自己的生成器,以在for循环中使用


-1

使用对数怎么样?

for i in range(int(math.log(n, 2)), -1, -1):
    # stride is 2**i

但这不会在每一步中将i除以2,对吧? - Daniel
这给了我(0, 1, 2, 3, 4, 5) - Tim Pietzcker
@Tim:修复了问题,现在你可以轻松计算“步幅”了。 - Björn Pollex
不错的想法,但似乎阅读起来并不特别容易,也不是很高效... :) - Blair

-2

嗯,最接近的方法是使用itertools模块:

>>> from itertools import takewhile, imap, count
>>> n = 64
>>> for i in takewhile(bool, imap(lambda x:n >> x, count(1))):
...     print i
... 
32
16
8
4
2
1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接