Was ist die kleinstmögliche Zahl? – Programmierwort des Tages

 Marin Benčević
Marin Benčević

Folgen

Aug 7, 2018 · 5 min Lesezeit

Was ist die kleinste Zahl größer als 0? Dies ist eine dieser einfachen Fragen mit komplizierten Antworten irgendwo zwischen „Es gibt keine“ und „Es hängt davon ab“.

Wenn Sie einen Mathematiker fragen, werden sie Ihnen sagen, dass es keine solche Zahl geben kann, weil sie die Mathematik brechen würde. Wenn Sie eine Zahl n haben, wobei n die kleinste Zahl nach 0 ist, kann es keine Zahl n / 2 geben, da n bereits die kleinste ist. Dies bedeutet, dass die Division selbst zusammenbricht, was Mathematikern nicht gefällt.

Wenn Sie einen Computer fragen, erhalten Sie tatsächlich eine Antwort. Im Gegensatz zur realen Welt haben Computer nicht unendlich viele Zahlen, weil sie einfach nicht passen könnten. Computer speichern Zahlen in Speicherregistern, und jedes Register hat eine feste Anzahl von Bits. Stellen Sie sich vor, Sie hätten nur drei Ziffern. Die größte Zahl, die Sie darstellen könnten, wäre 999. Genau das passiert in einem Computer.

Dies bedeutet, dass die Menge der Ganzzahlen in einem Computer durch die Anzahl der Ziffern begrenzt ist. In einem Computer gibt es definitiv eine größte Zahl (zum Beispiel INT_MAX in C). Es ist die Zahl mit der maximalen Anzahl von Ziffern, die alle auf eine Binärzahl 1 gesetzt sind. Auf einem 8-Bit-System wäre diese Zahl 11111111.

Wir können die Sache noch komplizierter machen, indem wir negative Zahlen einschließen. Wenn wir 8 Datenbits haben, können wir das erste Bit verwenden, um das Vorzeichen der Zahl darzustellen. 0 für Plus und 1 für Minus. Jetzt haben wir 7 Bits für unsere Ziffern, also ist die größte Zahl 011111111, was kleiner ist als unsere vorherige größte Zahl.

Wir sind noch nicht fertig. Wir müssen auch Dezimalzahlen darstellen. Auch wenn 0,12 eine kleine Zahl ist, hat sie immer noch drei Ziffern, genau wie 123. Der Unterschied ist, dass wir noch an eine Sache denken müssen: den Dezimalpunkt, auch Radixpunkt genannt. Wir müssen sowohl die Ziffern als auch die Position des Radixpunkts speichern.

Während Ganzzahlen in ihrer Größe begrenzt sind, sind Dezimalzahlen in Größe und Genauigkeit begrenzt. Wenn Sie eine feste Anzahl von Ziffern haben, gibt es nur so viele Ziffern, die Sie nach dem Dezimalpunkt setzen können. Aus diesem Grund müssen Computer Dezimalzahlen runden.

Wie speichern wir dann diese Dezimalzahlen? Computer verstehen nur ganze Zahlen, daher brauchen wir eine Möglichkeit, eine Dezimalzahl nur mit ganzen Zahlen zu speichern.

Angenommen, wir haben die Nummer 3.14. Beginnen wir mit dem Schreiben aller Ziffern der Nummer. Wir erhalten 314. Das ist ein Anfang. Wir wissen, dass wir durch Multiplikation mit Potenzen von 10 den Dezimalpunkt um die Zahl „verschieben“ können. 314 * 10^-1 ist 31,4, während 314 * 10^-2 3,14 ist.

Alles, was wir brauchen, um die Zahl 3.14 darzustellen, sind drei ganze Zahlen: 314, 10 und -2. 314 ist ein sogenannter Signifikand, und dies sind alle Ziffern der ausgeschriebenen Zahl.

10 wird als Radix oder Base bezeichnet. Wir wissen, dass wir durch Multiplikation mit Potenzen von 10 den Dezimalpunkt um Zahlen in der Basis 10 bewegen können. Das gleiche funktioniert für alle Zahlenbasen: in Basis 2 (oder binär) können Sie den Punkt verschieben, indem Sie mit Potenzen von 2 multiplizieren.

Die Potenz, um die wir verschieben, wird Exponent genannt und sagt uns, wo der Dezimalpunkt ist.

