Wie initialisiere ich einen Float auf seinen Max / Min-Wert?

100

Wie kann ich einen absoluten Maximal- oder Minimalwert für einen Float oder Double fest codieren? Ich möchte das Maximum / Min eines Arrays ermitteln, indem ich einfach das größte Array durchlaufe und abfange.

Es gibt auch positive und negative Unendlichkeiten für Schwimmer. Soll ich diese stattdessen verwenden? Wenn ja, wie bezeichne ich das in meinem Code?

Gefälscht
quelle

Antworten:

151

Sie können std::numeric_limitsden in definierten <limits>Wert verwenden, um den minimalen oder maximalen Wert von Typen zu ermitteln (sofern für den Typ eine Spezialisierung vorhanden ist). Sie können es auch verwenden, um die Unendlichkeit abzurufen (und ein -Vorzeichen für die negative Unendlichkeit zu setzen).

#include <limits>

//...

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

Wie in den Kommentaren angegeben, wird min()der niedrigstmögliche positive Wert zurückgegeben. Mit anderen Worten, der positive Wert, der 0 am nächsten kommt und dargestellt werden kann. Der niedrigstmögliche Wert ist das Negativ des maximal möglichen Werts.

Es gibt natürlich die std::max_elementFunktionen und min_element (definiert in <algorithm>), die eine bessere Wahl sein können, um den größten oder kleinsten Wert in einem Array zu finden.

Yacoby
quelle
Wie verwende ich das genau? Was muss ich einschließen? Ich glaube nicht, dass ich so etwas schon einmal benutzt habe.
Gefälschte
Hmm ... diese Max-Element-Funktion wäre sehr nützlich gewesen ... das passiert, wenn Sie das Codieren selbst und nicht formal lernen. Am Ende erfinden Sie das Rad 50 Mal neu. Dies ist genau wie das letzte Mal, dass ich von Ceil () erfahren habe. Danke dir.
Gefälschte
18
@Yacoby, Sie möchten vielleicht klarstellen, dass numeric_limits <float> :: min () nicht den negativsten Wert bedeutet, sondern den kleinsten positiven Wert.
MSN
13
@killogre: C ++ 11 hinzugefügt numeric_limits<T>::lowest(), wodurch der niedrigste (negative) Wert zurückgegeben wird, der für den Typ zur Lösung dieses Problems möglich ist.
Cornstalks
3
std::numeric_limits<float>::min()gibt nicht den kleinsten positiven Wert an, der dargestellt werden kann; Es gibt die kleinste normale Gleitkommazahl mit einfacher Genauigkeit. Es gibt auch subnormale Zahlen zwischen Null und dieser Zahl. Insbesondere std::numeric_limits<float>::min()gibt es 1.17549e-38aber den kleinsten darstellbaren subnormalen Float nextafterf(0.0f, 1.0f) == 1.4013e-45f.
Nibot
45

Sie können entweder -FLT_MAX(oder -DBL_MAX) für die negative Zahl mit maximaler Größe und FLT_MAX(oder DBL_MAX) für positiv verwenden. Dies gibt Ihnen den Bereich möglicher Float- (oder Double-) Werte.

Sie möchten wahrscheinlich nicht verwenden FLT_MIN; Sie entspricht der kleinsten positiven Zahl, die mit einem Float dargestellt werden kann, nicht dem negativsten Wert, der mit einem Float dargestellt werden kann.

FLT_MINund FLT_MAXentsprechen std::numeric_limits<float>::min()und std::numeric_limits<float>::max().

