จำนวนเต็มสูงสุดของ JavaScript คือจำนวนใดที่สามารถไปได้โดยไม่สูญเสียความแม่นยำ


951

สิ่งนี้ถูกกำหนดโดยภาษาหรือไม่ มีค่าสูงสุดที่กำหนดหรือไม่? มันแตกต่างกันในเบราว์เซอร์ที่แตกต่างกันอย่างไร


5
คุณไม่จำเป็นต้องขึ้นอยู่กับขีด จำกัด ของ JS กับไลบรารีเช่น github.com/MikeMcl/big.jsดูตัวอย่างที่นี่สำหรับการทดสอบความน่าเชื่อถือ
Dmitri Zaitsev

2
ค่าจำนวนเต็มสูงสุดที่คุณสามารถใช้ได้กับ big.js คืออะไร
จอร์จ

@George นี่คือ big.js API: mikemcl.github.io/big.js/#dp
simhumileco

คำถามไม่สมเหตุสมผล หมายความว่าตัวเลข "ไปที่" ค่าจำนวนเต็ม? ถ้าคุณแค่อยากถามว่าอะไรคือจำนวนเต็มสูงสุดที่คุณสามารถแทนได้ใน JS จำนวนสูงสุด (จำกัด ) ตัวมันเองคือจำนวนเต็ม
Veky

@DmitriZaitsev เราไม่จำเป็นต้องพึ่งพาไลบรารีภายนอกอีกต่อไป (ในบางเบราว์เซอร์อย่างน้อย) 1n << 10000nเป็นจำนวนเต็มขนาดใหญ่จริง ๆ โดยไม่สูญเสียความแม่นยำใด ๆ โดยไม่จำเป็นต้องพึ่งพาใด ๆ (และไม่จำเป็นต้องพูดไม่จำเป็นต้องใกล้ถึงขีด จำกัด )
ดาน

คำตอบ:


868

JavaScript มีสองประเภทจำนวน: และNumberBigInt

ส่วนใหญ่ที่ใช้บ่อยชนิดจำนวนNumberเป็น 64 บิตจุดลอยตัวIEEE 754จำนวน

ค่าอินทิกรัลที่แน่นอนที่สุดของประเภทนี้Number.MAX_SAFE_INTEGERคือ:

  • 2 53 -1 หรือ
  • +/- 9,007,199,254,740,991 หรือ
  • เก้า quadrillion เจ็ดล้านล้านหนึ่งแสนเก้าหมื่นเก้าพันสองร้อยห้าสิบสี่ล้านเจ็ดแสนสี่หมื่นเก้าร้อยเก้าสิบเก้า

ในการวางมุมมองนี้: หนึ่งพันล้านล้านไบต์เป็นเพตาไบต์ (หรือหนึ่งพันเทราไบต์)

"ปลอดภัย" ในบริบทนี้หมายถึงความสามารถในการแสดงจำนวนเต็มอย่างชัดเจนและเปรียบเทียบได้อย่างถูกต้อง

จากสเป็ค:

โปรดทราบว่าจำนวนเต็มบวกและลบทั้งหมดที่มีขนาดไม่เกิน 2 53สามารถแทนได้ในNumberประเภท (จริง ๆ แล้วจำนวนเต็ม 0 มีการแทนสองครั้ง, +0 และ -0)

หากต้องการใช้จำนวนเต็มที่มีขนาดใหญ่กว่านี้อย่างปลอดภัยคุณต้องใช้BigIntซึ่งไม่มีขอบเขตบน

โปรดทราบว่าตัวดำเนินการ bitwise และตัวดำเนินการ shift ทำงานกับจำนวนเต็ม 32 บิตดังนั้นในกรณีดังกล่าวจำนวนเต็มสูงสุดที่ปลอดภัยคือ 2 31 -1 หรือ 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


หมายเหตุด้านเทคนิคเกี่ยวกับเรื่องของหมายเลข 9,007,199,254,740,992: มีการแทนค่า IEEE-754 ที่แน่นอนของค่านี้และคุณสามารถกำหนดและอ่านค่านี้จากตัวแปรดังนั้นสำหรับแอปพลิเคชันที่เลือกอย่างระมัดระวังในโดเมนของจำนวนเต็มน้อยกว่าหรือเท่ากับ ค่านี้คุณสามารถถือว่านี่เป็นค่าสูงสุด

