在玩这个问题的时候,我注意到了一些我无法解释的关于np.log2
、np.log
和np.log10
的相对性能的事情
In [1]: %%timeit x = np.random.rand(100000)
....: np.log2(x)
....:
1000 loops, best of 3: 1.31 ms per loop
In [2]: %%timeit x = np.random.rand(100000)
np.log(x)
....:
100 loops, best of 3: 3.64 ms per loop
In [3]: %%timeit x = np.random.rand(100000)
np.log10(x)
....:
100 loops, best of 3: 3.93 ms per loop
np.log2
比np.log
和np.log10
快3倍。也许,反直觉地说,计算ln(x + 1)的np.log1p(x)
与np.log2
不相上下。
In [4]: %%timeit x = np.random.rand(100000)
np.log1p(x)
....:
1000 loops, best of 3: 1.46 ms per loop
我在numpy v1.10.1和v1.8.2中获得了几乎相同的时间。
运行时性能中的这些差异有直观的解释吗?
发布于 2015-11-30 07:17:20
我发现你的问题非常有趣,所以我花了几个小时做了一些研究;我想我已经找到了适用于整数的性能差异的解释(感谢意大利马泰奥给出的说明)--但还不清楚如何将这种推理扩展到浮动:
计算机使用基数2--根据参考文献中的文章,log2的计算是一个4个处理器周期的过程-- log10的计算过程需要将log2(val)乘以1/log2 2(10),这又增加了5个周期。
查找值中最不重要位的索引. Finding log2是的一件事(视频持续23分钟)。
bit黑客:查找整数的整数日志基10
bit黑客:在O(lg(N))中找到N位整数的日志基2。
整数对数基数10首先使用上述的一种技术求取对数基2。根据log10(v) = log2(v) / log2(10)的关系,我们需要将它乘以1/ log 2(10),即约为1233/4096,或1233,然后再右移12。由于IntegerLogBase2循环,需要加一个。最后,由于t值只是一个可能与之相去甚远的近似,所以通过减去v< PowersOf10t的结果就可以得到确切的值。 该方法比IntegerLogBase2多执行6次操作。可以通过修改上面的日志基2表查找方法来加快速度(在具有快速内存访问的机器上),以便条目保存t计算的内容(即预添加、-mulitply和-shift)。这样做总共只需要9个操作就可以找到日志基10,前提是使用了4个表(v的每字节一个)。
注意:使用DeBruijn序列查找和位移位技术来计算这个麻省理工学院视频: Lec 2-麻省理工学院6.172性能工程软件系统,2010年秋季中的log2 (视频在36分钟内向前移动)。
注意,这篇StackOverflow文章演示了一种利用log2实现高效跨平台计算的方法
警告:我还没有检查numpy源代码来验证它确实实现了类似的技术,但它没有实现这一点是令人惊讶的。实际上,从OP帖子的评论中,费米子门已经检查了:
实际上,numpy使用glibc中的math.h,如果使用math.h/cmath.h,您将看到C/C++的相同区别。您可以找到这两个函数的注释良好的源代码,例如ic.unicamp.br/~islene/2s2008-mo806/libc/sysdeps/ieee754/dbl-64/…和ic.unicamp.br/~islene/2s2008-mo806/libc/sysdeps/ieee754/dbl-64/… - 费米子门9。
发布于 2015-11-19 19:54:41
这只是一张便条,但比评论还要长。显然,这与您的特定安装有关:
import numpy as np
import numexpr as ne
x = np.random.rand(100000)
我从conda获得了与numpy 1.10相同的时间,并得到了一个用icc编译的版本:
%timeit np.log2(x)
1000 loops, best of 3: 1.24 ms per loop
%timeit np.log(x)
1000 loops, best of 3: 1.28 ms per loop
我想这可能与抓取MKL包有关,但看起来是否定的:
%timeit ne.evaluate('log(x)')
1000 loops, best of 3: 218 µs per loop
看起来,numpy安装正在从两个不同的地方获取它的log/log 2实现,这是很奇怪的。
发布于 2015-12-01 13:47:03
免责声明:我既不是可信的,也不是官方的消息来源。
我几乎可以肯定,日志到基e函数的任何实现都可以与log2函数一样快,因为要将其中一个函数转换为另一个函数,需要用一个常量进行一个除法。当然,这是假定单个除法运算是其他计算的一小部分;在对数的精确实现中,这是正确的。
在大多数情况下,numpy使用来自glibc
的glibc
,如果使用math.h
/cmath.h
,您将看到C/C++的相同区别。在评论中,有些人观察到np.log
和np.log2
的速度相同;我怀疑这可能来自不同的构建/平台。
您可以在e_log.c
、e_log2.c
、e_logf.c
、e_log2f.c
和这个GitHub回购的flt-32/
子目录中找到这两个函数的注释良好的源代码。
为了实现双精度,在glibc
中,log
函数正在实现一个完全不同的algo (相对于2001年的log2
),后者包含在他们的libultim
库中。而log2
则来自于1993年的太阳微系统。只要看一看代码,就可以看到正在实现两个不同的近似。相比之下,对于单个精度,log
和log2
函数除了在log2
情况下除以ln2
之外,都是相同的,因此速度是相同的。
更多关于基础算法、备选方案和将来将包含在glibc
中的讨论的背景信息,请参阅这里。
https://stackoverflow.com/questions/33809789
复制相似问题