Warum kann double größere Zahlen speichern als unsigned long long?

8

Die Frage ist, ich verstehe nicht recht, warum double größere Zahlen speichern kann als unsigned long long. Da beide 8 Bytes lang sind, also 64 Bits.

Wenn in unsigned long long alle 64 Bits verwendet werden, um einen Wert zu speichern, hat double andererseits 1 für das Vorzeichen, 11 für den Exponenten und 52 für die Mantisse. Selbst wenn 52 Bits, die für die Mantisse verwendet werden, verwendet werden, um Dezimalzahlen ohne Fließkomma zu speichern, hat es immer noch 63 Bits ...

ABER LLONG_MAX ist wesentlich kleiner als DBL_MAX ...

Warum?

    
denis631 05.05.2015, 12:16
quelle

6 Antworten

22

Der Grund ist, dass unsigned long long exakte ganze Zahlen speichert, während double eine Mantisse (mit einer begrenzten Genauigkeit von 52 Bit) und einen Exponenten speichert.

Dies erlaubt double , sehr große Zahlen zu speichern (ungefähr 10 308 ), aber nicht genau. Sie haben ungefähr 15 (fast 16) gültige Dezimalziffern in double , und der Rest der 308 möglichen Dezimalstellen sind Nullen (eigentlich undefiniert, aber Sie können zum besseren Verständnis "Null" annehmen).
Ein unsigned long long hat nur 19 Ziffern, aber jede einzelne davon ist genau definiert.

BEARBEITEN:
Als Antwort auf den folgenden Kommentar "Wie funktioniert das genau?" haben Sie 1 Bit für das Vorzeichen, 11 Bits für den Exponenten und 52 Bits für die Mantisse. Die Mantisse hat am Anfang ein implizites "1" -Bit, das nicht gespeichert wird, also effektiv Sie haben 53 Mantissen-Bits. 2 53 ist 9.007E15, also haben Sie 15, fast 16 Dezimalziffern, um damit zu arbeiten.
Der Exponent hat ein Vorzeichenbit und kann von -1022 bis +1023 reichen, was verwendet wird, um die Mantisse zu skalieren (binäre Verschiebung nach links oder rechts) (2 1023 ist ungefähr 10 307 , daher die Grenzen der Reichweite), also sehr kleine und sehr große Zahlen sind bei diesem Format gleichermaßen möglich.
Aber natürlich haben alle Zahlen, die Sie darstellen können, nur so viel Präzision, wie sie in die Matisse passen.

Alles in allem sind Fließkommazahlen nicht sehr intuitiv, da "einfache" Dezimalzahlen nicht unbedingt als Fließkommazahlen dargestellt werden können. Dies liegt an der Tatsache, dass die Mantisse binär ist. Zum Beispiel ist es möglich (und einfach), jede positive ganze Zahl bis zu einigen Milliarden oder Zahlen wie 0,5 oder 0,25 oder 0,0125 mit perfekter Genauigkeit darzustellen Andererseits ist es auch möglich, eine Zahl wie 10 <250> darzustellen, aber nur ungefähr. Tatsächlich werden Sie feststellen, dass 10 250 und 10 250 +1 die gleiche Anzahl sind (warte, was ???). Das liegt daran, dass, obwohl Sie leicht 250 Ziffern haben können, Sie nicht so viele signifikante Ziffern haben (lesen Sie "signifikant" als "bekannt" oder "definiert").
Auch etwas scheinbar Einfaches wie 0.3 ist auch nur annähernd möglich, obwohl 0.3 nicht einmal eine "große" Zahl ist. Sie können jedoch 0.3 nicht in Binärzahlen darstellen, und unabhängig davon, welchen binären Exponenten Sie daran anhängen, werden Sie keine Binärzahl finden, die genau 0,3 ergibt (aber Sie können sehr nahe kommen).

Einige "spezielle Werte" sind für "unendlich" (sowohl positiv als auch negativ) sowie "keine Zahl" reserviert, sodass Sie sehr wenig weniger als den theoretischen Gesamtbereich haben.

