漂浮小于FLT_MIN。 为什么FLT_TRUE_MIN?

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

#include  #include  #include  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. 是否有更有效的方法来certificate数据类型的限制?
  2. 为什么FLT_MIN实际上不是最小的浮点值? 我应该使用其他常量吗? 输入上一个问题后,我找到了FLT_TRUE_MIN。 这个号码是多少?

获得“低于最低”的2种可能性:

  1. float范围:

    典型的float有2个范围:从FLT_MAXFLT_MIN全精度(正常范围)和从FLT_MAXFLT_MIN精度降低的第二个范围。 这个称为“次正常”的第二个范围通常提供大约10 ^ -7个范围。

    FLT_TRUE_MIN是“最小正浮点数”

    FLT_MIN是“最小归一化正浮点数”

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

    C11dr§5.2.4.2.2

    通常0 < FLT_TRUE_MIN <= FLT_MIN <= 10^FLT_MIN_10_EXP <= 10^-37

  2. 数学表现为double

    printf()传递给它的每个float转换为double 。 C允许代码进行优化,使得传递给printf()的值可能是FLT_MIN * 0.0000004double乘积。

     float underflow = FLT_MIN * 0.0000004; printf("%e\n", underflow); 

    如果产量是4.701976e-45而不是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(); 

如果没有次正规数,则FLT_MIN附近的2个几乎相同的数值将具有远低于FLT_MIN的非零数学差异,并且结果将舍入为0.0

对于次正规数,每对不同float的差值可以用0.0以外的其他值表示。 **

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

在非常简单,不精确的术语中,浮点存储为0.xxxxx x 2 ^ yyyyyy。 “正常”数字在xxxxx部分中不需要前导零。 因此,您可以制作的最小数字是0.10000 x 2 ^ -111111。 但是,如果你“欺骗”并非规范化数字,你可以制作一个像0.000001 x 2 ^ -111111,这个更小但有效位数更少。

见http://en.wikipedia.org/wiki/Denormal_number

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

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