为什么X**4.0
比X**4
快?我使用的是CPython 3.5.2。
$ python -m timeit "for x in range(100):" " x**4.0"
10000 loops, best of 3: 24.2 usec per loop
$ python -m timeit "for x in range(100):" " x**4"
10000 loops, best of 3: 30.6 usec per loop
我试着改变我提升的幂,看看它是怎么做的,例如,如果我提升x的10或16的幂,它会从30跳到35,但如果我提升10.0作为浮动,它只是在24.1~4左右移动。
我想这和浮点转换和2次方有关,但我真的不知道。
为什么在Python 3*中X**4.0
比X**4
快?
Python 3int
对象是一个完整的对象,旨在支持任意大小;由于这一事实,它们在C级上是这样处理的(请参见如何在long_pow
中将所有变量声明为PylongObject*
类型)。这也使得它们的幂运算变得更加棘手和乏味,因为您需要使用它用来表示其值的ob_digit
数组来执行它。(勇敢者的源代码。--有关PylongObject
的更多信息,请参见:了解Python中大整数的内存分配。)
相反,Pythonfloat
对象可以转换为Cdouble
类型(通过使用pyfloat_asdouble
),并且可以使用这些本机类型执行操作。这很棒,因为在检查相关的边缘情况之后,它允许Python使用平台的POW
(即C的POW
)来处理实际的幂运算:
/* Now iv and iw are finite, iw is nonzero, and iv is
* positive and not equal to 1.0. We finally allow
* the platform pow to step in and do the rest.
*/
errno = 0;
PyFPE_START_PROTECT("pow", return NULL)
ix = pow(iv, iw);
其中IV
和IW
是我们的原始PyFloatObject
作为CDouble
。
值得注意的是:Python2.7.13
对我来说是一个因素2~3
更快,并且显示了相反的行为。
前面的事实也解释了Python 2和3之间的差异,所以我想我也要解决这个注释,因为它很有趣。
# Python 2
type(30) # <type 'int'>
type(30L) # <type 'long'>
static PyObject *
int_pow(PyIntObject *v, PyIntObject *w, PyIntObject *z)
{
register long iv, iw, iz=0, ix, temp, prev;
/* Snipped for brevity */
这允许一个很好的速度增益。
为了查看
与
相比有多慢,如果您在Python 2中的long
调用中包装x
名称(实际上强制它使用long_pow
,就像Python 3中的那样),速度增益将消失:
# <type 'int'>
(python2) ➜ python -m timeit "for x in range(1000):" " x**2"
10000 loops, best of 3: 116 usec per loop
# <type 'long'>
(python2) ➜ python -m timeit "for x in range(1000):" " long(x)**2"
100 loops, best of 3: 2.12 msec per loop
请注意,尽管其中一个代码段将int
转换为long
,而另一个代码段不转换(正如@pydsinger指出的那样),但这种强制转换并不是导致减速的原因。long_pow
的实现是。(仅用long(x)
对语句计时以查看)。
[...]它不会发生在循环之外。[...]对此有什么想法吗?
这是cpython的窥视孔优化器为您折叠常量。在这两种情况下,您都得到了相同的精确时间,因为没有实际的计算来找到幂的结果,只有加载值:
dis.dis(compile('4 ** 4', '', 'exec'))
1 0 LOAD_CONST 2 (256)
3 POP_TOP
4 LOAD_CONST 1 (None)
7 RETURN_VALUE
为'4**4'生成相同的字节码。
,唯一的区别是load_const
加载float256.0
而不是int256
:
dis.dis(compile('4 ** 4.', '', 'exec'))
1 0 LOAD_CONST 3 (256.0)
2 POP_TOP
4 LOAD_CONST 2 (None)
6 RETURN_VALUE
以下Python3.x整数乘法的平均运算时间在1.66s到1.77s之间: 如果将替换为,则需要在和之间。怎么会呢? 另一方面,在Java中则相反:在Java中更快。Java测试链接:为什么在Java中2*(i*i)比2*i*i快? 我运行每个版本的程序10次,以下是结果。
基于此,我认为我应该完全开始在中使用
问题内容: 我在计算机上得到以下结果: 我认为这可能与int / long转换有关,但在2.7中并没有更快的速度。 问题答案: Python 2使用朴素的阶乘算法: Python 3使用分治法阶乘算法: 有关讨论,请参见Python Bugtracker问题。感谢DSM指出这一点。
问题内容: 考虑以下示例: 我不确定Java语言规范中是否有一项规定要加载变量的先前值以便与右侧()进行比较,该变量应按照方括号内的顺序进行计算。 为什么第一个表达式求值,而第二个表达式求值?我本来希望先被评估,然后再与自身()比较并返回。 这个问题与Java表达式中子表达式的求值顺序不同,因为这里绝对不是“子表达式”。需要 加载 它以进行比较,而不是对其进行“评估”。这个问题是特定于Java的,
这个问题与Java表达式中子表达式的求值顺序不同,因为在这里肯定不是“子表达式”。需要加载它进行比较,而不是“求值”。这个问题是特定于Java的,表达式来自一个真实的项目,而不是通常为棘手的面试问题而设计的牵强附会的不切实际的构造。它应该是比较和替换习语的一行替换 它比x86 CMPXCHG指令还要简单,因此在Java中应该使用更短的表达式。
问题内容: 今天,我正在为即将参加的Java考试而学习,但遇到了这个问题: 设一个定义如下的类: 该指令产生的输出是什么? 答案似乎是,但我不明白为什么。有人可以给我适当的解释吗? 问题答案: 与具有可变参数列表的函数相比,重载解析始终偏向于使用具有明显数量的参数的函数,即使这意味着该函数是自动装箱的。 更详细地说,根据JLS 15.12.2 选择具有此优先级的函数: 类型加宽 自动装箱 可变参数