C中underflow和nan有什么区别?

What is the difference between underflow and nan in C?

目前我正在学习浮点异常。我正在写一个带有函数的循环。在该函数中,计算出的值等于 0.5。随着循环的进行,输入值除以 10.

循环:

 for(i = 0; i < e; i++)
 {
     xf /= 10.0;   // force increasingly smaller values for x
     float_testk (xf, i);
 }

函数:

void float_testk(float x, int i)
{
    float result;
   
    feclearexcept(FE_ALL_EXCEPT); // clear all pending exceptions
         
    result = (1 - cosf(x)) / (x * x);
        
    if(fetestexcept(FE_UNDERFLOW) != 0)
        fprintf(stderr,"Underflow occurred in double_testk!\n");
    if(fetestexcept(FE_OVERFLOW) != 0)
        fprintf(stderr,"Overflow occurred in double_testk!\n");
    if(fetestexcept(FE_INVALID) != 0)
        fprintf(stderr,"Invalid exception occurred in double_testk!\n");
   
    printf("Iteration %3d, float result for x=%.8f : %f\n",i,x,result);
}

前几次迭代输出约为 0.5,后来由于 CC 而变为 0。一段时间后,这是程序的输出:

Iteration  18, float result for x=0.00000000 : 0.000000
Underflow occurred in double_testk!
Iteration  19, float result for x=0.00000000 : 0.000000
Underflow occurred in double_testk!
Iteration  20, float result for x=0.00000000 : 0.000000
Underflow occurred in double_testk!
Iteration  21, float result for x=0.00000000 : 0.000000
Underflow occurred in double_testk!
Invalid exception occurred in double_testk!
Iteration  22, float result for x=0.00000000 : -nan
Underflow occurred in double_testk!
Invalid exception occurred in double_testk!

我想知道从下溢到 NaN 的过渡过程中发生了什么。因为underflow是指数字太小,内存存不下。

但如果人数已经太少,NaN的目标是什么?

Because underflow means that the number is too small to be stored in the memory.

不完全是;在 floating-point 中,underflow 表示结果低于可以完全精确表示数字的范围。结果可能仍然相当准确。

只要x至少为2−75x * x就会产生non-zero结果。它可能在 floating-point 域的次正规部分,精度正在下降,但 xx 的 real-number 结果大到足以四舍五入到 2−149 或更大。然后,对于这些小 x(1 - cosf(x)) / (x * x) 计算结果为零除以 non-zero 值,因此结果为零。

x小于2−75,则x * x产生零,因为[=10=的real-number结果]•x 太小了,在 floating-point 算术中,它四舍五入为零。然后 (1 - cosf(x)) / (x * x) 的计算结果为零除以零,因此结果为 NaN。这就是您的迭代 22 中发生的情况。

(2−149 是 IEEE-754 binary32 中可表示的最小正值,您的 C 实现可能将其用于 float。Real-number 结果在那个和 2−150 之间将四舍五入为 2−149。较低的结果将四舍五入为 0。假设四舍五入模式是 round-to-nearest, ties-to-even.)

NaN 是 IEEE 754 标准中为 floating-point 算术定义的概念,不是数字不等于负无穷大或正无穷大,NaN 用于算术无法表示的值,不是因为它们太小或太大,而仅仅是因为它们不存在。示例:

1/0 = ∞ //too large     
log (0) = -∞ //too small
sqrt (-1) = NaN //is not a number, can't be calculated

IEEE 754 floating point numbers can represent positive or negative infinity, and NaN (not a number). These three values arise from calculations whose result is undefined or cannot be represented accurately. You can also deliberately set a floating-point variable to any of them, which is sometimes useful. Some examples of calculations that produce infinity or NaN:

您使用这些标志的目的是要符合上述标准。它指定了要记录在状态标志中的五个算术异常:

FE_INEXACT: 不准确的结果,需要四舍五入以存储先前 floating-point 操作的结果。

Set if the rounded (and returned) value is different from the mathematically exact result of the operation.

FE_UNDERFLOW: 较早的 floating-point 操作的结果不正常,精度损失。

Set if the rounded value is tiny (as specified in IEEE 754) and inexact (or maybe limited to if it has denormalization loss, as per the 1984 version of IEEE 754), returning a subnormal value including the zeros.

FE_OVERFLOW: 先前 floating-point 操作的结果太大而无法表示。

Set if the absolute value of the rounded value is too large to be represented. An infinity or maximal finite value is returned, depending on which rounding is used.

FE_DIVBYZERO: 在之前的 floating-point 操作中出现极点错误。

Set if the result is infinite given finite operands, returning an infinity, either +∞ or −∞.

FE_INVALID: 在较早的 floating-point 操作中发生域错误。

Set if a real-valued result cannot be returned e.g. sqrt(−1) or 0/0, returning a quiet NaN.*

*安静的概念NaN:

Quiet NaNs, or qNaNs, do not raise any additional exceptions as they propagate through most operations. The exceptions are where the NaN cannot simply be passed through unchanged to the output, such as in format conversions or certain comparison operations.

来源:

Floating point environment

Floating-point arithmetic

20.5.2 Infinity and NaN

NaN