ในกรณีทั่วไปคุณต้องปฏิบัติต่อค่า IEEE-754 นี้เป็นแบบไม่แน่นอนเนื่องจากไม่ชัดเจนว่าจะเข้ารหัสค่าตรรกะ 9,007,199,254,740,992 หรือ 9,007,199,254,740,993


75
สิ่งนี้ดูเหมือนจะถูกต้อง แต่มีบางแห่งที่กำหนดไว้เช่นนี้ MAX_INT หรือ Integer ของ Java MAX_VALUE
TALlama

48
4294967295 === Math.pow(2,32) - 1;
CoolAJ86

13
ดังนั้นจำนวนเต็มที่น้อยที่สุดและใหญ่ที่สุดที่เราสามารถใช้เพื่อรับรองความถูกต้องแม่นยำคืออะไร
Pacerier

38
อาจจะน่าสังเกตว่าไม่มีจริง (int) ในจาวาสคริปต์ ทุกตัวอย่างของ Number คือ (float) หรือ NaN
บีทรูทบีทรูท

53
9007199254740992 ไม่ใช่ค่าสูงสุดจริง ๆ บิตสุดท้ายที่นี่ถือว่าเป็นศูนย์แล้วคุณจึงสูญเสียความแม่นยำ 1 บิต หมายเลขปลอดภัยจริงคือ 9007199254740991 (Number.MAX_SAFE_INTEGER)
Willem D'Haeseleer

461

> = ES6:

Number.MIN_SAFE_INTEGER;
Number.MAX_SAFE_INTEGER;

<= ES5

จากการอ้างอิง :

Number.MAX_VALUE;
Number.MIN_VALUE;


23
ฉันได้แก้ไขคำถามเพื่อให้แม่นยำยิ่งขึ้นเล็กน้อยเกี่ยวกับการต้องการค่าสูงสุดจำนวนเต็มไม่ใช่แค่ค่าจำนวนสูงสุด ขออภัยในความสับสนที่นี่
TALlama

5
ผลลัพธ์ที่ได้นั้นรับประกันว่าจะเท่ากันในทุกเบราว์เซอร์หรือไม่
Pacerier

7
โปรดทราบว่าNumber.MIN_VALUEเป็นจำนวนบวกที่น้อยที่สุดที่เป็นไปได้ น้อยค่า (เช่นน้อยกว่าสิ่งอื่น) -Number.MAX_VALUEน่าจะเป็น
Michael Scheper

34
ES6 แนะนำNumber.MIN_SAFE_INTEGERและNumber.MAX_SAFE_INTEGER
superlukas

2
ดังนั้นในกรณีนี้เราควรโหวตคำตอบเพราะมันผิดสำหรับคำถามที่อัปเดตหรือปล่อยทิ้งไว้เพราะ Peter Baily นั้นถูกต้องในเวลาที่ตอบ
rocketsarefast

112

มันคือ 2 53 == 9 007 199 254 740 992 นี่เป็นเพราะNumbers ถูกเก็บไว้เป็นทศนิยมใน mantissa 52 บิต

ค่านาที -2 53

ทำให้บางสิ่งสนุกเกิดขึ้น

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

และอาจเป็นอันตรายด้วย :)

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
}

อ่านเพิ่มเติม: http://blog.vjeux.com/2010/javascript/javascript-max_int-number-limits.html


1
แม้ว่าใครจะไม่ถึงจุดสิ้นสุดของการวนรอบในกรอบเวลาที่มีสติคุณอาจต้องการที่จะพูดi += 1000000000
ninjagecko

2
@ninjagecko เขาเริ่มต้นที่ MAX_INT ดังนั้นจุดจบอยู่ตรงนั้น การใช้ i + = 1000000000 จะทำให้ไม่วนซ้ำอีกต่อไป ลองมัน.
Ted Bigham

@TedBigham: โอ้อุ๊ปซ์ก็พร้อมแล้วเร็วเกินไป ขอบคุณที่แก้ไขฉันสองครั้ง
ninjagecko

ดูอาร์กิวเมนต์ของจิมมี่สำหรับ 9.007.199.254.740.991 แทน 9.007.199.254.740.992 ที่นี่ ที่รวมกับการติดตามของฉันดูเหมือนจะโน้มน้าวใจ
TJ Crowder

60

ใน JavaScript Infinityมีเป็นจำนวนที่เรียกว่า

ตัวอย่าง:

(Infinity>100)
=> true

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

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

อาจเพียงพอสำหรับคำถามบางข้อเกี่ยวกับหัวข้อนี้


