乘法怎么能比向左移位更快呢



众所周知,向左移位比相乘快,因为桶形移位器直接在硬件中实现。因此,这个简单的基准应该是错误的:

$start = 1;
$timestart = microtime(1);
for ($i = 0; $i < 10000000; $i++) {
$result2 = $start << 2;
}
echo microtime(1) - $timestart;
$timestart = microtime(1);
for ($i = 0; $i < 10000000; $i++) {
$result1 = $start * 4;
}
echo microtime(1) - $timestart;
echo "n";

因为我执行了多次,而且总是相乘比向左移位更快。例如:

0.73733711242676

0.71091389656067

因此,或者基准测试是错误的,或者PHP解释器在这里做了一些事情。该测试由运行在Ubuntu:中的PHP 7.0.32执行

PHP 7.0.32-0ubuntu0.16.04.1(cli((NTS(

CPU:Intel(R(Core(TM(i5-4460 CPU@3.20GHz

编辑:

在Windows框中执行,使用几乎相同的CPU(Intel(R(Core(TM(i5-4460S CPU@2.90GHz(,结果与预期相同:

0.24960112571716

0.28080010414124

这种情况下的PHP版本不同:

PHP 7.1.19(cli((内置时间:2018年6月20日23:24:42((ZTS MSVC14(Visual C++2015(x64(

您对硬件的推理基本上是无关紧要的。您使用的是口译语言,其中大部分成本是口译开销。

任何一个循环的asm版本都可以以每时钟1次的速度运行(假设计数偏移固定(,因此(在3GHz CPU上(只需要100k次迭代0.033ms,即0.000033秒,比PHP时间快250倍。


此外,解释循环必须使用变量计数移位(因为它无法将移位计数JIT编译为机器代码中的立即数(,由于x86遗留行李(标志语义(,这实际上对Intel CPU上的吞吐量(3 uop(来说更贵。AMD CPU具有单uop移位,即使对于可变移位计数也是如此。(shl reg, clshr reg, imm8(。参见INC指令与ADD 1:有关系吗?有关为什么shl reg,cl是Sandybridge家族上的3个uop,以及它如何通过标志创建错误依赖关系的更多信息(

在英特尔Sandybridge家族和AMD Ryzen上,整数乘法是1 uop,每时钟1吞吐量,3周期延迟。我在AMD推土机家族上每2个时钟,没有完全流水线。所以,是的,multiply有更高的延迟,但它们都是完全流水线式的吞吐量。你的循环丢弃了结果,所以没有循环携带的依赖链,所以延迟是不相关的(并且被无序执行隐藏(。

但这种微小的差异(2个额外的uops(不足以解释测量的差异实际移位或乘法仅为循环总周期的1/250。你说切换循环的顺序不会改变结果,所以这不仅仅是CPU上升到最大时钟速度之前的预热效果。

你还没有提到你运行的CPU微体系结构,但答案可能并不取决于移位与乘法指令的解码方式。

最新更新