2013-09-27 92 views
3

如果一个人计算给定int值的一小部分,说:整数除法或浮点乘法?

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

这是不是做快:

int i = 1.25*j; // ? 

如果是,是否有一个可以使用的转换因子决定使用哪一个,因为在同一时间内可以完成多少个int乘法?

编辑:我想评论说清楚的浮点运算会慢一些,但问题是,多少?如果我需要更换每个float乘以$ N $ int部门,那么$ N $会不会再值得呢?

+9

你有基准每一个? – Mysticial

+3

这些数字中有多少是动态的? –

+1

@KerrekSB指的是编译器为你优化所有这些。因此,基准为什么很重要。 – Adam

回答

5

你说过所有的值都是动态的,这是有差别的。对于特定值5 * j/4,整数运算将会非常快速,因为几乎最糟糕的情况是编译器将它们优化为两个班次和一个加法,再加上一些混乱以应对j为负的可能性。如果CPU可以做得更好(单周期整数乘法或其他),那么编译器通常会知道它。编译器优化这种类型的能力的限制基本上来自于编译多种CPU的时候(例如,生成最低公分母ARM代码),编译器并不十分了解硬件,因此不能总是做出好的选择。

我想,如果ab是固定的一段时间(但在编译时不知道),那么它可能是计算k = double(a)/b一次,然后int(k * x)x许多不同的值,可能比计算a * x/b快对于许多不同的值x。我不会指望它。

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

这不是真的有可能让这个简单的相对时序上现代的处理器,它实际上取决于周围的代码很多。代码中的主要成本通常不是“实际”操作:它是“隐形”的东西,例如指令流水线停滞于依赖关系,或溢出寄存器堆栈或函数调用开销。做这个工作的函数是否可以内联可能会比函数的实际功能更容易做出更多的改变。就性能的权威性陈述而言,你基本上可以测试真实代码或者闭嘴。但是,如果你的值是以整数开始的,那么对它们进行整数运算的速度会比转换为double并做类似数量的double运算更快。

1

这是不可能的情况下回答这个问题。由于整数和浮点运算的特性(包括舍入和溢出),另外5*j/4通常不会产生与(int) (1.25*j)相同的结果。

如果你的程序主要是做整数运算,那么将j转换为浮点数,乘以1.25,并且转换回整数可能是免费的,因为它使用了不以其他方式参与的浮点单元。

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

答案也取决于程序正在执行的特定处理器模型,以及操作系统,编译器如何转换源到组件的特性,并且甚至可能是什么系统上的其他进程正在做的。

此外,5*j/4(int) (1.25*j)之间的性能差异是最经常太小,是显着的一个程序,除非它或操作像它被重复许多次。 (并且,如果是这样的话,对代码进行矢量化可能会带来巨大的好处,也就是说,使用许多现代处理器的单指令多数据[SIMD]功能一次执行多个操作。)

0

对于您的情况, 5*j/4将比1.25*j快得多,因为通过2的幂除法可通过右移容易地操纵,并且5*j可以由单个指令上ARM上做一些架构,诸如LEA在x86或ADD(带换档)。大多数其他人最多需要2条指令(如j + j/4),而不是缓慢的乘法和非常缓慢的除法。使用int multiply/divide还允许编译器优化除以常量的分割,并且不需要转换为浮点值和从浮点值转换。

对于其他情况下,当分数不浮点表示的(如3*j/10)通过int乘法/除法会更正确的(因为0.3是不是二进制浮点正好0.3),并极有可能更快(因为编译器可以通过将其转换为乘以其乘法逆而将除以常量)。 [查看更多Divide a number by 3 without using *, /, +, -, % operatorsDivide by 10 using bit shifts?Divisiblity of 5 without using % and/operator]。而且不需要转换浮点数值,也不需要花费很多时间。

对于i和j属于浮点类型的情况,乘以另一个浮点值可能会更快。因为在float和int域之间移动值需要时间,正如我上面所说的,int和float之间的转换也需要时间。这就是为什么有不同的SSE或AVX指令可以在不同的域上执行完全相同的操作。

也就是说,对于“哪个更快”和“更快多快”这个问题,没有一般的答案,因为它取决于特定的架构和特定的环境。您必须测量您的系统并决定。但是如果一个表达式重复地处理了很多值,那么就该转向SIMD了。

Why is int * float faster than int/int?
Should I use multiplication or division?
Floating point division vs floating point multiplication