25
มีบางอย่างบอกฉันว่าอินฟินิตี้ไม่ได้มีคุณสมบัติเป็นจำนวนเต็ม :)
devios1

7
แต่ก็ดีพอที่จะเริ่มต้นminตัวแปรเมื่อคุณมองหาค่าต่ำสุด
djjeck

9
โปรดทราบว่าInfinity - 1 === Infinity
H.Wolper

2
ด้วย (Infinity <100) => false และ Math.pow (2,1024) === Infinity
Sijav

6
ยังไม่มีค่าอะไรที่มันจะจัดการกับอนันต์เชิงลบด้วย ดังนั้น1 - Infinity === -Infinity
dmccabe

41

คำตอบของจิมมี่อย่างถูกต้องแสดงถึงสเปกตรัมจำนวนเต็ม JavaScript อย่างต่อเนื่องเป็น-9007199254740992ถึง9007199254740992รวม (ขออภัย 9007199254740993 คุณอาจคิดว่าคุณเป็น 9007199254740993 แต่คุณผิด! การ สาธิตด้านล่างหรือในjsfiddle )

console.log(9007199254740993);

อย่างไรก็ตามไม่มีคำตอบที่ค้นพบ / พิสูจน์ทางโปรแกรม (นอกเหนือจาก CoolAJ86 ที่กล่าวถึงในคำตอบของเขาซึ่งจะเสร็จสิ้นใน 28.56 ปี;) ดังนั้นนี่เป็นวิธีที่มีประสิทธิภาพมากกว่าเล็กน้อยในการทำเช่นนั้น (มีความแม่นยำมากกว่า ประมาณ 28.559999999968312 ปี :) พร้อมกับซอทดสอบ :

/**
 * Checks if adding/subtracting one to/from a number yields the correct result.
 *
 * @param number The number to test
 * @return true if you can add/subtract 1, false otherwise.
 */
var canAddSubtractOneFromNumber = function(number) {
    var numMinusOne = number - 1;
    var numPlusOne = number + 1;
    
    return ((number - numMinusOne) === 1) && ((number - numPlusOne) === -1);
}

//Find the highest number
var highestNumber = 3; //Start with an integer 1 or higher

//Get a number higher than the valid integer range
while (canAddSubtractOneFromNumber(highestNumber)) {
    highestNumber *= 2;
}

//Find the lowest number you can't add/subtract 1 from
var numToSubtract = highestNumber / 4;
while (numToSubtract >= 1) {
    while (!canAddSubtractOneFromNumber(highestNumber - numToSubtract)) {
        highestNumber = highestNumber - numToSubtract;
    }
    
    numToSubtract /= 2;
}        

//And there was much rejoicing.  Yay.    
console.log('HighestNumber = ' + highestNumber);


8
@ CoolAJ86: ฮ่า ๆ ฉันรอคอยที่จะ 15 มีนาคม 2040 ถ้าตัวเลขของเราตรงกับที่เราควรจะจัดงานปาร์ตี้ :)
Briguy37

var x = Math.pow (2,53) -3; ในขณะที่ (x! = x + 1) x ++; -> 9007199254740991
MickLH

@MickLH: ฉันได้รับ 9007199254740992 ด้วยรหัสนั้น คุณใช้โปรแกรมจาวาสคริปต์ใดในการทดสอบ
Briguy37

คุณจะได้รับ 9007199254740992 ด้วยรหัสของคุณเองฉันไม่ได้ใช้ค่าสุดท้ายของ x แต่การหาค่าสุดท้ายของ x ++ สำหรับเหตุผลหวาดระแวง Google Chrome btw
MickLH

@MickLH: การประเมินx++ให้คุณค่าแก่คุณก่อนที่จะเกิดการเพิ่มขึ้นดังนั้นจึงอาจอธิบายความคลาดเคลื่อน หากคุณต้องการแสดงออกในการประเมินถึงสิ่งเดียวกันเป็นค่าสุดท้ายของ x ++xคุณควรเปลี่ยนไป
peterflynn

32

เพื่อความปลอดภัย

var MAX_INT = 4294967295;

เหตุผล

ฉันคิดว่าฉันฉลาดและหาคุณค่าที่x + 1 === xมีวิธีปฏิบัติมากขึ้น

เครื่องของฉันสามารถนับ 10 ล้านต่อวินาทีหรือมากกว่านั้น ... ดังนั้นฉันจะโพสต์กลับด้วยคำตอบที่ชัดเจนใน 28.56 ปี

