Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/277.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python Is&;检查奇数时速度是否超过%?_Python_Performance_Bit Manipulation_Modulo - Fatal编程技术网

Python Is&;检查奇数时速度是否超过%?

Python Is&;检查奇数时速度是否超过%?,python,performance,bit-manipulation,modulo,Python,Performance,Bit Manipulation,Modulo,要检查奇偶整数,最低位检查是否比使用模更有效 >>> def isodd(num): return num & 1 and True or False >>> isodd(10) False >>> isodd(9) True 是的。标准库中的timeit模块是检查这些内容的方式。例如: $ python -m timeit -s 'def isodd(x): x & 1' 'isodd(9)' 10000

要检查奇偶整数,最低位检查是否比使用模更有效

>>> def isodd(num):
        return num & 1 and True or False

>>> isodd(10)
False
>>> isodd(9)
True

是的。标准库中的
timeit
模块是检查这些内容的方式。例如:

$ python -m timeit -s 'def isodd(x): x & 1' 'isodd(9)'
1000000 loops, best of 3: 0.446 usec per loop
$ python -m timeit -s 'def isodd(x): x & 1' 'isodd(10)'
1000000 loops, best of 3: 0.443 usec per loop
$ python -m timeit -s 'def isodd(x): x % 2' 'isodd(9)'
1000000 loops, best of 3: 0.461 usec per loop
$ python -m timeit -s 'def isodd(x): x % 2' 'isodd(10)'
1000000 loops, best of 3: 0.453 usec per loop
如您所见,在我的(第一天==旧==慢;-)Macbook Air上,
&
解决方案的速度比
%
解决方案快7到18纳秒

timeit
不仅告诉你什么更快,还告诉你速度有多快(只需运行几次测试),这通常表明它是多么的不重要(当调用函数的开销在400左右时,你真的在乎10纳秒的差异吗?-)

让程序员相信微优化本质上是不相关的已经被证明是一项不可能的任务——尽管自Knuth以来已经35年了(在这段时间里,计算机的速度提高了几个数量级!)

我们应该忘记小问题 效率,比如说大约97%的 时间:过早优化是关键 万恶之源

正如他所解释的,这是从霍尔更古老的声明中引用的。我想每个人都完全相信他们的案子只剩下3%


因此,我们(Tim Peters尤其值得在那里获得荣誉)加入了标准Python库模块
timeit
,而不是没完没了地重复“这无关紧要”,这使得测量这些微基准非常容易,因此至少让一些程序员相信,嗯,该病例确实属于97%组!-)

说实话,我认为这不重要。

第一个问题是可读性。什么对其他开发人员更有意义?一、 就个人而言,在检查一个数字的均匀性/奇异性时,他希望得到一个模。我希望大多数其他开发者也会有同样的期望。通过引入不同的、出乎意料的方法,您可能会使代码读取和维护变得更加困难


第二个事实是,在执行这两个操作时,您可能永远不会遇到瓶颈。我支持优化,但在任何语言或环境中,早期优化都是最糟糕的事情。如果由于某种原因,确定一个数字是偶数还是奇数是一个瓶颈,那么找到解决问题的最快方法。然而,这让我回到了我的第一点——第一次编写例程时,它应该以尽可能可读的方式编写。

“return num&1 and True或False”?哇!如果你是速度狂(1)“return num&1”(2)内联它:
如果somenumber%2==1
是易读的,并且优于
isodd(somenumber)
,因为它避免了Python函数调用。

John提出了一个很好的观点。真正的开销在函数调用中:

me@localhost ~> python -mtimeit -s'9 % 2'
10000000 loops, best of 3: 0.0271 usec per loop
me@localhost ~> python -mtimeit -s'10 % 2'
10000000 loops, best of 3: 0.0271 usec per loop

me@localhost ~> python -mtimeit -s'9 & 1'
10000000 loops, best of 3: 0.0271 usec per loop
me@localhost ~> python -mtimeit -s'9 & 1'
10000000 loops, best of 3: 0.0271 usec per loop

me@localhost ~> python -mtimeit -s'def isodd(x): x % 2' 'isodd(10)'
1000000 loops, best of 3: 0.334 usec per loop
me@localhost ~> python -mtimeit -s'def isodd(x): x % 2' 'isodd(9)'
1000000 loops, best of 3: 0.358 usec per loop

me@localhost ~> python -mtimeit -s'def isodd(x): x & 1' 'isodd(10)'
1000000 loops, best of 3: 0.317 usec per loop
me@localhost ~> python -mtimeit -s'def isodd(x): x & 1' 'isodd(9)'
1000000 loops, best of 3: 0.319 usec per loop

