0

与其他浮点乘法相比,浮点乘法导致受 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);
  }
}
4

1 回答 1

1

执行 .9 * FLT_MIN 需要更长的时间的原因是结果小于浮点数可以表示的最小值。这会导致处理器引发异常,该异常由操作系统处理,并且可能涉及调用用户空间中的函数。与完全在硬件中完成的简单浮点乘法相比,这需要很长时间。

如何解决?取决于您的平台和构建工具。如果您使用的是 gcc,那么它会尝试使用 CPU 设置来优化某些操作,具体取决于您设置的标志。查看 gcc 手册以了解 -ffast-math 和相关的浮点优化标志。请注意,使用这些标志可能会导致不完全符合 IEEE 浮点规范的结果。

于 2014-01-19T14:22:46.310 回答