C乘法或加法浮点数结果NaN

Ale*_*lex 0 c floating-point gcc nan

我在程序中使用libresample.经过一段时间(大约50分钟),它在一个工作站的lib函数lrsFilterUD()中崩溃.

float lrsFilterUD(float Imp[],  /* impulse response */
              float ImpD[], /* impulse response deltas */
              UWORD Nwing,  /* len of one wing of filter */
              BOOL Interp,  /* Interpolate coefs using deltas? */
              float *Xp,    /* Current sample */
              double Ph,    /* Phase */
              int Inc,    /* increment (1 for right wing or -1 for left) */
              double dhb)
{
   float a;
   float *Hp, *Hdp, *End;
   float v, t;
   double Ho;

   v = 0.0; /* The output value */
   Ho = Ph*dhb;
   End = &Imp[Nwing];
   if (Inc == 1)        /* If doing right wing...              */
   {                      /* ...drop extra coeff, so when Ph is  */
      End--;            /*    0.5, we don't do too many mult's */
      if (Ph == 0)      /* If the phase is zero...           */
         Ho += dhb;     /* ...then we've already skipped the */
   }                         /*    first sample, so we must also  */
                        /*    skip ahead in Imp[] and ImpD[] */

   if (Interp)
      while ((Hp = &Imp[(int)Ho]) < End) {
         t = *Hp;       /* Get IR sample */
         Hdp = &ImpD[(int)Ho];  /* get interp bits from diff table*/
         a = Ho - floor(Ho);      /* a is logically between 0 and 1 */
         t += (*Hdp)*a; /* t is now interp'd filter coeff */
         t *= *Xp;      /* Mult coeff by input sample */
         v += t;            /* The filter output */
         Ho += dhb;     /* IR step */
         Xp += Inc;     /* Input signal step. NO CHECK ON BOUNDS */
      }
   else 
      while ((Hp = &Imp[(int)Ho]) < End) {
         dprintf("while begin: Hp = %p, *Hp = %a, (int)Ho = %d, Imp[(int)Ho] = %a, &Imp[(int)Ho] = %p", Hp, *Hp, (int)Ho, Imp[(int)Ho], &Imp[(int)Ho]);
         t = *Hp;       /* Get IR sample */
         dprintf("before t = %a, *Xp = %a, Xp = %p", t, *Xp, Xp);
         t *= *Xp;      /* Mult coeff by input sample */
         dprintf("after2 t = %a, v = %a", t, v);
         v += t;            /* The filter output */
         dprintf("v = %a", v);
         Ho += dhb;     /* IR step */
         Xp += Inc;     /* Input signal step. NO CHECK ON BOUNDS */
      }

   return v;
}
Run Code Online (Sandbox Code Playgroud)

我在乘法之前和之后记录了t,*Xp,Xp的值:

while begin: Hp = 0xaf5daa8, *Hp = -0.009034, (int)Ho = 16384, Imp[(int)Ho] = -0.009034, &Imp[(int)Ho] = 0xaf5daa8
before multiplication t = -0.009034, *Xp = 0.000000, Xp = 0xaebe9b8
after multiplication t = nan
Run Code Online (Sandbox Code Playgroud)

这段代码运行很多次,崩溃前有相同的t和Xp值:

before multiplication t = -0.009034, *Xp = 0.000000, Xp = 0xaebe9c8
after multiplication t = -0.000000, v = 282.423676
Run Code Online (Sandbox Code Playgroud)

或另外一个案例:

before addition t = -460.799988, v = 0.000000
after addition v = nan
Run Code Online (Sandbox Code Playgroud)

什么可能导致南?这是在Linux上使用gcc 4.1.2编译的.

更新:将变量打印为%a.结果:

//t = 0x1.2806bap+2
//Hp = 0xb3bb870
t = *Hp;
//t = nan
Run Code Online (Sandbox Code Playgroud)

更新2:如果代码由icpc编译,则不存在此类问题.那么有编译器特定的问题吗?

Eri*_*hil 5

显然,-0.009034•0.000000不应产生NaN.因此,问题中呈现的代码和数据不是实际计算的准确表示,或者计算实现是有缺陷的.

如果我们假设硬件和基本计算实现没有缺陷,那么调查的一些可能性包括:

  • 记录t并且*Xp未能记录乘法之前t*Xp之前的正确值,或者t在乘法之后立即记录正确的值.
  • 显示值t*Xp不正确.例如,用于显示的格式*Xp显示"0.000000",即使*Xp有其他值,例如NaN.
  • Xp某点不合适,导致*Xp不可靠(例如,由外部操作改变).
  • 显示的代码不准确.例如,它来自旧的源已被更改,或者它是新源,但正在执行先前编译的代码.

注意:当浮点对象调试,你应该带格式,如"%F"打印,特别是没有默认值的数字编号.您应该使用"%a"打印,它使用十六进制表示打印浮点值的确切值.在许多情况下,您也可以使用"%.99g",前提是您的C实现提供了将浮点值转换为十进制的良好转换.