漂浮小于FLT_MIN。为什么FLT_TRUE_MIN?

时间:2014-09-06 22:20:01

标签: c floating-point gnu99

为了看看在浮动下溢的情况下会发生什么,我发现我可以使浮点数比FLT_MIN小得多。我在OS 10.9上使用xcode 5.1。语言方言是gnu99。

#include <stdio.h>
#include <stdlib.h>
#include <float.h>

int main(int argc, const char * argv[])
{
    float underflow = FLT_MIN * 0.0000004;

    printf("Float min is %f or %e.\nUnderflow is %f or %e\nMin float exp is %d.\n", FLT_MIN, FLT_MIN, underflow, underflow, FLT_MIN_10_EXP);

    return 0;
}

打印:
浮点数为0.000000或1.175494e-38 下溢为0.000000或4.203895e-45
Min float exp是-37。

  1. 是否有更有效的方法来证明数据类型的限制?
  2. 为什么FLT_MIN实际上不是最小的浮点值?我应该使用其他常量吗?输入上一个问题后,我找到了FLT_TRUE_MIN。这个号码是什么?

3 个答案:

答案 0 :(得分:7)

获得“低于最低限度”的两种可能性:

  1. float范围:

    典型float个数字有2个范围:从FLT_MAXFLT_MIN的完整精度(正常范围)和从FLT_MIN到{{的精度降低的第二个范围1}}。第二个范围,称为“次正常”,通常提供大约10 ^ -7个范围。

      

    FLT_TRUE_MIN是“最小正浮点数”

         

    FLT_TRUE_MIN是“最小标准化正浮点数”

         

    FLT_MIN是“最小负整数,使得提升到该幂的10在标准化浮点数范围内”

         

    C11dr§5.2.4.2.2

    一般FLT_MIN_10_EXP

  2. 数学表现为0 < FLT_TRUE_MIN <= FLT_MIN <= 10^FLT_MIN_10_EXP <= 10^-37

    double会将传递给printf()的每个float转换为double。 C允许代码进行优化,以便传递给printf()的值可能是double的{​​{1}}乘积。

    FLT_MIN * 0.0000004

    如果输出为float underflow = FLT_MIN * 0.0000004; printf("%e\n", underflow); 而不是4.701976e-45,情况就是这样。


  3. 关于“次正常”的注释。 次正规(或非正规)数字的一个令人信服的原因在于以下问题。

    4.203895e-45

    如果没有次正规数,则float a,b; ... // somehow a and b are set. // Are the 2 below equivalent? if (a == b) foo(); if ((a - b) == 0) foo(); 附近的2个几乎相同的数值将具有非零数学差异,远低于FLT_MIN,结果将舍入为FLT_MIN

    对于次正规数,每对不同0.0 s的差异可由float以外的其他内容表示。 **

    ** 0.0除外。签名零有自己的特点。

答案 1 :(得分:3)

在非常简单,不精确的术语中,浮点存储为0.xxxxx x 2 ^ yyyyyy。 &#34;正常&#34;数字必须在xxxxx部分中没有前导零。因此,您可以制作的最小数字是0.10000 x 2 ^ -111111。但是,如果你&#34;作弊&#34;并且可以使你的数字非规范化,例如0.000001 x 2 ^ -111111,它更小但有效位数更少。

请参阅http://en.wikipedia.org/wiki/Denormal_number

答案 2 :(得分:1)

如果您确定y = (+/-) significand x base ^ (exponent - precision),则表示浮动数字为y != 0,每个significand >= base ^ (precision - 1)都有唯一的代表。满足此要求的非零y称为规范化。现在FLT_MIN是最低标准化正数float,而FLT_TRUE_MIN是没有标准化限制的真正最低值。

换句话说,FLT_MIN = base ^ (FLT_MIN_EXP - 1)FLT_TRUE_MIN = base ^ (FLT_MIN_EXP - precision)