Ich möchte direkt den Mindestwert von berechnen float
Typ, und hier ist mein Algorithmus (Angenommen, die Codierung der Gleitkommazahl entspricht dem IEEE 754-Standard):
#include <math.h>
#include <limits.h>
#include <float.h>
#include <stdio.h>
float float_min()
{
int exp_bit = CHAR_BIT * sizeof(float) - FLT_MANT_DIG;
float exp = 2 - pow(2, exp_bit - 1);
float m = pow(2, -(FLT_MANT_DIG - 1));
return m * pow(2, exp);
}
int main()
{
printf("%g\n", float_min());
}
Die Ausgabe ist 1.4013e-45
. Allerdings finde ich das den Wert von FLT_MIN
in dem C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\float.h
ist 1.175494351e-38F
. Wer ist falsch?
Obwohl diese Frage schon mehrmals gestellt und beantwortet wurde, sehe ich keine Antwort, die wirklich richtig ist. Der Schlüssel ist das FLT_MIN
ist am kleinsten normalisiert darstellbarer Wert. Früher war das alles, was zählte. Dann kam Intel und stellte es vor unternormal Werte, die die Genauigkeit reduzieren, um Werte näher an 0 darzustellen. Subnormale sind Werte mit dem minimalen Exponenten und einem Bruchteil, dessen hohe Bits alle Nullen sind. Daraus folgt, dass der kleinste subnormale Wert ungleich Null einen Bruchteil hat, der alle aus Nullen besteht, mit Ausnahme des niedrigsten Bits, das eine 1 ist. Das ist der kleinste Wert, der dargestellt werden kann, aber wenn Sie dort unten sind, ändern Sie sich hier ein wenig und da macht a groß Wertänderung, daher müssen diese Dinge mit großer Sorgfalt verwendet werden.
EDIT, um “Normalisierung” zu verdeutlichen:
Angenommen, wir schreiben Dezimalwerte: 6,02 x 10 ^ 23, 0,602 * 10 ^ 24, 60,2 * 10 ^ 22. Diese stellen alle den gleichen Wert dar, sehen aber deutlich unterschiedlich aus. Führen wir also eine Regel zum Schreiben von Dezimalwerten ein: Jeder Wert muss links vom Dezimalkomma genau eine Nicht-Null-Stelle haben. Die „normalisierte“ Form dieses Werts ist also 6,02 x 10 ^ 23, und wenn wir einen Wert in einer nicht normalisierten Form haben, können wir das Dezimalkomma verschieben und den Exponenten anpassen, um den Wert beizubehalten, und ihn in normalisierte Form bringen.
IEEE-Gleitkomma macht dasselbe: Die Regel lautet, dass das hohe Bit des Bruchs immer 1 sein muss, und jede Berechnung muss den Bruch und den Exponenten ihres Ergebnisses anpassen, um diese Regel zu erfüllen.
Wenn wir Dezimalwerte schreiben, die wirklich nahe bei 0 liegen, ist das kein Problem: Wir können den Exponenten so klein wie nötig machen, sodass wir Zahlen wie 6,02*10^-16384 schreiben können. Mit Fließkommawerten können wir das nicht: Es gibt einen minimalen Exponenten, den wir nicht unterschreiten können. Um kleinere Werte zuzulassen, besagen die IEEE-Anforderungen, dass, wenn der Exponent der kleinste darstellbare Wert ist, der Bruch nicht normalisiert werden muss, das heißt, er muss keine 1 in seinem hohen Bit haben. Beim Schreiben von Dezimalwerten ist das so, als würde man sagen, dass wir eine 0 links vom Dezimalpunkt haben können. Wenn also unsere Dezimalregel besagt, dass der niedrigste zulässige Exponent -100 ist, wäre der kleinste normalisierte Wert 1,00 x 10^-100, aber kleinere Werte könnten als nicht normalisiert dargestellt werden: 0,10*10^-100, 0,01*10^- 100 usw.
Fügen Sie nun eine Anforderung zu unseren Dezimalregeln hinzu, dass wir nur drei Ziffern haben können: eine links vom Dezimalkomma und zwei rechts. Das ist wie der Gleitkommabruch, da er eine feste Anzahl von Ziffern hat. Für kleine Normalwerte haben wir also drei Ziffern, mit denen wir spielen können: 1,23*10^-100. Für kleinere Werte verwenden wir führende Nullen und die verblieben Ziffern haben weniger Genauigkeit: 0,12*10^-100 hat zwei Ziffern und 0,01*10^-100 hat nur 1. So funktionieren auch Gleitkomma-Subnormale: Sie erhalten immer weniger signifikante Bits, je weiter Sie unter die kommen minimaler normalisierter Wert, bis Ihnen die Bits ausgehen und Sie 0 erhalten.
BEARBEITEN: Um die Terminologie zu verdeutlichen, bezeichnet der IEEE-754-Standard diejenigen Werte, die größer als 0 und kleiner als der normalisierte Mindestwert sind Denormale; die neueste Revision von IEEE-754 bezeichnet sie als Subnormale. Sie meinen dasselbe.
Dein Ergebnis 1.4013e-45
ist ein denormaler minimaler positiver Gleitkommawert, auch bekannt als FLT_TRUE_MIN
was gleich ist 1.401298464e-45F
.
FLT_MIN
ist normalisierter minimaler positiver Gleitkommawert (1.175494351e-38F
)
Haben Sie den Code schrittweise durchlaufen, um zu überprüfen, ob die Werte aller Zwischenvariablen Ihren Vorstellungen entsprechen? Und dass die endgültige Berechnung in der
return
-Anweisung trägt nicht zu den Rundungsproblemen bei? Oder dass die Umstellung auf adouble
für dieprintf
anrufen ist kein problem?– Irgendein Programmierer-Typ
15. August 2017 um 12:30 Uhr
Ihr Code gibt 0 für mich zurück: ideone.com/94xHPT
– zwischenjay
15. August 2017 um 12:32 Uhr
@interjay Versuchen Sie, signifikantere Zahlen hinzuzufügen, wie z
%.50f
.– Josef Thomson
15. August 2017 um 12:33 Uhr
Informieren Sie sich auch über denormale/subnormale Gleitkommazahlen.
– Gen
15. August 2017 um 12:34 Uhr
Sie können den Code bearbeiten. Und bitte posten Sie keinen Code, den Sie nicht getestet haben.
– zwischenjay
15. August 2017 um 12:35 Uhr