有趣的是,这两种方法在没有函数调用的情况下同时进行远程处理

您可以得到的最佳优化是不要将测试放入函数中。”<代码>数字%2和“数字&1”是检查奇数/均匀度的常用方法,有经验的程序员会立即识别出这种模式,并且您可以随时添加注释,如“如果数字是奇数,那么诸如此类”,如果您真的需要它变得明显

# state whether number is odd or even
if number & 1:
    print "Your number is odd"
else:
    print "Your number is even"

除了邪恶的优化之外,它还删除了非常惯用的“var%2==0”,每个编码人员都不需要看两遍就能理解它。因此,这是违反蟒蛇禅以及非常小的收益

此外,为了更好的可读性,a=b和True或False已被


如果num&1 else False

真的感到惊讶,则返回True上述答案中没有一个同时执行变量设置(定时文字是不同的故事)和函数调用(显然隐藏了“较低术语”)。从ipython的timeit开始,我就一直坚持这个时间点,在那里我得到了明确的赢家x&1——使用python2.6(约12%使用python3.1)获得了约18%的收益

在我的旧机器上:

$ python -mtimeit -s 'x = 777' 'x&1'
10000000 loops, best of 3: 0.18 usec per loop
$ python -mtimeit -s 'x = 777' 'x%2'
1000000 loops, best of 3: 0.219 usec per loop

$ python3 -mtimeit -s 'x = 777' 'x&1'
1000000 loops, best of 3: 0.282 usec per loop
$ python3 -mtimeit -s 'x = 777' 'x%2'
1000000 loops, best of 3: 0.323 usec per loop

使用Python3.6,答案是否定的。在2017 MBP上使用下面的代码表明使用模更快

# odd.py
from datetime import datetime

iterations = 100_000_000


def is_even_modulo(n):
    return not n % 2


def is_even_and(n):
    return not n & 1


def time(fn):
    start = datetime.now()
    for i in range(iterations, iterations * 2):
        fn(i)
    print(f'{fn.__name__}:', datetime.now() - start)


time(is_even_modulo)
time(is_even_and)
给出以下结果:

$ python3 -m odd
is_even_modulo: 0:00:14.347631
is_even_and: 0:00:17.476522
$ python3 --version
Python 3.6.1
正如在其他答案中所建议的,函数调用是一个巨大的开销,然而,去掉它表明模运算仍然比按位运算快,在Python 3.6.1中:

# odd.py
from datetime import datetime

iterations = 100_000_000


def time_and():
    start = datetime.now()
    for i in range(iterations):
        i & 1 
    print('&:', datetime.now() - start)


def time_modulo():
    start = datetime.now()
    for i in range(iterations):
        i % 2
    print('%:', datetime.now() - start)


time_modulo()
time_and()
结果:

$ python3 -m odd
%: 0:00:05.134051
&: 0:00:07.250571
额外好处:事实证明,在Python2.7中运行这项功能所需的时间大约是原来的两倍

$ time python2 -m odd
('&:', '0:00:20.169402')
('%:', '0:00:19.837755')

real    0m41.198s
user    0m39.091s
sys 0m1.899s
$ time python3 -m odd
&: 0:00:11.375059
%: 0:00:08.010738

real    0m19.452s
user    0m19.354s
sys 0m0.042s

我有一半的期望在这个问题上会有反对票,但我认为这对任何想知道这个(或任何类似)问题的人来说都是一个重要的观点,所以它会一直存在。而不是反对票。。。但是,在这种情况下,分析“明显的”选项并选择最快的是Python解决方案。半无用:我仍在学习Python,但我个人认为模运算符更Python,因为你正在做预期的事情。至少对我来说,这更明显、更清楚。我同意你的看法。正如Donald Knuth所说,“过早优化是万恶之源”。@gutofb7:在你发表评论前8分钟,我在我的回答中给出了Knuth伟大文章的完整引用和PDF链接(我相信这也是第一篇提出缩进作为指示块的唯一手段的文章;-)。顺便说一句,在这种情况下,我相信%2和&1的可读性是完全相同的(任何不懂位的人都很难理解与百分比无关的“%”,等等;-)。什么是“和真或假”?如果你想得到布尔结果,只需执行bool(num&1)“0为真,1为假”?!现在,这将是一种有趣的编程语言,事实上。。。!!!我搞砸了。在Python中,0为FALSE,1为TRUE。(但在*nix中,退出代码为0表示成功。bash确实很有趣。)是的,我记得有一次(在IBM Instruments小型计算机上用于实验室控制)以“返回0”结束一个程序,并在打印控制台上收到16条可怕的错误消息(结果是返回代码被逐位解释为1=成功,0=失败,例如