unsigned long long andererseits interpretiert das Bitmuster in keiner Weise. Alle Zahlen, die Sie darstellen können, sind einfach die exakte Zahl, die durch das Bitmuster dargestellt wird. Jede Ziffer einer jeden Zahl ist genau definiert, es findet keine Skalierung statt.

    
Damon 05.05.2015, 12:17
quelle
13

IEEE754 Gleitkommawerte können einen größeren Bereich von Zahlen speichern, weil sie Genauigkeit opfern.

Damit meine ich, dass ein 64-Bit-Integraltyp jeden einzelnen Wert in seinem Bereich darstellen kann, aber ein 64-Bit-Double nicht.

Wenn Sie beispielsweise versuchen, 0.1 in einem double zu speichern, wird <%> Sie % <%> geben, dann erhalten Sie etwas wie:

%Vor%

(das ist eigentlich der nächste einzelne Genauigkeitswert, aber derselbe Effekt gilt für doppelte Genauigkeit).

Aber wenn die Frage lautet: "Wie erhalten Sie einen größeren Bereich mit weniger Bits zur Verfügung?", Es ist einfach, dass einige dieser Bits verwendet werden, um den Wert zu skalieren.

Klassisches Beispiel, nehmen wir an, Sie haben vier Dezimalziffern, um einen Wert zu speichern. Mit einer Ganzzahl können Sie die Zahlen 0.1 bis 0000 inklusive darstellen. Die Präzision in diesem Bereich ist perfekt, Sie können jeden integralen Wert darstellen.

Lassen Sie uns jedoch einen Fließkommawert verwenden und die letzte Ziffer als Maßstab verwenden, so dass die Ziffern 9999 tatsächlich die Zahl 1234 darstellen.

So jetzt Ihr Bereich ist von 123 x 104 (dargestellt durch 0 bis 0000 ) bis 0009 (dargestellt durch 999,000,000,000 ist 9999 ).

Aber Sie können nicht jede Zahl innerhalb dieses Bereichs darstellen. Zum Beispiel, 999 x 109 kann nicht dargestellt werden, der Schrank, den du bekommen kannst, ist mit den Ziffern 123,456 , die dir 1233 geben. Und tatsächlich, wo die Integer-Werte eine Genauigkeit von vier Ziffern hatten, haben Sie jetzt nur noch drei.

Das ist im Grunde wie IEEE754 arbeitet, opfert Präzision für die Reichweite.

    
paxdiablo 05.05.2015 12:18
quelle
3

Haftungsausschluss

Dies ist ein Versuch, eine leicht verständliche Erklärung dafür zu liefern, wie die Fließkomma-Codierung funktioniert. Es ist eine Vereinfachung und deckt keine der technischen Aspekte des echten IEEE 754 Gleitkomma-Standards ab (Normalisierung, vorzeichenbehafteter Nullwert, Unendlichkeit, NaNs, Rundung usw.). Die hier vorgestellte Idee ist jedoch richtig.

Das Verständnis, wie die Gleitkommazahlen funktionieren, wird durch die Tatsache, dass Computer mit Zahlen in der Basis 2 arbeiten, stark behindert, während die Menschen sie nicht so einfach handhaben. Ich werde versuchen, zu erklären, wie die Gleitkommazahlen mit der Basis 10 funktionieren.

Lassen Sie uns eine Gleitkommazahlendarstellung mit Zeichen und Basis 10 Ziffern erstellen (d. h. die üblichen Ziffern von 0 bis 9 , die wir täglich verwenden).

Nehmen wir an, wir haben 10 -Zellen und jede Zelle kann entweder ein Vorzeichen ( + oder - ) oder eine Dezimalziffer ( 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 oder 9 ).

Wir können die 10 Ziffern verwenden, um vorzeichenbehaftete ganze Zahlen zu speichern. Eine Ziffer für das Zeichen und 9 Ziffern für den Wert:

%Vor%

So wird der Wert 1500 als Ganzzahl dargestellt.