หากคุณรอไม่ได้นานฉันก็ยินดีที่จะเดิมพัน

  • ลูปส่วนใหญ่ของคุณไม่ทำงาน 28.56 ปี
  • 9007199254740992 === Math.pow(2, 53) + 1 มีหลักฐานเพียงพอ
  • คุณควรยึดติดกับ4294967295สิ่งที่Math.pow(2,32) - 1เป็นเพื่อหลีกเลี่ยงปัญหาที่คาดหวังด้วยการขยับบิต

หาx + 1 === x:

(function () {
  "use strict";

  var x = 0
    , start = new Date().valueOf()
    ;

  while (x + 1 != x) {
    if (!(x % 10000000)) {
      console.log(x);
    }

    x += 1
  }

  console.log(x, new Date().valueOf() - start);
}());

4
ไม่สามารถเริ่มได้ที่ 2 ^ 53 - 2 เพื่อทดสอบ? (ใช่คุณทำได้ฉันแค่ลองแล้วแม้ว่าจะปลอดภัย -3: var x = Math.pow (2,53) -3; ในขณะที่ (x! = x + 1) x ++;) -> 9007199254740991
MickLH

คำตอบที่ดี! ยิ่งกว่านั้นฉันรู้ว่าค่าถูกตัดสิน แต่ทำไมไม่ใช้การค้นหาแบบไบนารีสำหรับการค้นหา
higuaro

1
ความสนุกในนั้นคืออะไร? นอกจากนี้ @ Briguy37 ยังเอาชนะฉันได้: stackoverflow.com/a/11639621/151312
CoolAJ86

โปรดทราบว่า MAX_INT แบบ 'ปลอดภัย' ซึ่งใช้ 32 บิตจะไม่ทำงานเมื่อเปรียบเทียบกับค่าวันที่ เมื่อวานนี้ 4294967295 เป็นเช่นนั้น!
Jerry

1
คำตอบ "เพื่อความปลอดภัย: var MAX_INT = 4294967295;" ไม่ตลก หากคุณไม่ได้เปลี่ยนบิตไม่ต้องกังวลกับมัน (เว้นแต่ว่าคุณต้องการ int ที่มีขนาดใหญ่กว่า 4294967295 ซึ่งในกรณีนี้คุณควรเก็บไว้เป็นสตริงและใช้ไลบรารี่ขนาดใหญ่)
CoolAJ86

29

คำตอบสั้น ๆ คือ“ ขึ้นอยู่กับ”

หากคุณใช้ตัวดำเนินการระดับบิตที่ใดก็ได้ (หรือถ้าคุณอ้างถึงความยาวของแถวลำดับ) ช่วงคือ:

ไม่ได้ลงนาม: 0…(-1>>>0)

ลงนาม: (-(-1>>>1)-1)…(-1>>>1)

(มันเกิดขึ้นที่ตัวดำเนินการระดับบิตและความยาวสูงสุดของอาร์เรย์ถูก จำกัด ไว้ที่จำนวนเต็ม 32 บิต)

หากคุณไม่ได้ใช้โอเปอเรเตอร์บิตเตอร์หรือทำงานกับอาเรย์

ลงนาม: (-Math.pow(2,53))…(+Math.pow(2,53))

ข้อ จำกัด เหล่านี้ถูกกำหนดโดยการเป็นตัวแทนภายในของประเภท“ ตัวเลข” ซึ่งโดยทั่วไปจะสอดคล้องกับการเป็นตัวแทนทศนิยมความแม่นยำสองเท่าของ IEEE 754 (โปรดทราบว่าไม่เหมือนกับเลขจำนวนเต็มทั่วไปขนาดของขีด จำกัด เชิงลบเท่ากับขนาดของขีด จำกัด บวกเนื่องจากลักษณะของการเป็นตัวแทนภายในซึ่งจริง ๆ แล้วมีค่าลบ 0!)


นี่คือคำตอบที่ฉันต้องการสะดุดในวิธีการแปลง X เป็นจำนวนเต็ม 32 บิตหรือจำนวนเต็มไม่ได้ลงนาม ยกระดับคำตอบของคุณสำหรับสิ่งนั้น
Charlie Affumigato

29

ECMAScript 6:

Number.MAX_SAFE_INTEGER = Math.pow(2, 53)-1;
Number.MIN_SAFE_INTEGER = -Number.MAX_SAFE_INTEGER;

