minimaler doppelter Wert in C / C ++

90

Gibt es eine Standard- und / oder tragbare Methode, um den kleinsten negativen Wert (z. B. negative Unendlichkeit) in einem C (++) -Programm darzustellen?

DBL_MIN in float.h ist die kleinste positive Zahl.

Wille
quelle
4
Ich werde mich für -DBL_MAX entscheiden, aber ich bin mir sicher, dass es einen technischen Grund gibt, warum dies nicht so ist :-)
4
@Neil, nein, gibt es nicht, es ist nicht wie 2 Komplement-Ganzzahlen
fortran
Ich habe noch nichts im Standard gesehen, was besagt, dass der Bereich der Gleitkommatypen um Null symmetrisch sein muss. Die Konstanten in limit.h und <limits> deuten jedoch darauf hin, dass sowohl der C- als auch der C ++ - Standard dies erwarten.
Steve Jessop
4
Tatsächlich ist DBL_MIN in float.h die kleinste positive normalisierte Zahl. Es gibt Zahlen, die noch kleiner sind.
Fdermishin
1
@fortran: IEEE 754 FP verwendet ein Vorzeichenbit, und die meiste FP-Hardware ist heutzutage IEEE 754. Da C und C ++ jedoch Nicht-IEEE 754 FP-Hardware unterstützen, ist die Frage offen, ob die Sprache die Garantie für -DBL_MAX übernimmt muss gleich dem minimalen darstellbaren Wert sein.
j_random_hacker

Antworten:

132

-DBL_MAX in ANSI C , das in float.h definiert ist.

dfa
quelle
Dies scheint der Standard und tragbarste
Will
Hier ist die Erklärung für mein -1: Wer oder was sagt, dass -DBL_MAX durch die C- oder C ++ - Sprache als darstellbar garantiert wird, geschweige denn als minimal darstellbarer Wert? Die Tatsache, dass die meisten FP-Hardware IEEE 754-konform ist und diese Darstellung verwendet, bedeutet nicht, dass -DBL_MAX garantiert auf jeder standardkonformen C-Plattform funktioniert.
j_random_hacker
@j_random_hacker: siehe fortrans Antwort 'unten'.
JohnTortugo
3
@j_random_hacker Das ist ein sehr guter Punkt, aber der C-Standard muss -DBL_MAXgenau darstellbar sein. Wenn die FP-Hardware dazu nicht in der Lage ist, muss die Implementierung ihn nur umgehen . Siehe das Gleitkommamodell in 5.2.4.2.2 Eigenschaften der Gleitkommatypen <float.h> p2 von C99 (möglicherweise seitdem an einen anderen Ort verschoben).
2
@j_random_hacker Ja, aber p2 gibt an, dass e_min und e_max unabhängig vom Vorzeichenbit sind, also DBL_MAXgenau (1 - b ^ - p) b ^ e_max, was genau darstellbar ist, der negativste endliche Wert ist genau - (1 - b ^ −p) b ^ e_max, und da dies genau der Fall ist -DBL_MAX, DBL_MAXkann das Negieren auch keine Rundungsfehler verursachen.
70

Gleitkommazahlen (IEEE 754) sind symmetrisch. Wenn Sie also den größten Wert ( DBL_MAXoder numeric_limits<double>::max()) darstellen können, stellen Sie einfach ein Minuszeichen voran.

Und dann ist der coole Weg:

double f;
(*((long long*)&f))= ~(1LL<<52);
fortran
quelle
6
+1 Für den Hinweis auf die Symmetrie von Gleitkommazahlen :)
Andrew Hare
4
Was ist mit C / C ++ - Implementierungen, die keine IEEE 754-Floats verwenden?
Steve Jessop
1
Das Handbuch von gcc für -ffast-math lautet: "Setzt -fno-math-errno, -funsafe-math-Optimierungen, -ffinite-math-only, -fno-rounding-math, -fno-signaling-nans und -fcx-limited- Bereich Diese Option wird von keiner -O-Option aktiviert, da sie zu einer falschen Ausgabe für Programme führen kann, die von einer genauen Implementierung der IEEE- oder ISO-Regeln / Spezifikationen für mathematische Funktionen abhängen. Sie kann jedoch schnelleren Code für Programme liefern, die dies tun erfordern nicht die Garantien dieser Spezifikationen. " Schnelle Mathematik ist eine gängige Einstellung, und der Intel ICC verwendet sie beispielsweise standardmäßig. Alles in allem nicht sicher, was das für mich bedeutet :-)
Will
4
Dies bedeutet, dass Implementierungen keine IEEE 754-Arithmetik verwenden, aber um fair zu sein, verwenden diese Optionen immer noch die IEEE-Darstellung. Möglicherweise finden Sie einige Emulationsbibliotheken, die eine Nicht-IEEE-Darstellung verwenden, da nicht alle Prozessoren ein natives Float-Format haben (obwohl sie möglicherweise ein C ABI veröffentlichen, das ein Format enthält, das den vom Hersteller bereitgestellten Emulationsbibliotheken entspricht). Daher können nicht alle Compiler einen verwenden. Kommt nur darauf an, was du meinst, wenn du nach "Standard und / oder tragbar" fragst, es gibt im Prinzip tragbar und in der Praxis tragbar.
Steve Jessop
3
Was Sie sagen, gilt für IEEE 754, aber der Standard erfordert nicht die Verwendung dieser Codierung (wie @SteveJessop hervorhebt, ist Portable in der Praxis nicht dasselbe wie Portable im Prinzip).
Christophe
43

