huge elapsed time for multiplication of FLT_MIN
本问题已经有最佳答案,请猛点这里访问。
与其他浮点乘法相比,浮点乘法导致受flt_min seam限制的结果非常慢。在我的Linux机器上运行下面的示例代码,我得到了以下结果:
1 2 3 4 5 6 | Elapsed time for 1E09 iterations of 0 * 0.900000 : 2.623269 s Elapsed time for 1E09 iterations of 1.17549e-38 * 0.900000 : 73.851011 s Elapsed time for 1E09 iterations of 2.35099e-38 * 0.900000 : 2.637788 s Elapsed time for 1E09 iterations of 0.00870937 * 0.900000 : 2.632788 s Elapsed time for 1E09 iterations of 1 * 0.900000 : 2.654571 s Elapsed time for 1E09 iterations of 3.40282e+38 * 0.900000 : 2.639316 s |
操作1.17549E-38*0.9的时间似乎至少是其他被测乘法操作的25倍。这是一个众所周知的问题吗?
在一个时间紧迫的项目中,需要执行大量可能导致flt_min的乘法,有什么方法可以快速解决这个问题?(我不能在乘法前检查每个值,但我可以容忍乘法结果中E-5的顺序错误)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | #include <sys/time.h> #include <stdio.h> #include <float.h> #define N_VALS 6 #define ALMOST_MIN FLT_MIN*2 int timeval_subtract (struct timeval *result,struct timeval * start,struct timeval *stop) { long int sdiff= stop-> tv_sec - start->tv_sec; long int udiff=stop->tv_usec - start-> tv_usec; if (udiff<0) { udiff=1000000+udiff; sdiff--; } result->tv_sec = sdiff; result->tv_usec = udiff; } int main() { float values [N_VALS]={0.0f,FLT_MIN,ALMOST_MIN, 0.00870937f, 1.0f, FLT_MAX}; float out, mul=0.9f; int i, j, err; struct timeval t_start, t_stop, t_elaps; for (j=0; j<N_VALS; j++) { err=gettimeofday(&t_start, NULL); for (i=0; i<1000000000; i++) out=values[j]*mul; err=gettimeofday(&t_stop, NULL); timeval_subtract(&t_elaps, &t_start, &t_stop); printf("Elapsed time for 1E09 iterations of %g * %f : %ld.%06ld s ", values[j], mul, t_elaps.tv_sec, t_elaps.tv_usec); } } |
号
执行.9*flt_min需要花费更长时间的原因是,结果小于浮点所能表示的最小值。这会导致处理器引发异常,异常由操作系统处理,可能涉及到用户空间中的调用函数。与完全在硬件中完成的简单浮点乘法相比,这需要很长的时间。
如何修复?取决于您的平台和构建工具。如果您使用gcc,那么它会根据您设置的标志,尝试使用cpu设置来优化一些操作。查看gcc手册中的-ffast数学和相关浮点优化标志。请注意,使用这些标志可能导致结果不完全符合IEEE浮点规范。