MSN
quelle
Ich denke, ich werde diese Version tatsächlich verwenden, sie ist einfacher zu merken und macht mir mehr Szene. Ganzzahlen, die ich nur mit Hexadezimalzahl initialisieren kann. Die beste Antwort bleibt jedoch bestehen, da ich durch diese Antwort auch einige neue äußerst nützliche Funktionen kennengelernt habe.
Gefälschte
2
"[ FLT_MIN] entspricht der kleinsten positiven Zahl, die mit einem Float dargestellt werden kann" - Dies ist nicht wahr . Es ist die kleinste normale Zahl. Es gibt auch subnormale Zahlen.
Nibot
Sie wollen FLT_TRUE_MINfür den tatsächlich kleinstmöglichen Schwimmer, der entsprichtstd::numeric_limits<float>::denorm_min()
Chris Dodd
17

Es ist nicht wirklich erforderlich, auf möglichst klein / groß zu initialisieren, um das kleinste / größte im Array zu finden:

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

Oder wenn Sie es mehr als einmal tun:

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

Der Nachteil der Bereitstellung von Beispielcode - ich sehe, dass andere bereits die gleiche Idee vorgeschlagen haben.

Beachten Sie, dass der Standard zwar ein min_element und ein max_element enthält, für deren Verwendung jedoch ein zweimaliges Durchsuchen der Daten erforderlich ist. Dies kann ein Problem sein, wenn das Array überhaupt groß ist. Neuere Standards haben dies durch Hinzufügen eines a behoben std::minmax_element, das dasselbe wie find_extremaoben tut (finden Sie sowohl die minimalen als auch die maximalen Elemente in einer Sammlung in einem einzigen Durchgang).

Bearbeiten: Behebung des Problems, den kleinsten Wert ungleich Null in einem Array von vorzeichenlosen Werten zu finden: Beachten Sie, dass vorzeichenlose Werte "umlaufen", wenn sie ein Extrem erreichen. Um den kleinsten Wert ungleich Null zu finden, können wir für den Vergleich jeweils einen subtrahieren. Alle Nullwerte werden auf den größtmöglichen Wert für den Typ "umgebrochen", aber die Beziehung zwischen anderen Werten bleibt erhalten. Nachdem wir fertig sind, fügen wir dem gefundenen Wert offensichtlich einen hinzu.

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

Beachten Sie, dass hierfür immer noch das erste Element für den Anfangswert verwendet wird, wir jedoch keinen "Sonderfall" -Code benötigen. Da dieser Wert auf den größtmöglichen Wert umgebrochen wird, wird jeder Wert ungleich Null als kleiner verglichen. Das Ergebnis ist der kleinste Wert ungleich Null oder genau dann 0, wenn der Vektor keine Werte ungleich Null enthält.

Jerry Sarg
quelle
Aber du bekommst eine +1 dafür von mir!
Dan Diplo
1
Ich initialisiere auf max min, weil ich manchmal den kleinsten Wert ungleich Null möchte (in einem vorzeichenlosen ganzzahligen Fall haben meine Daten beispielsweise viele uninteressante Nullen). Es erscheint mir nur sinnvoll, es zu initialisieren, anstatt zusätzliche Prüfungen durchzuführen, um sicherzustellen, dass das erste Element nicht Null ist.
Gefälschte
@Faken: Selbst dann können Sie eine Vergleichsfunktion definieren, die Null als den größtmöglichen Wert behandelt, so dass Sie weiterhin verwenden können 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 fügt minmax_element hinzu, um das von Ihnen erwähnte Problem zu beheben. (Aber dann wird es nicht möglich sein, Nullen zu ignorieren ...)
UncleBens
1
Was ist, wenn das erste Element zum Zeitpunkt der Initialisierung nicht verfügbar ist? Dies passiert viel in der Online-Verarbeitung (wie in Boost :: Akkumulatoren)
Killogre
5

Um das Minimum eines Arrays manuell zu ermitteln, müssen Sie den Mindestwert von float nicht kennen:

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

Und ähnlicher Code für den Maximalwert.

Rechnung
quelle
4

Darf ich vorschlagen, dass Sie Ihre Variablen "max und min bisher" nicht auf unendlich, sondern auf die erste Zahl im Array initialisieren?

Thomas Padron-McCarthy
quelle