1
ระวัง นี่ยังไม่รองรับเบราว์เซอร์ทั้งหมด!วันนี้ iOS (ไม่ได้เป็นโครเมี่ยม), Safari และ IE ไม่ชอบ
cregox

5
โปรดอ่านคำตอบอย่างระมัดระวังเราไม่ได้ใช้การเริ่มต้นใช้งาน Number.MAX_SAFE_INTEGER ใน ECMAScript 6 เรากำหนดโดย Math.pow (2, 53) -1
WaiKit Kung

ฉันคิดว่ามันเป็นเพียงการอ้างอิงถึงวิธีการใช้งานใน ECMA 6! : PI คิดว่าความคิดเห็นของฉันยังคงใช้ได้ เรื่องของบริบททั้งหมด ;)
cregox

3
การคำนวณMAX_SAFE_INTEGERย้อนหลังในเบราว์เซอร์ทั้งหมดน่าเชื่อถือหรือไม่ คุณควรย้ายไปข้างหน้าแทนไหม? เช่น, Number.MAX_SAFE_INTEGER = 2 * (Math.pow (2, 52) - 1) + 1;
kjv

คือMath.pow(2, 53)-1การดำเนินการความปลอดภัยหรือไม่ มันจะใหญ่กว่าเลขจำนวนเต็มที่ปลอดภัยที่สุดตัวหนึ่ง
ioquatix

21

คำตอบมากมายจากก่อนหน้านี้แสดงให้เห็นผลลัพธ์trueของ9007199254740992 === 9007199254740992 + 1การตรวจสอบว่า9 007 199 254 740 991เป็นจำนวนเต็มสูงสุดและปลอดภัย

เกิดอะไรขึ้นถ้าเรายังคงสะสม:

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

เราสามารถหาได้ว่าในบรรดาตัวเลขที่มากกว่า9 007 199 254 740 992มีเพียงตัวเลขเท่านั้นที่สามารถแทนได้แทนได้

เป็นทางเข้าเพื่ออธิบายวิธีการทำงานของรูปแบบไบนารี 64 บิตที่มีความแม่นยำสูงนี้ มาดูกันว่า9 007 199 254 740 992ถูกจัดขึ้น (แสดง) โดยใช้รูปแบบไบนารีนี้อย่างไร

ใช้เวอร์ชันย่อเพื่อสาธิต 4 503 599 627 370 496 :

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

ที่ด้านซ้ายของลูกศรเรามี ค่าบิต 1และจุด radix ที่อยู่ติดกันจากนั้นโดยการคูณ2^52เราไปทางขวาย้ายจุด radix 52 ขั้นตอนและมันจะสิ้นสุด ตอนนี้เราได้ 4503599627370496 เป็นไบนารี่

ทีนี้เราเริ่มสะสม 1 ถึงค่านี้จนกระทั่งบิตทั้งหมดตั้งค่าเป็น 1 ซึ่งเท่ากับ9 007 199 254 740 991 เป็นทศนิยม

  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. 

ตอนนี้เนื่องจากว่าในรูปแบบไบนารี 64 บิตที่มีความแม่นยำสองเท่าจะจัดสรรส่วนที่ 52 บิตสำหรับเศษส่วนจึงไม่มีบิตที่จะดำเนินการสำหรับการเพิ่มหนึ่งอีก 1 ดังนั้นสิ่งที่เราสามารถทำได้คือตั้งบิตทั้งหมดกลับเป็น 0 และ จัดการส่วนเลขชี้กำลัง:

  |--> This bit is implicit and persistent.
  |        
  1 . 1111 ---- 1111  *  2^52      =>  1  1111 ---- 1111. 
     |-- 52 bits --|                     |-- 52 bits --|

                          (+1)
                                     (radix point has no way to go)
  1 . 0000 ---- 0000  *  2^52 * 2  =>  1  0000 ---- 0000. * 2  
     |-- 52 bits --|                     |-- 52 bits --|

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

ทีนี้เราได้ 9 9 007 199 254 740 992และด้วยจำนวนที่มากกว่านั้นรูปแบบที่สามารถเก็บได้คือเศษส่วน 2 เท่านั่นหมายความว่าตอนนี้ทุก ๆ 1 ส่วนของเศษส่วนเท่ากับ 2 บวกนั่นคือสาเหตุที่สอง -precision รูปแบบไบนารี 64 บิตไม่สามารถเก็บตัวเลขคี่ได้เมื่อตัวเลขมากกว่า 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 --|

