5

如果必须计算给定 int 值的一小部分,请说:

int j = 78;
int i = 5* j / 4;

这是否比这样做更快:

int i = 1.25*j; // ?

如果是,是否有一个转换因子可以用来决定使用哪个,例如在int一次float乘法的同时可以进行多少次除法?

编辑:我认为评论清楚地表明浮点数学会变慢,但问题是,减慢多少?如果我需要将每个float乘法替换为N int个除法,那么N将不再值得吗?

4

3 回答 3

5

你说过所有的价值观都是动态的,这会有所不同。对于特定的值5 * j / 4,整数运算将非常快,因为几乎最坏的情况是编译器将它们优化为两次移位和一次加法,加上一些混乱以应对j负数的可能性。如果 CPU 可以做得更好(单周期整数乘法或其他),那么编译器通常会知道它。编译器优化此类事情的能力的限制基本上出现在您为广泛的 CPU 系列进行编译(例如,生成最小公分母 ARM 代码)时,编译器并不真正了解硬件,因此不能总是做出好的选择。

我想如果ab被固定了一段时间(但在编译时不知道),那么有可能对 的许多不同值进行k = double(a) / b一次又一次计算,可能比计算的许多不同值更快。我不会指望它。int(k * x)xa * x / bx

如果所有值每次都不同,那么计算 的浮点除法1.25,然后是浮点乘法,似乎不太可能比整数乘法和整数除法更快。但你永远不知道,测试它。

在现代处理器上,实际上不可能给出简单的相对时序,这在很大程度上取决于周围的代码。代码中的主要成本通常不是“实际”操作:它是“不可见”的东西,例如指令管道在依赖项上停滞,或将寄存器溢出到堆栈,或函数调用开销。执行这项工作的函数是否可以内联可能很容易比函数实际执行它的方式产生更大的差异。就性能的明确声明而言,您基本上可以测试真实代码或闭嘴。但是很有可能,如果您的值以整数开始,对它们执行整数操作将比转换为double并执行类似数量的double操作更快。

于 2013-09-27T23:30:50.807 回答
1

断章取义是不可能回答这个问题的。此外,由于整数和浮点算术的属性,包括舍入和溢出,5*j/4通常不会产生与 相同的结果。(int) (1.25*j)

如果您的程序主要执行整数运算,则转换j为浮点数、乘以 1.25 以及转换回整数可能是免费的,因为它使用的浮点单元不会以其他方式使用。

或者,在某些处理器上,操作系统可能会将浮点状态标记为无效,这样当一个进程第一次使用它时,就会出现异常,操作系统会保存浮点寄存器(其中包含来自另一个进程),恢复或初始化进程的寄存器,并从异常中返回。相对于正常的指令执行而言,这将花费大量时间。

答案还取决于程序正在执行的特定处理器模型的特性,以及操作系统、编译器如何将源代码转换为程序集,甚至可能还取决于系统上的其他进程在做什么。

5*j/4此外,和之间的性能差异(int) (1.25*j)通常太小而无法在程序中引起注意,除非它或类似的操作重复很多次。(如果是的话,向量化代码可能会带来巨大的好处,也就是说,使用许多现代处理器的单指令多数据 [SIMD] 特性来一次执行多个操作。)

于 2013-09-27T23:58:48.407 回答
0

在您的情况下,5*j/4这将比1.25*j因为除以 2 的幂可以通过右移轻松操作,并且5*j可以通过许多架构(例如LEAx86)上的单个指令或ADDARM 上的移位来完成要快得多。大多数其他人最多需要2条指令,j + (j >> 2)但这样它仍然可能比浮点乘法更快。此外,通过这样做int i = 1.25*j,您需要 2 次往返转换intdouble以及 2 次跨域数据移动,这通常非常昂贵

在其他情况下,当分数不能用二进制浮点数表示时(如3*j/10),那么使用 int 乘法/除法会更正确(因为 0.3 在浮点数中不完全是 0.3),而且很可能更快(因为编译器可以通过将常数转换为乘法来优化除法)


ij是浮点类型的情况下,乘以另一个浮点值可能会更快。因为在 float 和 int 域之间移动值需要时间,而 int 和 float 之间的转换也需要时间,正如我上面所说

一个重要的区别是5*j/4如果 j 太大会溢出,但1.25*j不会

也就是说,对于“哪个更快”和“多快”的问题没有一般的答案,因为它取决于特定的架构和特定的上下文。您必须对您的系统进行测量并做出决定。但是,如果一个表达式对很多值重复执行,那么是时候转移到 SIMD

也可以看看

于 2013-09-28T01:04:32.663 回答