it-swarm.com.de

Gibt es Zahlen, die in Basis 10 nicht darstellbar sind, aber in Basis 2 dargestellt werden können?

C# hat den Typ decimal , der für Zahlen verwendet wird, die in Basis 10 genau dargestellt werden müssen. Zum Beispiel 0.1 kann nicht in Basis 2 dargestellt werden (z. B. float und double) und ist immer eine Annäherung, wenn es in Variablen dieses Typs gespeichert wird.

Ich habe mich gefragt, ob die umgekehrte Tatsache auch möglich ist. Gibt es Zahlen, die in Basis 10 nicht darstellbar sind, aber in Basis 2 dargestellt werden können (in diesem Fall möchte ich ein float anstelle eines decimal verwenden, um sie zu behandeln)?

43
Max

Hier ist der Schlüssel zu Ihrem Dilemma: 10 ist das Produkt von 2 und 5. Sie können jede Zahl genau in Dezimalstellen der Basis 10 darstellen, die k * 1/2 istn * 1/5m Dabei sind k, n und m ganze Zahlen.

Alternativ formuliert - Wenn die Zahl n in 1/n einen Faktor enthält, der nicht Teil der Faktoren der Basis ist, kann die Zahl nicht genau in einer festen Anzahl von Ziffern in der Binärdatei/dargestellt werden dezimal/was auch immer Erweiterung dieser Zahl - es wird einen sich wiederholenden Teil haben. Zum Beispiel 1/15 = 0,0666666666 .... weil 3 (15 = 3 * 5) kein Faktor von 10 ist.

Somit alles, was in Basis 2 genau dargestellt werden kann (k * 1/2n) kann in Basis 10 genau dargestellt werden.

Darüber hinaus stellt sich die Frage, wie viele Ziffern/Bits Sie zur Darstellung der Zahl verwenden. Es gibt einige Zahlen, die in einer Basis genau dargestellt werden können, aber es sind mehr als einige Ziffern/Bits erforderlich.


In der Binärdatei kann die Zahl 1/10, die bequemerweise 0,1 in Dezimalzahl ist, nicht als eine Zahl dargestellt werden, die in einer festen Anzahl von Bits in der Binärzahl dargestellt werden kann. Stattdessen lautet die Nummer 0,00011001100110011 ...2 (Der 0011-Teil wiederholt sich für immer).

Schauen wir uns die Nummer 1 an2/ 10102 etwas genauer.

 ____ 
 0,00011 
 + --------- 
 1010 | 1.00000 
 0 
 - 
 1 0 
 0 
 ---- 
 1 00 ------- - + 
 0 | 
 -- 1 000 | 
 0 | 
 ------ | Wiederholen von 
 1 0000 | Block 
 1010 | 
 ------ | 
 1100 | 
 1010 | 
 ---- | 
 100 ---- + 

Dies ist genau die gleiche Art von Dingen, die Sie erhalten, wenn Sie versuchen, die lange Division für 1/3 durchzuführen.

1/10, wenn faktorisiert ist 1/(21 * 51). Für die Basis 10 (oder ein beliebiges Vielfaches von 10) endet diese Zahl und wird als --- (reguläre Zahl bezeichnet. Eine sich wiederholende Dezimalerweiterung wird als wiederholte Dezimalzahl bezeichnet, und die Zahlen, die ohne Wiederholung für immer weitergehen, sind irrationale Zahlen.

Das Mathe dahinter vertieft sich in Fermats kleiner Satz ... und sobald Sie anfangen, Fermat oder Theorem zu sagen, wird es zu einem Math.SE-Frage .

Gibt es Zahlen, die in Basis 10 nicht darstellbar sind, aber in Basis 2 dargestellt werden können?

Die Antwort ist nein'.

An diesem Punkt sollten wir alle klar sein, dass jede binäre Erweiterung einer rationalen Zahl mit fester Länge als Dezimalerweiterung mit fester Länge dargestellt werden kann.


Lassen Sie uns schauen Sie sich die Dezimalstelle in C # genauer an , was uns zu Dezimal-Gleitkomma in .NET führt, und wenn der Autor dies tut, werde ich akzeptieren, dass es so funktioniert.

Der Dezimaltyp hat dieselben Komponenten wie jede andere Gleitkommazahl: eine Mantisse, ein Exponent und ein Vorzeichen. Wie üblich ist das Vorzeichen nur ein einzelnes Bit, aber es gibt 96 Bit Mantisse und 5 Bit Exponent. Es sind jedoch nicht alle Exponentenkombinationen gültig. Es funktionieren nur die Werte 0-28, und sie sind praktisch alle negativ: Der numerische Wert ist sign * mantissa / 10exponent. Dies bedeutet, dass die Maximal- und Minimalwerte des Typs +/ 2) sind96-1), und die kleinste Nicht-Null-Zahl in Bezug auf die absolute Größe ist 10-28.