Verwenden Sie in C

#include <float.h>

const double lowest_double = -DBL_MAX;

Verwenden Sie in C ++ vor 11

#include <limits>

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

Verwenden Sie in C ++ 11 und höher

#include <limits>

constexpr double lowest_double = std::numeric_limits<double>::lowest();
rubenvb
quelle
War die min()Funktion vor C ++ 11 nicht verfügbar? Oder ist das ein anderer Wert als -max()? en.cppreference.com/w/cpp/types/numeric_limits
Alexis Wilke
5
@Alexis: Wenn Sie sich die drei niedrigsten Zeilen in der Tabelle auf der von Ihnen verlinkten Seite ansehen, werden Sie feststellen, dass minSie den kleinsten positiven Wert in der Größe und lowestden größten negativen Wert in der Größe erhalten. Ja, es ist schrecklich. Willkommen in der brillanten Welt der C ++ - Standardbibliothek :-P.
Rubenvb
für C ist es definiert in float.h. limits.hist für ganze Zahlen
Ciprian Tomoiagă
33

Versuche dies:

-1 * numeric_limits<double>::max()

Referenz: numeric_limits

Diese Klasse ist auf jeden der grundlegenden Typen spezialisiert, wobei ihre Mitglieder die verschiedenen Werte zurückgeben oder festlegen, die die Eigenschaften definieren, die der Typ in der spezifischen Plattform hat, auf der er kompiliert wird.

Andrew Hare
quelle
1
Warum nicht einfach -numeric_limits<double>::max()?
k06a
4
@ k06a Wenn die Negation durch ein einzelnes Zeichen in einem so langen Ausdruck dargestellt wird, in dem die Zeichenfolge sogar "max" sagt, wird sicher früher oder später jemand gefunden. Entweder wird es in einer beschreibenden Variablen gespeichert oder verwendet -1 * ..., um es etwas klarer zu machen.
Filip Haglund
20

Suchen Sie nach der tatsächlichen Unendlichkeit oder dem minimalen endlichen Wert? Wenn erstere, verwenden Sie

-numeric_limits<double>::infinity()

was nur funktioniert wenn

numeric_limits<double>::has_infinity

Andernfalls sollten Sie verwenden

numeric_limits<double>::lowest()

Das wurde in C ++ 11 eingeführt.

Wenn lowest()nicht verfügbar, können Sie auf zurückgreifen

-numeric_limits<double>::max()

was lowest()im Prinzip abweichen kann, in der Praxis aber normalerweise nicht.

Christoph
quelle
+1 für die Differenz zwischen endlichem und unendlichem Wert! Der Standard garantiert jedoch keine symetrische Gleitkomma-Codierung. Also -numeric_limits<double>::max()auch wenn es in der Praxis funktioniert , ist nicht vollständig tragbar in der Theorie.
Christophe
@Christophe: [x] behoben
Christoph
10

Eine wirklich tragbare C ++ - Lösung

Ab C ++ 11 können Sie verwenden numeric_limits<double>::lowest(). Gemäß dem Standard gibt es genau das zurück, wonach Sie suchen:

Ein endlicher Wert x, so dass es keinen anderen endlichen Wert y gibt y < x.
Sinnvoll für alle Spezialisierungen, in denen is_bounded != false.

Online-Demo


Viele nicht portable C ++ - Antworten hier!

Es gibt viele Antworten -std::numeric_limits<double>::max().

Glücklicherweise funktionieren sie in den meisten Fällen gut. Gleitkomma-Codierungsschemata zerlegen eine Zahl in einer Mantisse und einen Exponenten, und die meisten von ihnen (z. B. das beliebte IEEE-754 ) verwenden ein eindeutiges Vorzeichenbit, das nicht zur Mantisse gehört. Dies ermöglicht es, das größte Positiv in das kleinste Negativ umzuwandeln, indem Sie einfach das Vorzeichen umdrehen:

Geben Sie hier die Bildbeschreibung ein

Warum sind diese nicht tragbar?

Der Standard schreibt keinen Gleitkomma-Standard vor.

Ich stimme zu, dass mein Argument ein wenig theoretisch ist, aber nehmen wir an, dass ein exzentrischer Compilerhersteller ein revolutionäres Codierungsschema mit einer Mantisse verwenden würde, die in einigen Variationen des Zweierkomplements codiert ist . Die Zweierkomplementcodierung ist nicht symmetrisch. Beispielsweise ist für ein vorzeichenbehaftetes 8-Bit-Zeichen das maximale positive 127, das minimale negative -128. Wir könnten uns also vorstellen, dass einige Gleitkomma-Codierungen ein ähnliches asymmetrisches Verhalten zeigen.

