come faccio a inizializzare un float al suo valore max / min?


100

Come faccio a codificare un valore massimo o minimo assoluto per un float o un doppio? Voglio cercare il massimo / minimo di un array semplicemente iterando e catturando il più grande.

Esistono anche infiniti positivi e negativi per i float, dovrei usare quelli invece? In tal caso, come lo denoto nel mio codice?

Risposte:


152

È possibile utilizzare std::numeric_limitsquale è definito in <limits>per trovare il valore minimo o massimo dei tipi (purché esista una specializzazione per il tipo). Puoi anche usarlo per recuperare l'infinito (e mettere un -davanti per l'infinito negativo).

#include <limits>

//...

std::numeric_limits<float>::max();
std::numeric_limits<float>::min();
std::numeric_limits<float>::infinity();

Come indicato nei commenti, min()restituisce il valore positivo più basso possibile. In altre parole il valore positivo più vicino a 0 che può essere rappresentato. Il valore più basso possibile è il negativo del valore massimo possibile.

Ci sono ovviamente le std::max_elementfunzioni e min_element (definite in <algorithm>) che possono essere una scelta migliore per trovare il valore più grande o più piccolo in un array.


Come lo uso esattamente? Cosa devo includere? Non credo di aver usato qualcosa di simile prima.
Faken

Hmm ... quella funzione max element sarebbe stata molto utile ... questo è quello che succede quando impari a programmare da solo e non formalmente. Finisci per reinventare la ruota 50 volte. Questa è proprio come l'ultima volta che ho imparato a conoscere ceil (). Grazie.
Faken

18
@Yacoby, potresti voler chiarire che numeric_limits <float> :: min () non significa il valore più negativo, significa il più piccolo positivo.
MSN

13
@killogre: aggiunto C ++ 11 numeric_limits<T>::lowest(), che restituisce il valore (negativo) più basso possibile per il tipo per risolvere questo problema.
Steli di mais

3
std::numeric_limits<float>::min()non non dare il valore positivo più piccolo che può essere rappresentato; fornisce il più piccolo numero in virgola mobile a precisione singola normale . Ci sono anche numeri subnormali tra zero e questo numero. In particolare, std::numeric_limits<float>::min()1.17549e-38ma il più piccolo float subnormale rappresentabile è nextafterf(0.0f, 1.0f) == 1.4013e-45f.
nibot

45

È possibile utilizzare -FLT_MAX(o -DBL_MAX) per il numero negativo di magnitudine massima e FLT_MAX(oDBL_MAX ) per positivo. Questo ti dà la gamma di possibili valori float (o double).

Probabilmente non vuoi usare FLT_MIN; corrisponde al numero positivo di magnitudo più piccolo che può essere rappresentato con un float, non al valore più negativo rappresentabile con un float.

FLT_MINe FLT_MAXcorrispondono a std::numeric_limits<float>::min()e std::numeric_limits<float>::max().


Penso che userò questa versione in realtà, è più semplice da ricordare e fa più scena per me. I numeri interi che posso inizializzare usando solo esadecimali. Tuttavia, la risposta migliore rimane ancora perché la risposta mi ha anche introdotto ad alcune nuove funzioni estremamente utili.
Faken

2
"[ FLT_MIN] corrisponde al numero positivo di magnitudo più piccolo che può essere rappresentato con un float" - Questo non è vero . È il numero normale più piccolo . Ci sono anche numeri subnormali.
nibot

Vuoi FLT_TRUE_MINil flottante più piccolo possibile, che corrisponde astd::numeric_limits<float>::denorm_min()
Chris Dodd,

17

Non è necessario inizializzare al più piccolo / più grande possibile per trovare il più piccolo / più grande nell'array:

double largest = smallest = array[0];
for (int i=1; i<array_size; i++) {
    if (array[i] < smallest)
        smallest = array[i];
    if (array[i] > largest0
        largest= array[i];
}

Oppure, se lo fai più di una volta:

#include <utility>

template <class iter>
std::pair<typename iter::value_type, typename iter::value_type> find_extrema(iter begin, iter end) {
    std::pair<typename iter::value_type, typename iter::value_type> ret;
    ret.first = ret.second = *begin;
    while (++begin != end) {
        if (*begin < ret.first)
           ret.first = *begin;
        if (*begin > ret.second)
           ret.second = *begin;
   }
   return ret;
}

Lo svantaggio di fornire un codice di esempio: vedo che altri hanno già suggerito la stessa idea.

Si noti che mentre lo standard ha un elemento min_element e un elemento max, il loro utilizzo richiederebbe la scansione dei dati due volte, il che potrebbe essere un problema se l'array è di grandi dimensioni. Gli standard recenti hanno affrontato questo problema aggiungendo un std::minmax_element, che fa lo stesso delfind_extrema sopra (trova sia gli elementi minimi che quelli massimi in una raccolta in un unico passaggio).

Modifica: risolvere il problema di trovare il valore diverso da zero più piccolo in un array di unsigned: osserva che i valori senza segno "si avvolgono" quando raggiungono un estremo. Per trovare il valore più piccolo diverso da zero, possiamo sottrarre uno da ciascuno per il confronto. Qualsiasi valore zero verrà "spostato" attorno al valore più grande possibile per il tipo, ma verrà mantenuta la relazione tra gli altri valori. Dopo aver finito, ovviamente ne aggiungiamo uno di nuovo al valore che abbiamo trovato.

unsigned int min_nonzero(std::vector<unsigned int> const &values) { 
    if (vector.size() == 0)
        return 0;
    unsigned int temp = values[0]-1;
    for (int i=1; i<values.size(); i++)
        if (values[i]-1 < temp)
            temp = values[i]-1;
    return temp+1;
}

Nota che questo utilizza ancora il primo elemento per il valore iniziale, ma non abbiamo ancora bisogno di alcun codice "caso speciale" - poiché questo andrà a capo al valore più grande possibile, qualsiasi valore diverso da zero verrà confrontato come più piccolo. Il risultato sarà il valore diverso da zero più piccolo o 0 se e solo se il vettore non conteneva valori diversi da zero.


Ma tu ottieni un +1 da me!
Dan Diplo

1
Inizializzo a max mins perché a volte voglio il valore più piccolo diverso da zero (in un caso intero senza segno, ad esempio, i miei dati tendono ad avere molti zeri non interessanti). Mi sembra che abbia senso inizializzarlo piuttosto che preformare controlli aggiuntivi per garantire che il primo elemento non sia zero.
Faken

@Faken: anche in questo caso puoi definire una funzione di confronto che tratti lo zero come il valore più grande possibile, quindi puoi ancora usare std::min_element:bool less_ignoring_zero(unsigned a, unsigned b) { if (a == 0) return false; if (b == 0) return true; return a < b; }
UncleBens

2
@ Jerry: C ++ 0x aggiungerà minmax_element per risolvere il problema menzionato. (Ma poi non sarà possibile ignorare gli zeri ...)
UncleBens

1
Cosa succede se il primo elemento non è disponibile al momento dell'inizializzazione? Questo accade
spesso

5

Per trovare manualmente il minimo di un array non è necessario conoscere il valore minimo di float:

float myFloats[];
...
float minimum = myFloats[0];
for (int i = 0; i < myFloatsSize; ++i)
{
  if (myFloats[i] < minimum)
  {
    minimum = myFloats[i];
  }
}

E codice simile per il valore massimo.


4

Posso suggerire di inizializzare le variabili "max e min finora" non all'infinito, ma al primo numero dell'array?

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.