ดังนั้นเมื่อตัวเลขได้มากกว่า 9 007 199 254 740 992 * 2 = 18 014 398 509 481 984 เท่านั้น เศษส่วน 4 ครั้งที่สามารถจัดขึ้นได้:

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

วิธีประมาณหมายเลขระหว่าง [ 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  --|

ค่าบิต 1 หลังจากจุด radix คือ 2 ^ -1 (= 1/2, = 0.5) ดังนั้นเมื่อจำนวนที่น้อยกว่า4 503 599 627 370 496 (2 ^ 52) มีหนึ่งบิตที่สามารถใช้แทน 1/2 คูณของจำนวนเต็ม :

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

น้อยกว่า 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

// If the digits exceed 17, JavaScript round it to print it.
//, but the value is 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"

และสิ่งที่เป็นช่วงที่มีอยู่ของส่วนสัญลักษณ์ ? รูปแบบจัดสรร 11 บิตสำหรับมัน รูปแบบที่สมบูรณ์จากWiki : (สำหรับรายละเอียดเพิ่มเติมกรุณาไปที่นั่น)

IEEE 754 Double Floating Point Format.svg

ป้อนคำอธิบายรูปภาพที่นี่

ดังนั้นเพื่อให้ส่วนเลขชี้กำลังเป็น 2 ^ 52 เราต้องตั้ง e = 1075


13

อื่น ๆ อาจให้คำตอบทั่วไปแล้ว แต่ฉันคิดว่ามันเป็นความคิดที่ดีที่จะให้วิธีที่รวดเร็วในการพิจารณา:

for (var x = 2; x + 1 !== x; x *= 2);
console.log(x);

ซึ่งให้ฉัน 9007199254740992 ภายในน้อยกว่าหนึ่งมิลลิวินาทีใน Chrome 30

มันจะทดสอบพลังของ 2 เพื่อหาอันที่เมื่อ 'เพิ่ม' 1 เท่ากับตัวเอง


อาจทำให้แอปพลิเคชันของคุณขัดข้อง
Sapphire_Brick

8

สิ่งที่คุณต้องการใช้สำหรับการดำเนินการในระดับบิตจะต้องอยู่ระหว่าง 0x80000000 (-2147483648 หรือ -2 ^ 31) และ 0x7fffffff (2147483647 หรือ 2 ^ 31 - 1)

คอนโซลจะบอกคุณว่า 0x80000000 เท่ากับ +2147483648 แต่ 0x80000000 และ 0x80000000 เท่ากับ -2147483648


6

ลอง:

maxInt = -1 >>> 1

ใน Firefox 3.6 มันคือ 2 ^ 31 - 1


2
@danorton: ฉันไม่แน่ใจว่าคุณเข้าใจสิ่งที่คุณกำลังทำ ^หมายถึงการยกขึ้นสู่อำนาจ ในคอนโซล javascript ^คือXORไม่ใช่แบบยกระดับให้
kumarharsh

2
เปิดคอนโซล Chrome / Firefox พิมพ์ 5 ^ 2 ในไบนารี 5 101และ 2 010เป็น ตอนนี้ถ้าคุณ Bitwise XOR คุณจะได้5(101) ^ 2(010) = 7(111) อ่านสิ่งนี้หากคุณมั่นใจ สิ่งที่ถูกกล่าวถึงที่นี่Math.pow()ไม่ใช่ตัว^ดำเนินการ
kumarharsh

3
อีกครั้งฉันไม่สับสนเลย ผมมีความเห็นและ downvoted กับสิ่งที่เป็นลายลักษณ์อักษร หาก Math.pow () เป็นสิ่งที่มีความหมายแล้วนั่นคือสิ่งที่ควรจะเขียน ในการตอบคำถามเกี่ยวกับ JavaScript มันไม่เหมาะสมที่จะใช้ไวยากรณ์ของภาษาอื่น มันไม่เหมาะสมที่จะใช้ไวยากรณ์ที่ถูกต้องใน JavaScript แต่มีการตีความใน JavaScript ที่มีความหมายแตกต่างจากสิ่งที่ตั้งใจไว้
danorton

10
2 ^ 31 เป็นวิธีที่หนึ่งเขียนสองถึงสามสิบเอ็ดอำนาจในภาษาอังกฤษ มันไม่ได้อยู่ในบล็อคโค้ด คุณจะบ่นเกี่ยวกับคนที่ใช้ ในคำตอบเพราะนั่นคือตัวละครที่มีความหมายแตกต่างกันใน Javascript?
lmm

3
แม้ว่าหนึ่งควรเขียน2³¹และไม่2 ^ 31ในข้อความธรรมดาที่จะทำเช่นนั้นเพราะส่วนใหญ่รูปแบบแป้นพิมพ์ไม่มีตัวอักษรเหล่านั้นโดยค่าเริ่มต้น อย่างน้อยฉันก็ไม่มีปัญหาใด ๆ ที่จะเข้าใจความหมายของคำตอบนี้
Jocke

6

ในขณะที่เขียน, JavaScript BigIntจะได้รับข้อมูลใหม่ประเภท: มันเป็นข้อเสนอที่ TC39 ที่4 ขั้นตอนที่จะรวมอยู่ในECMAScript 2020 BigIntพร้อมใช้งานใน Chrome 67+, FireFox 68+, Opera 54 และ Node 10.4.0 มันกำลังดำเนินการอยู่ใน Safari และอื่น ๆ ... แนะนำตัวอักษรตัวเลขที่มีคำต่อท้าย "n" และอนุญาตให้มีความแม่นยำตามอำเภอใจ:

var a = 123456789012345678901012345678901n;

ความแม่นยำจะยังคงสูญหายอยู่แน่นอนเมื่อจำนวนดังกล่าวถูกข่มขู่กับชนิดข้อมูลตัวเลข

และแน่นอนว่าจะมีข้อ จำกัด ที่แม่นยำเนื่องจากหน่วยความจำ จำกัด และค่าใช้จ่ายในแง่ของเวลาเพื่อจัดสรรหน่วยความจำที่จำเป็นและดำเนินการทางคณิตศาสตร์กับตัวเลขจำนวนมากเช่นนี้

ตัวอย่างเช่นการสร้างตัวเลขที่มีตัวเลขหลักแสนหนึ่งแสนหลักจะทำให้เกิดความล่าช้าอย่างเห็นได้ชัดก่อนที่จะเสร็จสิ้น:

console.log(BigInt("1".padEnd(100000,"0")) + 1n)

... แต่มันใช้งานได้


4

ฉันทำการทดสอบอย่างง่ายด้วยสูตร X- (X + 1) = - 1 และค่าที่ใหญ่ที่สุดของ XI สามารถทำงานกับ Safari, Opera และ Firefox (ทดสอบบน OS X) คือ 9e15 นี่คือรหัสที่ฉันใช้สำหรับการทดสอบ:

javascript: alert(9e15-(9e15+1));

1
โปรดทราบว่า 9e15 = 2 ^ 53 (ดูคำตอบของ @ Jimmy)
ลิ่ม

6
9e15 = 9000000000000000 2 ^ 53 = 9007199254740992 ดังนั้นในการพูดพล่าม 9e15 จึงมีค่าประมาณเท่ากับ 2 ^ 53 (มีตัวเลขนัยสำคัญสองตัว)
devios1

@chaiguy ใน9000000000000000นั้นมี 1 ตัวเลขที่สำคัญ ใน `9007199254740992 'มี 15 ตัวเลขนัยสำคัญ
Royi Namir

@RoyiNamir ไม่ต้องการเริ่มอาร์กิวเมนต์ที่ไม่มีจุดหมายที่นี่ แต่ 9000000000000000 มีตัวเลข 16 หลัก ถ้าคุณต้องการเพียง 1 มันจะต้องเขียนเป็น 9x10 ^ 15
devios1

1
@chaiguy ไม่9000000000000000มันเป็น - มี1เอสเอฟ โดยที่90*10^14มี 2. ( sigfigscalculator.appspot.com ) & mathsfirst.massey.ac.nz/Algebra/Decimals/SigFig.htm (ส่วนล่าง)
Royi Namir

3

ฉันเขียนแบบนี้:

var max_int = 0x20000000000000;
var min_int = -0x20000000000000;
(max_int + 1) === 0x20000000000000;  //true
(max_int - 1) < 0x20000000000000;    //true

เหมือนกันสำหรับ int32

var max_int32 =  0x80000000;
var min_int32 = -0x80000000;

3

เรามาถึงแหล่งที่มา

ลักษณะ

MAX_SAFE_INTEGERคงมีค่า9007199254740991(9,007,199,254,740,991 หรือ ~ 9 quadrillion) เหตุผลที่อยู่เบื้องหลังของจำนวนนั้นคือจาวาสคริปต์ใช้ตัวเลขรูปแบบทศนิยมที่มีความแม่นยำสองเท่าตามที่ระบุในIEEE 754และสามารถแสดงตัวเลขระหว่าง-(2^53 - 1)และ2^53 - 1และ

ปลอดภัยในบริบทนี้หมายถึงความสามารถในการแสดงจำนวนเต็มอย่างแน่นอนและเปรียบเทียบได้อย่างถูกต้อง ตัวอย่างเช่นNumber.MAX_SAFE_INTEGER + 1 === Number.MAX_SAFE_INTEGER + 2จะประเมินเป็นจริงซึ่งไม่ถูกต้องทางคณิตศาสตร์ ดูNumber.isSafeInteger ()สำหรับข้อมูลเพิ่มเติม

เนื่องจากMAX_SAFE_INTEGERเป็นคุณสมบัติแบบคงที่ของNumberคุณจะใช้มันเป็นNumber.MAX_SAFE_INTEGERแทนที่จะเป็นคุณสมบัติของวัตถุNumber ที่คุณสร้างขึ้น

ความเข้ากันได้ของเบราว์เซอร์

ป้อนคำอธิบายรูปภาพที่นี่




-1

Scato wrotes:

สิ่งที่คุณต้องการใช้สำหรับการดำเนินการระดับบิตต้องอยู่ระหว่าง 0x80000000 (-2147483648 หรือ -2 ^ 31) และ 0x7fffffff (2147483647 หรือ 2 ^ 31 - 1)

คอนโซลจะบอกคุณว่า 0x80000000 เท่ากับ +2147483648 แต่ 0x80000000 และ 0x80000000 เท่ากับ -2147483648

ทศนิยมสิบหกเป็นค่าบวกที่ไม่ได้ลงนามดังนั้น 0x80000000 = 2147483648 - นั่นถูกต้องทางคณิตศาสตร์ ถ้าคุณต้องการทำให้มันเป็นค่าที่ลงนามคุณต้องกะขวา: 0x80000000 >> 0 = -2147483648 คุณสามารถเขียน 1 << 31 แทนได้เช่นกัน


-7

Firefox 3 ดูเหมือนจะไม่มีปัญหากับจำนวนมาก

1e + 200 * 1e + 100 จะคำนวณค่าปรับเป็น 1e + 300

Safari ดูเหมือนจะไม่มีปัญหากับมันเช่นกัน (สำหรับบันทึกนี้เป็นบน Mac หากใครตัดสินใจที่จะทดสอบนี้)

เว้นแต่ว่าฉันจะสูญเสียสมองในเวลานี้นี่เป็นวิธีที่ใหญ่กว่าจำนวนเต็ม 64 บิต


18
มันไม่ใช่จำนวนเต็ม 64 บิต แต่เป็นจำนวนจุดลอยตัว 64 บิตซึ่ง 52/53 บิตเป็นส่วนจำนวนเต็ม ดังนั้นมันจะจัดการได้ถึง 1e300 แต่ไม่ใช่ด้วยความแม่นยำที่แน่นอน
จิมมี่

4
จิมมี่ถูกต้องแล้ว ลองสิ่งนี้ในเบราว์เซอร์หรือบรรทัดคำสั่ง JS ของคุณ:100000000000000010 - 1 => 100000000000000020
Ryan

-7

Node.js และ Google Chrome ดูเหมือนว่าทั้งสองจะใช้ค่าทศนิยม 1024 บิตดังนั้น:

Number.MAX_VALUE = 1.7976931348623157e+308

1
-1: จำนวนสูงสุดที่สามารถแทนได้ (ไม่ถูกต้อง) อาจเป็น ~ 2 ^ 1024 แต่นั่นไม่ได้หมายความว่าพวกเขาเบี่ยงเบนจากมาตรฐาน IEEE-754 64-บิต
Roy Tinker

2
MAX_INT? คุณหมายถึง MAX_VALUE หรือไม่
Raul Guiu

3
นั่นคือค่าทศนิยมสูงสุด ไม่ได้หมายความว่าคุณสามารถเก็บ int ไว้ได้นาน
phuclv

1
หรือมากกว่าไปยังจุดที่คุณไม่สามารถเชื่อถือได้เก็บ int ว่านานโดยไม่สูญเสียของความถูกต้อง 2^53เรียกว่าMAX_SAFE_INTเพราะเหนือจุดนั้นค่าจะกลายเป็นค่าประมาณในทางเดียวกันคือเศษส่วน
IMSoP
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.