Wir können sie auch verwenden, um Gleitkommazahlen zu speichern. Zum Beispiel 7 Ziffern für die Mantisse und 3 Ziffern für den Exponenten:

%Vor%

Dies ist eine der möglichen Darstellungen von 1500 als Fließkommawert (unter Verwendung unserer 10 Dezimalstellen).

Der Wert der Mantisse ( M ) ist +150 , der Wert des Exponenten ( E ) ist +1 . Der oben dargestellte Wert ist:

%Vor%

Die Bereiche

Die ganzzahlige Repräsentation kann signierte Werte zwischen -(10^9-1) ( -999,999,999 ) und +(10^9-1) ( +999,999,999 ) speichern. Mehr, es kann jeden einzelnen Integer-Wert zwischen diesen Grenzen darstellen. Darüber hinaus gibt es für jeden Wert eine einzige Repräsentation, die genau ist.

Die Gleitkommadarstellung kann signierte Werte für die Mantisse ( M ) zwischen -999,999 und +999,999 und für den Exponenten ( E ) zwischen -99 und +99 speichern.

Es kann Werte zwischen -999,999*10^99 und +999,999*10^99 speichern. Diese Zahlen haben 105 Ziffern, viel mehr als 9 Ziffern der größten Zahlen, die oben als Ganzzahlen dargestellt werden.

Das ist los von Präzision

Nehmen wir an, dass M das Vorzeichen und die ersten 6 Stellen des Wertes (oder weniger) für ganzzahlige Werte speichert und E die Anzahl der Stellen ist, die nicht in M passen.

%Vor%

Versuchen wir, V = +987,654,321 mit unserer Fließkomma-Codierung darzustellen.

Da M auf +999,999 beschränkt ist, kann nur +987,654 und E wird +3 gespeichert werden (die letzten 3 Ziffern von V können nicht in M passen).

Zusammenfügen:

%Vor%

Dies ist nicht unser ursprünglicher Wert von V , aber die beste Annäherung, die wir mit dieser Darstellung erhalten können.

Nehmen wir an, dass alle Zahlen zwischen (und einschließlich) +987,654,000 und +987,654,999 mit dem gleichen Wert ( M=+987,654, E=+3 ) approximiert werden. Es gibt auch keine Möglichkeit, Dezimalziffern für Zahlen größer als +999,999 zu speichern.

Bei Zahlen, die größer sind als der Maximalwert von M ( +999.999 ), erzeugt diese Methode für alle Werte zwischen +999,999*10^E und +999,999*10^(E+1)-1 (ganze oder reelle Werte) die gleiche Darstellung 't Materie).

Fazit

Bei großen Werten (größer als der Maximalwert von M ) weist die Gleitkommadarstellung Lücken zwischen den Zahlen auf, die dargestellt werden können. Diese Lücken werden größer und größer, je höher der Wert von E wird.

Die ganze Idee des "Gleitkommas" besteht darin, etwa ein Dutzend der repräsentativsten Ziffern (den Anfang der Zahl) und die Größe der Zahl zu speichern.

Nehmen wir die Lichtgeschwindigkeit als Beispiel. Sein Wert ist ungefähr 300,000 km/s . Da es so massiv ist, ist es für die meisten praktischen Zwecke egal, ob es 300,000.001 km/s oder 300,000.326 km/s ist.

  

Tatsächlich ist es nicht einmal so groß, eine bessere Annäherung ist 299.792,458 km / s.

Die Gleitpunktzahlen extrahieren die wichtigen Eigenschaften der Lichtgeschwindigkeit: ihre Größe beträgt Hunderttausende km / s ( E=5 ) und ihr Wert ist 3 (Hunderttausende km / s).

> %Vor%

Unsere Gleitkommadarstellung kann es annähern durch: 299,792 km/s ( M=299,792 , E=0 ).

    
axiac 05.05.2015 15:26
quelle
3
  

Welche Art von Magie passiert?

