C 长双精度(80位)的速度是双精度的两倍,具有安全的数学优化功能
我一直认为,在使用C 长双精度(80位)的速度是双精度的两倍,具有安全的数学优化功能,c,gcc,floating-point,compiler-optimization,C,Gcc,Floating Point,Compiler Optimization,我一直认为,在使用-funsafe数学优化时,使用长双精度数据类型的计算速度大约是使用双精度的两倍。我想了解一下这一点,因为80位格式早就被弃用了,或者我可能正在用double数据类型做一些非常愚蠢的事情。编译器是g++4.8.2,目标是x86_64(因此,如果我不使用长双精度,gcc更喜欢SSE2) 我的代码大致如下(伪代码): //x是一个浮点数数组 对于i->x尺寸 累加器=0 对于k->kmax 累加器+=A[k]*(B[k]*cos(C*k*x[i])-D[k]*sin(C*k*x[i
-funsafe数学优化时,使用长双精度
数据类型的计算速度大约是使用双精度
的两倍。我想了解一下这一点,因为80位格式早就被弃用了,或者我可能正在用double
数据类型做一些非常愚蠢的事情。编译器是g++4.8.2,目标是x86_64(因此,如果我不使用长双精度
,gcc更喜欢SSE2)
我的代码大致如下(伪代码):
//x是一个浮点数数组
对于i->x尺寸
累加器=0
对于k->kmax
累加器+=A[k]*(B[k]*cos(C*k*x[i])-D[k]*sin(C*k*x[i]);
x[i]+=F*累加器;
如果(x[i]>=1/2)x[i]=integer(x[i]+1/2);
如果(x[i]<-1/2)x[i]=整数(x[i]-1/2);
A
,B
。。是一些预计算的数组/常量
加速似乎与缓存线问题无关,因为如果我使用OpenMP并行化外部for循环,我会得到相同的相对加速
编辑:
我更正了伪代码:注意cos
和sin
有相同的参数,这就是最终加速的原因(请参见gsg的答案和注释)。我猜差异是由于cos
造成的
必须将长双精度
数学编译成x87指令,从而使x87操作fcos
的使用变得简单高效。但是,xmm
寄存器没有超越操作,因此对cos的调用必须生成代码,将double
移动到x87堆栈上并调用fcos
,或者进行函数调用以执行等效工作。对于这个编译器和机器来说,这些可能更昂贵
您可以通过查看程序集(查找callcos
或x87指令)来验证这一点,也可能值得使用-mfpmath=387
进行编译,以查看性能特征是否发生变化。if
和for
语句的分支历史记录是否有任何变化?原因是什么两个版本的汇编程序输出?当使用long double
时,您使用的是cosl()
还是cos()
?您的“80位格式从很长时间以来就被弃用”的来源是什么?@PatriciaShanahan我不确定我是否理解您的意思。我不使用任何基于配置文件的优化,并且if/elseif的平均使用次数也不会改变。请检查。你有没有解释过这只会发生在-funsafe数学优化中?因为当x87 FCO“不安全”时,@LorenzoPistone,x87三角指令在某些型号的处理器上具有低于标准的参数缩减。请参见观察:gcc在历史上发出了对cos
的调用,除非指定了-ffast math
,在这种情况下,它使用fcos
指令。这个决定可能是因为cos(3)
应该为NaN
参数设置errno
,但我不确定。我在问题中输入了一个错误:我没有两个cos
,而是一个cos
和一个sin
具有相同参数。我在汇编中看到这条指令,fsincos
,我很确定这就是大幅加速的原因。没有-funsafe数学优化
,我接到一个电话到sincosl
@gsg,我接受了你的回答。如果你也提到这件事,那就太好了。其他操作,如sqrt
似乎不受-funsafe数学优化的影响。
//x is an array of floating point numbers
for i -> x.size
accumulator = 0
for k -> kmax
accumulator += A[k]*(B[k]*cos(C*k*x[i]) - D[k]*sin(C*k*x[i]));
x[i] += F*accumulator;
if(x[i] >= 1/2) x[i] -= integer(x[i]+1/2);
else if(x[i] < -1/2) x[i] -= integer(x[i]-1/2);