在 C/C++ 中乘以低数字(相对于高数字)是否更快?

Is it faster to multiply low numbers in C/C++ (as opposed to high numbers)?

本文关键字:数字 是否 高数字 相对于 C++      更新时间:2023-10-16

问题示例:

计算123*456比计算123456*7890快吗?还是相同的速度?

我想知道 32 位无符号整数,但我不会忽略有关其他类型的答案(64 位、有符号、浮点数等)。如果不同,差异是由于什么?位是否为 0/1?

编辑:如果它有区别,我应该澄清我指的是任何数字(两个小于 100 的随机数与两个高于 1000 的随机数)

对于至少达到架构字大小的内置类型(例如,现代 PC 上的 64 位,过去几十年大多数低成本通用 CPU 上的 32 或 16 位),对于我听说过的每个编译器/实现/版本和 CPU,用于乘以特定整数大小的 CPU 操作码需要一定数量的时钟周期,而不管涉及的数量如何不同大小的数据乘法在某些 CPU 上执行不同(例如,AMD K7 在 16 位 IMUL 上有 3 个周期的延迟,而 32 位有 4 个周期的延迟)。

在某些体系结构和编译器/标志组合中,像long long int这样的类型可能比 CPU 操作码在一个指令中可以操作的位数多,因此编译器可能会发出代码来分阶段执行乘法,这将比 CPU 支持的类型的乘法慢。 但同样,在运行时以较宽类型存储的小值不太可能与较大的值有任何不同。

综上所述,如果一个或两个值都是编译时常量,编译器能够避免 CPU 乘法运算符,并针对某些值(例如1显然是无操作,任何一方 0 ==> 0 结果,* 4有时可以实现为<< 2)。 没有什么特别的停止技术,如位移用于较大的数字,但这种数字的较小百分比可以优化到相同的程度(例如,有更多的 2 的幂 - 可以使用位左移执行乘法 - 在 0 到 1000 之间比在 1000 到 2000 之间)。

这在很大程度上取决于处理器体系结构和型号。

在过去(约1980-1990年),两个数字中的1个数将是一个因素--1越多,乘以[符号调整后,因此乘以-1并不比乘以1慢,但乘以32767(15个)明显比乘以17(2个1)慢]。这是因为乘法本质上是:

unsigned int multiply(unsigned int a, unsigned int b)
{  
res = 0;  
for(number of bits)
{
if (b & 1)
{
res += a;
}
a <<= 1;
b >>= 1;
}
}

在现代处理器中,乘法无论哪种方式都非常快,但 64 位乘法可能比 32 位值慢一两个时钟周期。仅仅因为现代处理器可以"负担得起"在单个周期内完成此操作的整个逻辑 - 无论是晶体管本身的速度还是这些晶体管占用的面积。

此外,在过去,经常有指令来执行 16 x 16 -> 32 位结果,但如果你想要 32 x 32 -> 32(或 64),编译器将不得不调用库函数 [或内联这样的函数]。今天,我不知道有任何现代高端处理器[x86,ARM,PowerPC]不能做至少64 x 64 -> 64,有些可以做64 x 64 ->128,所有这些都在一条指令中(并不总是一个周期)。

请注意,我完全忽略了"数据是否在缓存中是一个重要因素"这一事实。是的,这是一个因素 - 这有点像以 200 公里/小时行驶时忽略风阻 - 这根本不是你在现实世界中忽略的东西。但是,对于此讨论而言,这并不重要。就像制造跑车的人关心空气动力学一样,要让复杂(或简单)软件快速运行,需要一定程度的关心缓存内容。

对于所有意图和目的,相同的速度(即使计算速度存在差异,它们也是不可估量的)。如果您好奇,以下是对不同 CPU 操作进行基准测试的参考:http://www.agner.org/optimize/instruction_tables.pdf。