1107 Stimmen

Was ist der höchste ganzzahlige Wert in JavaScript, den eine Zahl erreichen kann, ohne an Präzision zu verlieren?

Ist dies in der Sprache festgelegt? Gibt es ein bestimmtes Maximum? Ist es in verschiedenen Browsern unterschiedlich?

990voto

Jimmy Punkte 85199

JavaScript hat zwei Zahlentypen: Number y BigInt .

Der am häufigsten verwendete Zahlentyp, Number ist ein 64-Bit-Gleitkomma IEEE 754 Nummer.

Der größte exakte Integralwert dieser Art ist Number.MAX_SAFE_INTEGER das ist:

  • 2 53 -1, oder
  • +/- 9.007.199.254.740.991, oder
  • neun Quadrillionen sieben Billionen einhundertneunundneunzig Milliarden zweihundertvierundfünfzig Millionen siebenhundertvierzigtausendneunhunderteinundneunzig

Zum Vergleich: Eine Billiarde Bytes ist ein Petabyte (oder tausend Terabytes).

"Sicher" bezieht sich in diesem Zusammenhang auf die Fähigkeit, ganze Zahlen exakt darzustellen und korrekt zu vergleichen.

Aus der Spezifikation:

Beachten Sie, dass alle positiven und negativen ganzen Zahlen, deren Betrag nicht größer als 2 53 sind darstellbar in der Number Typ (in der Tat ist die Ganzzahl 0 hat zwei Darstellungen, +0 und -0).

Um ganze Zahlen, die größer sind, sicher zu verwenden, müssen Sie BigInt die keine Obergrenze hat.

Beachten Sie, dass die bitweisen Operatoren und die Verschiebeoperatoren mit 32-Bit-Ganzzahlen arbeiten, so dass in diesem Fall die maximal sichere Ganzzahl 2 ist 31 -1, also 2.147.483.647.

const log = console.log
var x = 9007199254740992
var y = -x
log(x == x + 1) // true !
log(y == y - 1) // also true !

// Arithmetic operators work, but bitwise/shifts only operate on int32:
log(x / 2)      // 4503599627370496
log(x >> 1)     // 0
log(x | 1)      // 1

Technische Anmerkung zur Zahl 9.007.199.254.740.992: Es gibt eine exakte IEEE-754-Darstellung dieses Wertes, und Sie können diesen Wert einer Variablen zuweisen und aus ihr lesen, also für sehr sorgfältig gewählten Anwendungen im Bereich der ganzen Zahlen, die kleiner oder gleich diesem Wert sind, könnten Sie dies als Maximalwert behandeln.

Im allgemeinen Fall müssen Sie diesen IEEE-754-Wert als ungenau behandeln, da es nicht eindeutig ist, ob er den logischen Wert 9.007.199.254.740.992 oder 9.007.199.254.740.993 kodiert.

497voto

Peter Bailey Punkte 103278

>= ES6:

Number.MIN_SAFE_INTEGER;
Number.MAX_SAFE_INTEGER;

<= ES5

Von die Referenz :

Number.MAX_VALUE;
Number.MIN_VALUE;

console.log('MIN_VALUE', Number.MIN_VALUE);
console.log('MAX_VALUE', Number.MAX_VALUE);

console.log('MIN_SAFE_INTEGER', Number.MIN_SAFE_INTEGER); //ES6
console.log('MAX_SAFE_INTEGER', Number.MAX_SAFE_INTEGER); //ES6

119voto

Vjeux Punkte 5726

Es sind 2 53 \== 9 007 199 254 740 992. Der Grund dafür ist Number s werden als Fließkommazahlen mit einer Mantisse von 52 Bit gespeichert.

Der Mindestwert ist -2 53 .

Dies macht einige lustige Dinge passieren

Math.pow(2, 53) == Math.pow(2, 53) + 1
>> true

Und kann auch gefährlich sein :)

var MAX_INT = Math.pow(2, 53); // 9 007 199 254 740 992
for (var i = MAX_INT; i < MAX_INT + 2; ++i) {
    // infinite loop
}

Lesen Sie weiter: <a href="http://blog.vjeux.com/2010/javascript/javascript-max_int-number-limits.html" rel="noreferrer">http://blog.vjeux.com/2010/javascript/javascript-max_int-number-limits.html</a>

65voto

BananaNeil Punkte 9300

In JavaScript gibt es eine Zahl namens Infinity .

Beispiele:

(Infinity>100)
=> true

// Also worth noting
Infinity - 1 == Infinity
=> true

Math.pow(2,1024) === Infinity
=> true

Dies mag für einige Fragen zu diesem Thema ausreichend sein.

49voto

Carr Punkte 2491

Viele frühere Antworten haben gezeigt 9007199254740992 === 9007199254740992 + 1 es wahr um zu überprüfen, dass 9,007,199,254,740,991 ist die maximale und sichere ganze Zahl.

Aber was ist, wenn wir weiter akkumulieren?

input: 9007199254740992 + 1  output: 9007199254740992  // expected: 9007199254740993
input: 9007199254740992 + 2  output: 9007199254740994  // expected: 9007199254740994
input: 9007199254740992 + 3  output: 9007199254740996  // expected: 9007199254740995
input: 9007199254740992 + 4  output: 9007199254740996  // expected: 9007199254740996

Wir können sehen, dass unter den Zahlen größer als 9,007,199,254,740,992 sind nur gerade Zahlen darstellbar .