Sie können jede Dezimalzahl als diese drei Zahlen mit einer einfachen Formel schreiben:

number = significand * base^exponent3.14 = 314 * 10^-2
32.8 = 328 * 10^-1

Ein Computer speichert eine Dezimalzahl, indem er das Vorzeichen, den Exponenten und den Signifikanten in einer einzigen Zeichenfolge von 32- oder 64-Bit-Ziffern speichert. Normalerweise gibt es 1 Bit für das Vorzeichen, 11 Bits zum Speichern des Exponenten und 53 Bits zum Speichern des Signifikanden, was 64 ergibt.

In diesem Sinne kehren wir zu unserer Frage zurück: Was ist die kleinste Zahl ungleich Null? Wenn wir nur drei Ziffern übrig haben, ist die kleinstmögliche Zahl 0,01. Mit vier Ziffern ist es 0,001. Sie werden hier ein Muster bemerken: Der Signifikanzwert ist immer gleich, nur der Exponent ändert sich.

Was wir brauchen, ist ein Signifikanzwert von 1, denn das ist der kleinste nach 0. Wir müssen dann den Dezimalpunkt so weit wie möglich nach links verschieben. Dazu benötigen wir den kleinsten (negativsten) möglichen Exponenten.

Wie klein, hängt vom Layout der Nummer im Speicher ab. Wenn wir 11 Bits für den Exponenten haben, können wir nur eine Zahl schreiben, die 10 Bits lang ist, wobei 1 Bit für das Vorzeichen reserviert ist. In einem 64-Bit-System ist der kleinste Exponent -308.

Am Ende wäre die kleinstmögliche Zahl in einem 64-Bit-System etwa 1 * 10^-308. Das ist klein!

Wir haben festgestellt, dass es eine kleinste Zahl gibt. Diese Zahl sagt uns, wie sehr wir unserem Computer vertrauen können. Wenn Sie etwas tun, das sehr große Zahlen oder sehr genaue Zahlen erfordert, müssen Sie diese Zahl im Auge behalten.

Was wir gerade berechnet haben, ist etwas, das als Einheit an letzter Stelle oder ulp von 0 bezeichnet wird. Abgesehen davon, dass es ein wirklich cooles Wort ist, ulp sagt uns, was der Mindestabstand zwischen zwei Zahlen in einem Computer ist. Wir haben den ulp von 0 berechnet, was der Mindestabstand zwischen 0 und der nächsten Zahl ist.

Wenn Sie den berechneten Wert zu 0 addieren und versuchen, sie zu vergleichen, sind sie nicht dieselbe Zahl. Wenn Sie jedoch einen Wert hinzufügen, der kleiner als der ulp ist, ist dies für den Computer immer noch dieselbe Zahl.

print(0 == 0 + ulp(0)) // false
print(0 == 0 + ulp(0) / 2) // true

Für uns ist es offensichtlich, dass das Hinzufügen eines Werts ungleich Null zu einer Zahl eine andere Zahl ergibt, aber ein Computer muss irgendwo runden, sodass er nicht unbedingt feststellen kann, ob zwei Zahlen gleich sind.

Um Computersysteme einfacher zu vergleichen, verwenden wir den ulp von 1 und nennen ihn die Maschine epsilon. Sobald Sie die Maschine epsilon kennen, können Sie jede andere ulp mit der folgenden Formel berechnen:

ulp(x) = machine epsilon * radix^exponent(x)

Der von uns berechnete Wert ist sehr klein, sodass Sie dieses Limit beim Codieren wahrscheinlich nicht erreichen werden. Aber wir haben den Wert für 0 berechnet. Je mehr Ziffern für die linke Seite des Dezimalpunkts benötigt werden, desto weniger haben wir für die rechte Seite. Das bedeutet, je größer die Zahl, desto weniger Genauigkeit haben Sie. Mit anderen Worten, der ulp ist eine direkte Funktion des Exponenten. Wenn Sie den Dezimalpunkt nach rechts verschieben, erhöht sich der ulp und Sie verlieren an Genauigkeit.

Ich hoffe, diese Informationen helfen Ihnen beim nächsten Mal, wenn Sie einen seltsamen Gleitkommafehler in Ihrem Code erhalten. Denken Sie daran, Computer sind ziemlich leistungsfähig, aber selbst ein Computer hat seine Grenzen.



+