flotte plus petit que FLT_MIN. pourquoi FLT_TRUE_MIN?

Dans une tentative pour voir ce qui se produirait dans le cas d’un sous-flottant, j’ai trouvé que je pouvais faire des nombres flottants beaucoup plus petits que FLT_MIN. J’utilise xcode 5.1 sur OS 10.9. Le dialecte de la langue est le 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; } 

Impressions:
Float min = 0.000000 ou 1.175494e-38.
Le débordement est 0.000000 ou 4.203895e-45
Min float exp est de -37.

  1. Existe-t-il une méthode plus efficace pour démontrer les limites des types de données?
  2. Pourquoi FLT_MIN n’est-il pas la plus petite valeur float? Y a-t-il d’autres constantes que je suis supposé utiliser? Après avoir tapé la question précédente, j’ai trouvé FLT_TRUE_MIN. Quel est le nombre?

2 possibilités pour obtenir “en dessous du minimum”:

  1. gamme de float :

    Les nombres float typiques ont 2 plages: précision FLT_MAX (plage normale) de FLT_MAX jusqu’à FLT_MIN et une deuxième plage avec réduction de la précision de FLT_MIN jusqu’à FLT_TRUE_MIN . Cette 2ème plage, appelée “subnormal” fournit généralement environ 10 ^ -7 plage de plus.

    FLT_TRUE_MIN est le “nombre minimal positif en virgule flottante”

    FLT_MIN est le “nombre minimum normalisé positif en virgule flottante”

    FLT_MIN_10_EXP est le “nombre entier négatif minimal tel que 10 élevé à cette puissance se situe dans la plage des nombres à virgule flottante normalisés”

    C11dr §5.2.4.2.2

    En général 0 < FLT_TRUE_MIN <= FLT_MIN <= 10^FLT_MIN_10_EXP <= 10^-37

  2. Math effectué en double .

    printf() couvre chaque float passé à un double . C permet au code d’optimiser de telle sorte que la valeur transmise à printf() puisse être le double produit de FLT_MIN * 0.0000004 .

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

    Si la sortie avait été 4.701976e-45 plutôt que 4.203895e-45 , cela aurait été le cas.


Note sur "subnormal". Une raison impérieuse pour des nombres sous-normaux (ou dénormaux) réside dans le problème suivant.

 float a,b; ... // somehow a and b are set. // Are the 2 below equivalent? if (a == b) foo(); if ((a - b) == 0) foo(); 

Sans nombres sous-normaux, 2 nombres presque identiques au voisinage de FLT_MIN auraient une différence mathématique non nulle bien inférieure à FLT_MIN et le résultat serait arrondi à 0.0 .

Avec des nombres inférieurs à la normale, la différence de chaque paire de float différents peut être représentée par autre chose que 0.0 . **

** Sauf +0.0, -0.0 . Les zéros signés ont leurs propres particularités.

En termes très simples et non exacts, les points flottants sont stockés sous la forme 0.xxxxx x 2 ^ yyyyyy. Les nombres “normaux” ne doivent PAS comporter de zéros dans la partie xxxxx. Donc, le plus petit nombre que vous pouvez faire est quelque chose comme 0.10000 x 2 ^ -111111. Toutefois, si vous “sortingchez” et dénormalisez le nombre, vous pouvez en créer un comme 0,000001 x 2 ^ -111111, qui est plus petit mais comporte moins de chiffres significatifs.

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

Représentant un nombre flottant sous la forme y = (+/-) significand x base ^ (exponent - precision) , chaque y != 0 a une représentation unique si vous vous assurez que cette significand >= base ^ (precision - 1) . Un y non nul qui satisfait cela s’appelle normalisé . Maintenant, FLT_MIN est le float positif normalisé minimum, alors que FLT_TRUE_MIN est le minimum réel obtenu sans la ressortingction normalisée.

En d’autres termes, FLT_MIN = base ^ (FLT_MIN_EXP - 1) et FLT_TRUE_MIN = base ^ (FLT_MIN_EXP - precision) .