Mir ist kein solches Codierungsschema bekannt, aber der Punkt ist, dass der Standard nicht garantiert, dass das Umdrehen der Vorzeichen das beabsichtigte Ergebnis liefert . Diese beliebte Antwort (sorry Leute!) Kann also nicht als vollständig tragbare Standardlösung angesehen werden! / * zumindest nicht, wenn du nicht behauptet hast, dass numeric_limits<double>::is_iec559das wahr ist * /

Christophe
quelle
1

Die ursprüngliche Frage betrifft die Unendlichkeit. Also, warum nicht verwenden

#define Infinity  ((double)(42 / 0.0))

nach der IEEE-Definition? Das können Sie natürlich negieren.

Norbert
quelle
Gute Idee ! Und es funktioniert . Aber nur wennnumeric_limits<double>::has_infinity && ! numeric_limits<double>::traps
Christophe
1

Gibt es eine Standard- und / oder tragbare Methode, um den kleinsten negativen Wert (z. B. negative Unendlichkeit) in einem C (++) -Programm darzustellen?

C-Ansatz.

Viele Implementierungen unterstützen +/- Unendlichkeiten, daher ist der negativste doubleWert -INFINITY.

#include <math.h>
double most_negative = -INFINITY;

Gibt es einen Standard- und / oder tragbaren Weg ....?

Jetzt müssen wir auch andere Fälle berücksichtigen:

  • Keine Unendlichkeiten

Einfach -DBL_MAX.

  • Nur eine unsignierte Unendlichkeit.

Ich würde in diesem Fall erwarten, OP würde es vorziehen -DBL_MAX.

  • De-normale Werte größer als DBL_MAX.

Dies ist ein ungewöhnlicher Fall, der wahrscheinlich außerhalb der Besorgnis von OP liegt. Wenn doublees als Paar von Gleitkommazahlen codiert wird , um den gewünschten Bereich / die gewünschte Präzession zu erreichen (siehe Doppel-Doppel ), gibt es eine maximale Normalen double und möglicherweise eine größere De-Normalen . Ich habe eine Debatte gesehen, wenn ich mich DBL_MAXauf die größte Normalität beziehen sollte, auf die größte von beiden.

Glücklicherweise enthält dieser gepaarte Ansatz normalerweise eine -Infinity, sodass der negativste Wert erhalten bleibt -INFINITY.


Für mehr Portabilität kann Code die Route entlang gehen

// HUGE_VAL is designed to be infinity or DBL_MAX (when infinites are not implemented)
// .. yet is problematic with unsigned infinity.
double most_negative1 = -HUGE_VAL;  

// Fairly portable, unless system does not understand "INF"
double most_negative2 = strtod("-INF", (char **) NULL);

// Pragmatic
double most_negative3 = strtod("-1.0e999999999", (char **) NULL);

// Somewhat time-consuming
double most_negative4 = pow(-DBL_MAX, 0xFFFF /* odd value */);

// My suggestion
double most_negative5 = (-DBL_MAX)*DBL_MAX;
chux - Monica wieder einsetzen
quelle
-1

Wenn Sie keine Float-Ausnahmen aktiviert haben (die Sie nicht imho sollten), können Sie einfach sagen:

double neg_inf = -1/0.0;

Dies ergibt eine negative Unendlichkeit. Wenn Sie einen Float benötigen, können Sie entweder das Ergebnis umwandeln

float neg_inf = (float)-1/0.0;

oder verwenden Sie eine Arithmetik mit einfacher Genauigkeit

float neg_inf = -1.0f/0.0f;

Das Ergebnis ist immer das gleiche, es gibt genau eine Darstellung der negativen Unendlichkeit in einfacher und doppelter Genauigkeit und sie konvertieren wie erwartet ineinander.

cmaster - Monica wieder einsetzen
quelle
Warum sollten Sie dies tun, anstatt nur zu schreiben-INFINITY
MM
Unendlichkeit kann auch existieren oder nicht, und wenn sie existiert, können Positiv und Negativ möglicherweise nicht unterschieden werden (in Standard C).
MM
In vielen Compilern und / oder Architekturen verlangsamt Ihr C / C ++ - Code viele von Ihnen, die Unendlichkeits- und NaN-Werte verbreiten.
Markgalassi
@markgalassi Bitte schauen Sie genauer hin: Sie werden feststellen, dass der Wertneg_inf auf einen konstanten Wert initialisiert ist . Der Compiler kümmert sich um die Berechnung des infWertes. Wenn Sie es als Nullwert für die Berechnung eines Maximums verwenden, wird es bei der ersten Iteration im Allgemeinen mit einem größeren Wert überschrieben. Dh die Leistung ist kaum ein Problem. Und das OP fragt speziell nach "zB negative Unendlichkeit verwenden" und -infist in der Tat die einzig richtige Antwort darauf. Sie haben eine korrekte und nützliche Antwort abgelehnt.
cmaster