Die gleiche Art von Magie, mit der Sie die 101-stellige Zahl darstellen können

%Vor%

als

1.0 * 10100

Es ist nur statt der Basis 10, du machst es in der Basis 2:

0.57149369564113749110789177415267 * 2333 .

Mit dieser Notation können Sie sehr große (oder sehr kleine) Werte kompakt darstellen. Anstatt jede Ziffer zu speichern, speichern Sie den Signifikanten (a.k.a. die Mantisse oder den Bruch) und den Exponenten . Auf diese Weise können Zahlen, die Hunderte von Dezimalstellen lang sind, in einem Format dargestellt werden, das nur 64 Bits benötigt.

Es ist der Exponent, der Gleitkommazahlen erlaubt, einen so großen Bereich von Werten darzustellen. Der Exponentenwert 1024 benötigt nur 10 Bits zum Speichern, aber 21024 ist eine 308-stellige Zahl.

Der Nachteil ist, dass nicht jeder Wert genau dargestellt werden kann. Bei einer 64-Bit-Ganzzahl hat jeder Wert zwischen 0 und 264-1 (oder -263 bis 263-1 ) eine exakte Darstellung. Das gilt nicht für Gleitkommazahlen aus verschiedenen Gründen. Zuallererst haben Sie nur so viele Bits, die Ihnen nur so viele Stellen der Genauigkeit geben. Wenn Sie beispielsweise nur 3 signifikante Ziffern haben, können Sie keine Werte zwischen 0,123 und 0,124 oder 1,23 und 1,24 oder 123 und 124 oder 1230000 und 1240000 darstellen. Wenn Sie sich der Kante Ihres Bereichs nähern, wird die Lücke zwischen den darstellbaren Werten angezeigt wird größer.

Zweitens gibt es, genau wie es Werte gibt, die nicht in einer endlichen Anzahl von Stellen dargestellt werden können ( 3/10 gibt die nicht endende Sequenz 0.33333...10 ), Werte, die nicht in einer endlichen Anzahl von Bits dargestellt werden können ( 1/10 gibt die nicht-terminierende Sequenz 1.100110011001...2 ) an.

    
John Bode 05.05.2015 16:08
quelle
2

Vielleicht haben Sie das Gefühl, dass das Speichern einer Zahl in N Bits etwas Grundlegendes ist, obwohl es verschiedene Möglichkeiten gibt, dies zu tun. Tatsächlich ist es genauer zu sagen, dass wir eine Zahl in N Bits darstellen, da die Bedeutung davon abhängt, welche Konvention wir annehmen. Wir können im Prinzip jede Konvention annehmen, die wir für welche Zahlen verschiedene N-Bit-Muster darstellen. Es gibt die binäre Konvention, wie sie für unsigned long long und andere Integer-Typen verwendet wird, und die Mantisse + Exponenten Konvention wie für double , aber wir könnten auch eine (absurde) Konvention definieren, in der zum Beispiel Alle Bits Null bedeuten eine enorme Zahl, die Sie angeben möchten. In der Praxis verwenden wir normalerweise Konventionen, die es uns erlauben, Zahlen effizient zu kombinieren (addieren, multiplizieren usw.), indem wir die Hardware verwenden, auf der wir unsere Programme ausführen.

Das heißt, Ihre Frage muss beantwortet werden, indem die größte binäre N-Bit Zahl mit der größten Zahl der Form 2^exponent * mantissa verglichen wird, wobei exponent mantissa E- und M-Bit Binärzahlen sind (mit eine implizite 1 am Anfang der Mantisse). Das ist 2^(2^E-1) * (2^M - 1) , was normalerweise viel größer ist als 2^N - 1 .

    
PJTraill 05.05.2015 13:37
quelle
0

Ein kleines Beispiel für Damon und Paxdiablo Erklärungen:

%Vor%

Ausgabe:

%Vor%

Beide Variablen wären auf die gleiche Weise mit einer Verschiebung von 51 oder weniger inkrementiert worden.

    
calandoa 05.05.2015 13:22
quelle