2016-04-24 31 views
6

Se dovessi produrre valori in virgola mobile nel modo seguente:La distribuzione reale uniforme "da min a max" produce Inf, -Inf o NaN?

template <typename T> 
T RandomFromRange(T low, T high){ 
    std::random_device random_device; 
    std::mt19937 engine{random_device()}; 
    std::uniform_real_distribution<T> dist(low, high); 
    return dist(engine); 
} 

template <typename T> 
T GetRandom(){ 
    return RandomFromRange 
    (std::numeric_limits<T>::min(),std::numeric_limits<T>::max()); 
} 

//produce floating point values: 
auto num1 = GetRandom<float>(); 
auto num2 = GetRandom<float>(); 
auto num3 = GetRandom<float>(); 
//... 

E 'possibile che io mai tornare un NaN, Inf o -Inf?

+1

Dato che nessuno di quelli rientra nell'intervallo [min, max], quindi presumibilmente no. –

risposta

9

Consideriamo ciò che genera std::uniform_real_distribution.

produce valori in virgola mobile casuali i, distribuiti uniformemente sull'intervallo [a, b)

Così, che è tra std::numeric_limits<foat>::min() e std::numeric_limits<float>::max(), tra cui l'ex, ma escludendo quest'ultimo. Quali valori restituiscono quei limiti? Restituiscono rispettivamente FLT_MIN e FLT_MAX. Bene, quali sono quelli?

minimo normalizzato positivo virgola mobile numero

virgola mobile finito rappresentabile massimo numero

Poiché né {positivo, negativo} infinito, né NaN è compreso nell'intervallo di numeri finiti , no non sono generati.

Come sottolineato da Christopher Oicles, attenzione che FLT_MIN e, per estensione, std::numeric_limits<foat>::min() è il più piccolo positiva valore rappresentabile.

Come indicate da Chris Dodd, se nell'intervallo [min, max) supera std::numeric_limits<float>::max(), allora si otterrebbe un comportamento indefinito e in tal caso qualsiasi uscita, tra cui generatrice infinito sarebbe possibile.

+1

Per i tipi a virgola mobile, 'std :: numeric_limits :: min()' è un valore positivo (il più piccolo valore positivo diverso da zero).E la differenza: 'std :: numeric_limits :: max() - std :: numeric_limits :: min()' di solito finisce uguale a 'std :: numeric_limits :: max()' (certamente non maggiore, in in ogni caso). Quindi non sono sicuro che Trevor lo sapesse o no, ma la sua scelta di gamma è riuscita a evitare un comportamento indefinito dalla distribuzione. –

+0

@ChristopherOicles buon punto, non me ne ero reso conto. L'ho incorporato nella mia risposta. – user2079303

6

In realtà, questo provoca un comportamento indefinito, a causa dei requisiti per std::uniform_real_distribution (sezione 26.5.8.2.2 del progetto di specifiche che ho):

explicit uniform_real_distribution(RealType a = 0.0, RealType b = 1.0); 
    Requires: a ≤ b and b − a ≤ numeric_limits<RealType>::max(). 
    Effects: Constructs a uniform_real_distribution object; a and b correspond to 
      the respective parameters of the distribution. 

tuo esempio specifico traboccherà che numeric_limits requisito.

Ora è potrebbe costruire una std::uniform_real_distribution<double> con std::numeric_limits<float>::min/max come i limiti, e che dovrebbe essere ben definita. È anche probabile che il tuo esempio funzioni sulla maggior parte delle implementazioni (dato che generalmente promuovono i float ai raddoppiati nei calcoli interni), ma sta comunque raggiungendo un comportamento indefinito.

Nelle implementazioni in cui non funziona, suppongo che la modalità di errore più probabile stia generando Inf, poiché questo è ciò che verrà generato da b-a.