Es ist ein Eintrag, der erklärt, wie die Doppelpräzisions-64-Bit-Binärformat Werke. Schauen wir mal, wie 9,007,199,254,740,992 unter Verwendung dieses Binärformats gespeichert (dargestellt) werden.

Zur Veranschaulichung eine kurze Version aus 4,503,599,627,370,496 :

  1 . 0000 ---- 0000  *  2^52            =>  1  0000 ---- 0000.  
     |-- 52 bits --|    |exponent part|        |-- 52 bits --|

Auf der linken Seite des Pfeils haben wir Bitwert 1 und ein angrenzendes Radixpunkt . Durch den Verbrauch des Exponententeils auf der linken Seite wird der Radixpunkt um 52 Schritte nach rechts verschoben. Der Radixpunkt landet am Ende, und wir erhalten 4503599627370496 in reinem Binärformat.

Nun erhöhen wir den Bruchteil so lange um 1, bis alle Bits auf 1 gesetzt sind, was gleichbedeutend ist mit 9,007,199,254,740,991 in Dezimalzahlen.

  1 . 0000 ---- 0000  *  2^52  =>  1  0000 ---- 0000.  
                       (+1)
  1 . 0000 ---- 0001  *  2^52  =>  1  0000 ---- 0001.  
                       (+1)
  1 . 0000 ---- 0010  *  2^52  =>  1  0000 ---- 0010.  
                       (+1)
                        . 
                        .
                        .
  1 . 1111 ---- 1111  *  2^52  =>  1  1111 ---- 1111. 

Da das 64-Bit-Doppelpräzisionsformat 52 Bits für den Bruchteil vorsieht, sind keine weiteren Bits verfügbar, wenn wir eine weitere 1 hinzufügen:

   This bit is implicit and persistent.

  1 . 1111 ---- 1111  *  2^52      =>  1  1111 ---- 1111. 
     |-- 52 bits --|                     |-- 52 bits --|

                          (+1)

  1 . 0000 ---- 0000  *  2^52 * 2  =>  1  0000 ---- 0000. * 2  
     |-- 52 bits --|                     |-- 52 bits --|
                                      (By consuming the 2^52, radix
                                       point has no way to go, but
                                       there is still one 2 left in
                                       exponent part)
  =>  1 . 0000 ---- 0000  *  2^53 
         |-- 52 bits --| 

Jetzt bekommen wir die 9,007,199,254,740,992 und für die Zahlen, die darüber liegen, kann das Format nur 2er-Schritte verarbeiten, da jeder 1er-Schritt im Bruchteil mit der linken 2 im Exponententeil multipliziert wird. Deshalb ist Doppelpräzisions-64-Bit-Binärformat kann keine ungeraden Zahlen enthalten, wenn die Zahl größer ist als 9,007,199,254,740,992 :

                            (consume 2^52 to move radix point to the end)
  1 . 0000 ---- 0001  *  2^53  =>  1  0000 ---- 0001.  *  2
     |-- 52 bits --|                 |-- 52 bits --|

Wenn die Zahl größer als 9.007.199.254.740.992 * 2 = 18.014.398.509.481.984 ist, kann der Bruch nur viermal gehalten werden:

input: 18014398509481984 + 1  output: 18014398509481984  // expected: 18014398509481985
input: 18014398509481984 + 2  output: 18014398509481984  // expected: 18014398509481986
input: 18014398509481984 + 3  output: 18014398509481984  // expected: 18014398509481987
input: 18014398509481984 + 4  output: 18014398509481988  // expected: 18014398509481988

Wie wäre es mit Zahlen zwischen [ 2 251 799 813 685 248 , 4 503 599 627 370 496 )?

 1 . 0000 ---- 0001  *  2^51  =>  1 0000 ---- 000.1
     |-- 52 bits --|                |-- 52 bits  --|

Der Wert 0,1 ist im Binärsystem genau 2^-1 (=1/2) (=0,5) Wenn die Zahl also kleiner ist als 4,503,599,627,370,496 (2^52) steht ein Bit zur Verfügung, das die 1/2 mal der ganzen Zahl :

input: 4503599627370495.5   output: 4503599627370495.5  
input: 4503599627370495.75  output: 4503599627370495.5  

Weniger als 2,251,799,813,685,248 (2^51)

input: 2251799813685246.75   output: 2251799813685246.8  // expected: 2251799813685246.75 
input: 2251799813685246.25   output: 2251799813685246.2  // expected: 2251799813685246.25 
input: 2251799813685246.5    output: 2251799813685246.5
/**
   Please note that if you try this yourself and, say, log 
   these numbers to the console, they will get rounded. JavaScript
   rounds if the number of digits exceed 17. The value 
   is internally held correctly:
*/

input: 2251799813685246.25.toString(2) 
output: "111111111111111111111111111111111111111111111111110.01"
input: 2251799813685246.75.toString(2) 
output: "111111111111111111111111111111111111111111111111110.11"
input: 2251799813685246.78.toString(2)   
output: "111111111111111111111111111111111111111111111111110.11"

Und wie groß ist die verfügbare Reichweite von Exponententeil ? 11 Bits, die das Format dafür vorsieht.

Von Wikipedia (weitere Einzelheiten finden Sie dort)

IEEE 754 Double Floating Point Format.svg

Damit der Exponent Teil 2^52 ist, müssen wir e = 1075 setzen.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X