Ich werde sofort darauf hinweisen, dass es aufgrund dieser Implementierung Zahlen im Typ double gibt, die in decimal nicht dargestellt werden können - solche, die außerhalb des Bereichs liegen. Double.Epsilon ist 4.94065645841247e-324, das nicht in einem decimal dargestellt werden kann, sondern in einem double.

Innerhalb des Bereichs, den die Dezimalzahl darstellen kann, hat sie jedoch eine höhere Genauigkeit als andere native Typen und kann sie fehlerfrei darstellen.

Es gibt einige andere Typen, die herumschweben. Es gibt eine --- (BigInteger in C # , die eine beliebig große ganze Zahl darstellen kann. Es gibt kein Äquivalent zu Java BigDecimal (das Zahlen mit Dezimalstellen von bis zu 2 darstellen kann32 Ziffern lang - das ist ein beträchtlicher Bereich) genau . Wenn Sie jedoch ein wenig herumstochern , können Sie handgerollte Implementierungen finden.

Es gibt einige Sprachen, die auch einen rationalen Datentyp haben, mit dem Sie Rationals genau darstellen können (so dass 1/3 tatsächlich 1/3 ist).


Speziell für C # und die Wahl von float oder rational werde ich Jon Skeet aus dem Decimal Floating Pint in .NET :

Die meisten Geschäftsanwendungen sollten wahrscheinlich eher Dezimal als Float oder Double verwenden. Meine Faustregel lautet, dass künstliche Werte wie die Währung normalerweise besser mit dezimalem Gleitkomma dargestellt werden: Das Konzept von genau 1,25 Dollar ist beispielsweise völlig vernünftig. Für Werte aus der Natur wie Längen und Gewichte sind binäre Gleitkommatypen sinnvoller. Obwohl es theoretische "genau 1,25 Meter" gibt, wird es in der Realität niemals vorkommen: Sie werden sicherlich niemals in der Lage sein, exakte Längen zu messen, und es ist unwahrscheinlich, dass sie überhaupt auf atomarer Ebene existieren. Wir sind daran gewöhnt, dass es eine gewisse Toleranz gibt.

105
user40980

Sobald Sie außerhalb des Bereichs akzeptabler Werte sind, lautet die Antwort Ja. Das heißt, fast alles innerhalb des Bereichs wird eine Darstellung haben. C # Dezimalreferenz Obwohl in der Spezifikation nicht angegeben, können irrationale Zahlen nicht genau dargestellt werden (z. B. e1, pi, Quadratwurzel von 2 usw.).

Das Dezimalschlüsselwort bezeichnet einen 128-Bit-Datentyp. Im Vergleich zu Gleitkommatypen weist der Dezimaltyp eine größere Genauigkeit und einen kleineren Bereich auf, wodurch er für finanzielle und monetäre Berechnungen geeignet ist. Der ungefähre Bereich und die Genauigkeit für den Dezimaltyp sind in der folgenden Tabelle aufgeführt.

Präzision: 28-29 signifikante Stellen

1 Vielen Dank an MichaelT, der mich an eine andere irrationale Zahl erinnert hat.

6
Adam Zuckerman

Ein Gleitkomma-Typ mit Basis zwei könnte viele Werte genau darstellen, die ein Typ mit Basis zehn gleicher Größe nicht könnte. Jeder Wert, der durch einen Basis-2-Typ einer bestimmten Größe genau darstellbar wäre, wäre in einem Basis-Zehn-Typ mit ausreichender Größe genau darstellbar. Die erforderliche Größe für einen reinen Basis-Zehn-Typ zur Darstellung aller Werte einer binären Gleitkommazahl hängt vom Exponentenbereich des binären Typs ab. Hunderte von Bits für ein float oder Tausende für ein double.

Abgesehen davon ist der Typ Decimal groß genug, um als "universeller" Typ verwendet werden zu können, der den Wert eines anderen numerischen Grundelements halten und darüber hinaus einige andere zusätzliche Funktionen bereitstellen kann (if Verwenden Sie ein Bit, um anzugeben, ob der gespeicherte Wert das Ergebnis der Konvertierung eines double ist. Wenn dieses Bit gesetzt ist, verwenden Sie 64 Bit, um den betreffenden Wert zu speichern. Microsoft hat sich jedoch dagegen entschieden. Infolgedessen schlägt die Konvertierung eines double in Decimal bei großen Werten vollständig fehl und führt dazu, dass kleine Werte auf den nächsten Wert 1E-28 gerundet werden. Selbst innerhalb des Dynamikbereichs von decimal wird die Konvertierungsmethode nicht "umlaufen". Wenn Sie beispielsweise 1,0/3,0 als doppelt auswerten, erhalten Sie 0,3333333333333333148, aber wenn Sie diese in eine Dezimalzahl umwandeln, erhalten Sie 0,33333333333333333m, und wenn Sie diese zurück in double konvertieren, erhalten Sie 0,333333333333333329818.

1
supercat