2009-04-29 8 views
12

I tratti numeric_limits si suppone che sia un modo generale di ottenere vari tipi infomation, per essere in grado di fare cose comeCome risolvere il problema della definizione incoerente di numeric_limits <T> :: min()?

template<typename T> 
T min(const std::vector<T>& vect) 
{ 
    T val = std::numeric_limits<T>::min(); 

    for(int i=0 ; i<vect.size() ; i++) 
     val = max(T, vect[i]); 

    return val; 
} 

Il problema è che (almeno con MS Visual Studio 2008) numerici _ limiti <int> :: min() restituisce il numero negativo più piccolo, mentre i numeri numerici _ limiti <doppio> :: min() restituisce il numero più piccolo positivo!

Qualcuno conosce la razionalità dietro questo progetto? Esiste un modo migliore (consigliato?) Di utilizzare i limiti numerici _? Nella mia specifica funzione di cui sopra, ho potuto ovviamente inizializzare T per VECT [0], ma che non è la risposta sto cercando ..

Vedi anche (floating-point-specifico) discussione here

+0

Ci sono due errori nel tuo esempio. 1. La funzione deve essere chiamata max(), poiché calcola l'elemento massimo. 2. la riga "val = max (T, vect [i])" deve essere "val = max (val, vect [i])". – TonJ

risposta

1

una soluzione sarebbe

double val = -std::numeric_limits<double>::max(); 

Naturalmente, questo non spiega lo strano comportamento di numerics_limits :: min(), che potrebbe essere il risultato del fatto che ci sono diversi min/max confini per gli interi (min = -2^n, max = 2^n-1) ma non per i doppi.

+0

È std :: numeric_limits :: max() == -std :: numeric_limits :: min()? –

+0

Io non la penso così - come ho scritto, penso che min = -2^31, max = 2^31-1 per i tipi di dati a 32-bit, per esempio. Questo rappresenta il più alto valore negativo/positivo int - gcc conferma questo: "min: -2147483648, max: 2147483647" – schnaader

+0

Questo è il punto che sto cercando di fare. Il tuo codice è SBAGLIATO. –

9

È possibile utilizzare le librerie Boost. La libreria Conversioni numeriche fornisce una classe denominata limiti che può essere utilizzata in modo coerente.

Vedere la documentazione here.

4

Il comportamento di min() non è poi così strano, restituisce FLT_MIN, DBL_MIN o INT_MIN (oi rispettivi valori), a seconda del tipo con cui si è specializzati. Quindi la tua domanda dovrebbe essere il motivo per cui FLT_MIN e DBL_MIN sono definiti in modo diverso da INT_MIN.

Purtroppo, non conosco la risposta a quest'ultima domanda.

Il mio sospetto è che sia stato definito così per scopi pratici. Per i numeri interi, di solito sei interessato a overflow/underflow, in cui il valore minimo e massimo diventano di interesse.

Per i numeri in virgola mobile, esiste un diverso tipo di underflow in quanto un calcolo potrebbe risultare in un valore maggiore di zero, ma minore del più piccolo decimale rappresentabile per quel tipo di virgola mobile. Sapendo che il più piccolo valore in virgola mobile rappresentabile ti consente di aggirare il problema. Vedi anche l'articolo di Wikipedia sui numeri subnormal/denormal.

1

La definizione del valore più piccolo per un vettore vuoto può essere discussa. Se il vettore è vuoto, non esiste un elemento più piccolo.

preferisce utilizzare std::min_element invece:

int main() 
{ 
    std::vector<int> v; 
    std::generate_n(std::back_inserter(v), 1000, std::rand); 

    std::vector<int>::iterator it = std::min_element(v.begin(), v.end()); 
    if (it == v.end()) 
    { 
     std::cout << "There is no smallest element" << std::endl; 
    } 
    else 
    { 
     std::cout << "The smallest element is " << *it << std::endl; 
    } 
} 
1

Non sono sicuro delle motivazioni, ma si prevede un comportamento. Bene, nel senso che è così che Josuttis (e presumibilmente lo standard) lo descrive!

min(): "miniumum valore finito (minimo valore normalizzato per virgola mobile tipi con denormalizzazione)."

come meglio posso dire se il tipo è non un numero intero (numeric_limits<>::is_integer) e ha denormalizzazione (numeric_limits<>::has_denorm) min() restituirà il più piccolo valore rappresentabile da quel tipo. Altrimenti restituirà il valore più piccolo - che potrebbe essere negativo.

Per un'interfaccia più coerente, consultare la libreria Boost numeric/conversion. Specificamente lo bounds traits class. Ecco un frammento:

cout << "lowest float:" << boost::numeric::bounds<float>::lowest(); 
cout << "lowest int: " << boost::numeric::bounds<int>::lowest(); 

È inoltre possibile trovare il boost::integer library utile. Porta un po 'del supporto intero di C99 (come int_least16_t) a C++ e può aiutare a selezionare il tipo di dimensione migliore per la tua particolare necessità. Un esempio:

boost::uint_t<20>::fast fastest20bits; // fastest unsigned integer that 
             // can hold at least 20 bits. 
boost::int_max_value_t<100000>::least // smallest integer that can store 
             // the value 100000. 

Spesso trovo che quando ho bisogno di uno di boost :: numerico/conversione o boost :: intero ho tutti e due bisogno.

1

numeric_limits<int>::min restituito il numero negativo disponibilità, ogni numero in virgola mobile, restituire il numero positivo piccolo quando ho provato con Sun CC & g ++.

Immagino che questo sia perché "minimo" e "minimo" significano cose diverse con numeri in virgola mobile. È un po 'strano però.

Sia Sun CC e g ++ producono lo stesso risultato:

breve: min: -32768 max: 32767

int: min: -2147483648 max: 2147483647

unsigned int: min : 0 max: 4294967295

lungo: min: -2147483648 max: 2147483647

float: min: 1.17549e-38 ma x: 3.40282e + 38

doppia: min: 2.22507e-308 max: 1.79769e + 308

lungo doppio: min: 3.3621e-4932 max: 1.18973e + 4932

unsigned short: min: 0 max: 65535

unsigned int: min: 0 max: 4294967295

unsigned long: min: 0 max: 429496729

template<typename T> 
void showMinMax() 
{ 
    cout << "min: " << numeric_limits<T>::min() << endl; 
    cout << "max: " << numeric_limits<T>::max() << endl; 
    cout << endl; 
} 

int main() 
{ 
cout << "short:"; 
showMinMax<short>() 
...etc...etc.. 
+1

Strange, numeric_limits :: min restituisce qui un numero molto piccolo positivo (g ++ 3.4. 5). Forse dipende dalla versione/OS/implementazione – schnaader

5

Questa è una discussione precedente, ma c'è una risposta aggiornata:

C++ 11 ha aggiunto una funzione lowest() a std::numeric_limits (See here)

Così ora è possibile chiamare std::numeric_limits<double>::lowest() per ottenere il valore negativo più basso rappresentabile.

Problemi correlati