Mat*_*Mut 0 c++ floating-point
众所周知,除法需要比乘法更多的时钟周期来计算.(请参考此处的讨论:浮点除法与浮点乘法.)
我已经使用x * 0.5,而不是x / 2和x * 0.125,而不是x / 8在我的C++代码,但我不知道我应该坚持多久.
对于反转时1 / num重复出现的小数(即.是重复的十进制数),我使用除法而不是乘法(例如x / 2.2代替x * 0.45454545454).
我的问题是:在迭代次数相当多的循环中,我应该用它们的重复乘法对应物替换除数(即x * 0.45454545454代替x / 2.2),还是会带来更大的精度损失?
编辑:我做了一些分析,我在Visual Studio中启用了完全优化,使用Windows QueryPerformanceCounter()函数来获取分析结果.
int main() {
init();
int x;
float value = 100002030.0;
start();
for (x = 0; x < 100000000; x++)
value /= 2.2;
printf("Div: %fms, value: %f", getElapsedMilliseconds(), value);
value = 100002030.0;
restart();
for (x = 0; x < 100000000; x++)
value *= 0.45454545454;
printf("\nMult: %fms, value: %f", getElapsedMilliseconds(), value);
scanf_s("");
}
Run Code Online (Sandbox Code Playgroud)
结果为:Div:426.907185ms,值:0.000000 Mult:289.616415ms,值:0.000000
即使在优化的情况下,除法几乎是乘法的两倍.性能优势得到保证,但它们会降低精度吗?
对于反转时重复的小数(即1/num是重复的十进制),我使用除法而不是乘法(例如x/2.2而不是x*0.45454545454).
众所周知,22/10在二进制浮点中无法准确表示,因此您所实现的只是稍微不准确的值,而不是乘以稍微不准确的值.
实际上,如果意图是除以22/10或其他一些不一定在二进制浮点中可以完全表示的实数值,那么一半时间,乘法比除法更精确,因为它是巧合的1/X的相对误差小于X的相对误差.
另一个评论是你的微基准测试会遇到次正规数,其中时间不能代表正常浮点数上常规操作的时序,并且在一段时间后,value为零,这再次意味着时间不具代表性乘法和除法数的现实.正如Mark Ransom所说,至少应该使两个测量的操作数相同:因为当前写入的所有乘法都采用零操作数并导致零.此外,由于2.2和0.45454545454都有型double,基准测试是测量双精度乘法和除法,如果你愿意实现由双精度乘法单精度除法,这需要不涉及任何精度损失(但你必须提供更多数字1/2.2).
但是不要让自己被愚弄试图修复微观基准.你不需要它,因为当X不能比1/X更准确地表示时,没有权衡.没有理由不使用乘法.
注意:您应该明确地乘以,1 / X因为由于这两个操作/ X并且* (1 / X)略有不同,编译器本身无法进行替换.另一方面,你不需要替换 / 2,* 0.5因为任何值得盐的编译器都应该为你做.