2014-09-06 3 views
6

Nel tentativo di vedere cosa accadrebbe nel caso di un underflow del float, ho scoperto che potevo rendere i numeri float molto più piccoli di FLT_MIN. Sto usando xcode 5.1 su OS 10.9. Il dialetto della lingua è gnu99.è inferiore a FLT_MIN. perché FLT_TRUE_MIN?

#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; 
} 

Stampe:
Float min è 0.000000 o 1.175494e-38.
L'underflow è 0.000000 o 4.203895e-45
L'intervallo minimo di espansione è -37.

  1. Esiste un metodo più efficace per dimostrare i limiti dei tipi di dati?
  2. Perché FLT_MIN non è in realtà il valore float più piccolo? Ci sono altre costanti che dovrei usare? Dopo aver digitato la domanda precedente ho trovato FLT_TRUE_MIN. Qual è il numero?
+1

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

+0

Scrivilo come risposta, per favore. –

+0

Hai menzionato che il tuo dialetto è "gnu99"; Vorrei attirare la tua attenzione sul fatto che "FLT_TRUE_MIN" è stato introdotto con C11, quindi in modo formale richiederebbe l'uso del dialetto "gnu11". – AntoineL

risposta

5

2 possibilità di ottenere "sotto il minimo":

  1. float gamma:

    tipici float numeri hanno 2 gamme: piena precisione (range normale) da FLT_MAX fino a FLT_MIN e un 2 ° serie con riduzione della precisione da FLT_MIN a FLT_TRUE_MIN. Questo secondo intervallo, chiamato "subnormale" fornisce in genere circa 10^-7 più di distanza.

    FLT_TRUE_MIN è il "numero in virgola mobile positivo minimo"

    FLT_MIN è il "numero in virgola mobile di minimo normalizzato positivo"

    FLT_MIN_10_EXP è il "numero intero minimo negativo tale che 10 elevato a tale la potenza è compresa nell'intervallo dei numeri in virgola mobile normalizzati "

    C11dr §5.2.4.2.2

    In generale 0 < FLT_TRUE_MIN <= FLT_MIN <= 10^FLT_MIN_10_EXP <= 10^-37

  2. matematiche eseguite come double.

    printf() covered ogni float passato ad esso a double. C consente al codice di ottimizzare in modo che il valore passato a printf() possa essere il prodotto double di FLT_MIN * 0.0000004.

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

    Aveva all'uscita stati 4.701976e-45 anziché 4.203895e-45, questo sarebbe stato il caso.


Nota su "subnormali". Un motivo valido per i numeri subnormali (o denormali) si trova nel seguente problema.

float a,b; 
... // somehow a and b are set. 

// Are the 2 below equivalent? 
if (a == b) foo(); 
if ((a - b) == 0) foo(); 

Senza numeri subnormali, 2 quasi gli stessi numeri di valore vicino FLT_MIN avrebbero una differenza matematico non zero molto sotto FLT_MIN e il risultato sarebbe round 0.0.

Con numeri subnormali, la differenza di ogni coppia di diversi float s è rappresentabile da qualcosa di diverso da 0.0. **

** Eccetto +0.0, -0.0. Gli zeri firmati hanno le loro peculiarità.

3

In termini veramente semplici, non esatti, i punti in virgola mobile sono memorizzati come 0.xxxxx x 2^yyyyyy. I numeri "normali" sono necessari per NON avere zeri iniziali nella parte xxxxx. Quindi il numero più piccolo che puoi creare è qualcosa come 0.10000 x 2^-111111. Tuttavia, se "imbroglia" e denormalizza il numero, puoi crearne uno come 0.000001 x 2^-111111, che è più piccolo ma ha meno cifre significative.

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

1

Rappresentazione di un numero fluttuante come y = (+/-) significand x base^(exponent - precision), ogni y != 0 ha una rappresentazione unica se si assicurarsi che significand >= base^(precision - 1). Un valore diverso da zero che soddisfa questo è chiamato normalizzato. Ora FLT_MIN è il minimo normalizzato positivo float, mentre FLT_TRUE_MIN è il minimo che si ottiene senza la restrizione normalizzata.

In altre parole, FLT_MIN = base^(FLT_MIN_EXP - 1) e FLT_TRUE_MIN = base^(FLT_MIN_EXP - precision).