与其他浮点乘法相比,浮点乘法导致FLT_MIN接缝限制的结果非常慢。在我的Linux机器上运行下面的示例代码,我得到了以下结果:
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的顺序错误)
#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 \n", values[j], mul, t_elaps.tv_sec, t_elaps.tv_usec);
}
}
答案 0 :(得分:1)
需要花费更长时间的原因.9 * FLT_MIN是结果小于float可以表示的最小值。这导致处理器引发异常,该异常由OS处理并且可能涉及在用户空间中调用函数。与完全用硬件完成的简单浮点乘法相比,这需要很长时间。
如何解决?取决于您的平台和构建工具。如果您正在使用gcc,那么它会尝试使用CPU设置来优化某些操作,具体取决于您设置的标志。查看-ffast-math和相关浮点优化标志的gcc手册。请注意,使用这些标志可能会导致结果不符合IEEE浮点规范。