以下Python3.x整数乘法的平均运算时间在1.66s到1.77s之间:
import time
start_time = time.time()
num = 0
for x in range(0, 10000000):
# num += 2 * (x * x)
num += 2 * x * x
print("--- %s seconds ---" % (time.time() - start_time))
如果将2*x*x
替换为2*(x*x)
,则需要在2.04
和2.25
之间。怎么会呢?
另一方面,在Java中则相反:2*(x*x)
在Java中更快。Java测试链接:为什么在Java中2*(i*i)比2*i*i快?
我运行每个版本的程序10次,以下是结果。
2 * x * x | 2 * (x * x)
---------------------------------------
1.7717654705047607 | 2.0789272785186768
1.735931396484375 | 2.1166207790374756
1.7093875408172607 | 2.024367570877075
1.7004504203796387 | 2.047525405883789
1.6676218509674072 | 2.254328966140747
1.699510097503662 | 2.0949244499206543
1.6889283657073975 | 2.0841963291168213
1.7243537902832031 | 2.1290600299835205
1.712965488433838 | 2.1942825317382812
1.7622807025909424 | 2.1200053691864014
首先,请注意,我们在Python2.x中没有看到相同的东西:
>>> timeit("for i in range(1000): 2*i*i")
51.00784397125244
>>> timeit("for i in range(1000): 2*(i*i)")
50.48330092430115
所以这让我们相信这是由于整数在Python 3中的变化:具体地说,Python 3到处使用long
(任意大的整数)。
对于足够小的整数(包括我们在这里考虑的整数),CPython实际上只使用O(MN)grade-school逐位数乘法算法(对于较大的整数,它切换到Karatsuba算法)。你可以在源代码中看到这一点。
>>> timeit("a*b", "a,b = 2, 123456**2", number=100000000)
5.796971936999967
>>> timeit("a*b", "a,b = 2*123456, 123456", number=100000000)
4.3559221399999615
再次将其与Python2进行比较,Python2不会到处使用任意长度的整数:
>>> timeit("a*b", "a,b = 2, 123456**2", number=100000000)
3.0912468433380127
>>> timeit("a*b", "a,b = 2*123456, 123456", number=100000000)
3.1120400428771973
(一个有趣的注意:如果您查看源代码,您会发现该算法实际上有一个平方数的特例(我们在这里正在做),但即使这样也不足以克服2*(x*x)
只需要处理更多数字的事实。)
基于此,我认为我应该完全开始在中使用
我在查看sorted_containers的源代码时,惊讶地看到了这一行: 这里的是一个整数。为什么在一个地方使用位移位,而在另一个地方使用乘法?位移位可能比整数除以2快,这似乎是合理的,但为什么不把乘法也换成移位呢?我对以下案例进行了基准测试: (乘以,除法) (shift,shift) (次数,移位) (移位、除法) 以上是问题的原话。丹·盖茨在他的回答中提供了一个极好的解释。 为了完整起见,
问题内容: 我在计算机上得到以下结果: 我认为这可能与int / long转换有关,但在2.7中并没有更快的速度。 问题答案: Python 2使用朴素的阶乘算法: Python 3使用分治法阶乘算法: 有关讨论,请参见Python Bugtracker问题。感谢DSM指出这一点。
问题内容: 我已经对Java中的x * x或Math.pow(x,2)更快进行了一些测试。我原本以为简单的x * x会更快一些,但是事实证明它的速度差不多相等。有人可以启发我吗,那怎么可能? 问题答案: 就您所知,它完全是JITted(甚至已经在编译时)了。由于没有真实的上下文,此类微基准很少会提供非常有用的结果。 绝对不是一个彼此优先的理由,因为现实世界中的代码很少有简单的操作作为性能热点。
问题内容: 考虑以下示例: 我不确定Java语言规范中是否有一项规定要加载变量的先前值以便与右侧()进行比较,该变量应按照方括号内的顺序进行计算。 为什么第一个表达式求值,而第二个表达式求值?我本来希望先被评估,然后再与自身()比较并返回。 这个问题与Java表达式中子表达式的求值顺序不同,因为这里绝对不是“子表达式”。需要 加载 它以进行比较,而不是对其进行“评估”。这个问题是特定于Java的,
这个问题与Java表达式中子表达式的求值顺序不同,因为在这里肯定不是“子表达式”。需要加载它进行比较,而不是“求值”。这个问题是特定于Java的,表达式来自一个真实的项目,而不是通常为棘手的面试问题而设计的牵强附会的不切实际的构造。它应该是比较和替换习语的一行替换 它比x86 CMPXCHG指令还要简单,因此在Java中应该使用更短的表达式。