To a precision of 1 decimal digits, the maximum number you can work with is 562949953421311.
To a precision of 2 decimal digits, it's 70368744177663.
Interestingly, the first number is equal to:
(Number.MAX_SAFE_INTEGER + 1) / 16 - 1
And the second number is equal to:
(Number.MAX_SAFE_INTEGER + 1) / 128 - 1
What we're looking for, is the maximum safe number to support a precision of d digits after the decimal point.
By "support" I mean "can reliably do basic arithmetic".
For example, we know that Number.MAX_SAFE_INTEGER (aka 2**53-1) is not safe, because basic arithmetic is broken:
Number.MAX_SAFE_INTEGER - 0.1 === Number.MAX_SAFE_INTEGER
>>> true // unsafe
And we know that 0 is safe, since:
0 + 0.1 === 0
>>> false // safe
BTW, 0 is reliable as far as 1e-323 (including):
0 + 1e-323 === 0
>>> false // safe
0 + 1e-324 === 0
>>> true // unsafe
I binary-searched between 0 and Number.MAX_SAFE_INTEGER for the biggest number that answers that definition, and came up with these numbers.
Here's the code (pass any other number to findMaxSafeFloat() at the end of snippet)
/**Returns whether basic arithmetic breaks between n and n+1, to a precision of `digits` after the decimal point*/
function isUnsafe(n, digits) {
// digits = 1 loops 10 times with 0.1 increases.
// digits = 2 means 100 steps of 0.01, and so on.
let prev = n;
for (let i = 10 ** -digits; i < 1; i += 10 ** -digits) {
if (n + i === prev) { // eg 10.2 === 10.1
return true;
}
prev = n + i;
}
return false;
}
/**Binary search between 0 and Number.MAX_SAFE_INTEGER (2**53 - 1) for the biggest number that is safe to the `digits` level of precision.
* digits=9 took ~30s, I wouldn't pass anything bigger.*/
function findMaxSafeFloat(digits, log = false) {
let n = Number.MAX_SAFE_INTEGER;
let lastSafe = 0;
let lastUnsafe = undefined;
while (true) {
if (log) {
console.table({
'': {
n,
'Relative to Number.MAX_SAFE_INTEGER': `(MAX + 1) / ${(Number.MAX_SAFE_INTEGER + 1) / (n + 1)} - 1`,
lastSafe,
lastUnsafe,
'lastUnsafe - lastSafe': lastUnsafe - lastSafe
}
});
}
if (isUnsafe(n, digits)) {
lastUnsafe = n;
} else { // safe
if (lastSafe + 1 === n) { // Closed in as far as possible
console.log(`\n\nMax safe number to a precision of ${digits} digits after the decimal point: ${n}\t((MAX + 1) / ${(Number.MAX_SAFE_INTEGER + 1) / (n + 1)} - 1)\n\n`);
return n;
} else {
lastSafe = n;
}
}
n = Math.round((lastSafe + lastUnsafe) / 2);
}
}
console.log(findMaxSafeFloat(1));
An interesting thing I've found by lining up the safe numbers, is that the exponents don't step up in a consistent manner. Look at the table below; once in a while, the exponent increases (or decreases) by 4, and not 3. Not sure why.
| Precision | First UNsafe | 2^53/x |
|-----------|-----------------------------|--------------------------|
| 1 | 562,949,953,421,312 = 2^49 | x = 16 = 2^4 |
| 2 | 70,368,744,177,664 = 2^46 | x = 128 = 2^7 |
| 3 | 8,796,093,022,208 = 2^43 | x = 1,024 = 2^10 |
| 4 | 549,755,813,888 = 2^39 | x = 16,384 = 2^14 |
| 5 | 68,719,476,736 = 2^36 | x = 131,072 = 2^17 |
| 6 | 8,589,934,592 = 2^33 | x = 1,048,576 = 2^20 |
| 7 | 536,870,912 = 2^29 | x = 16,777,216 = 2^24 |
| 8 | 67,108,864 = 2^26 | x = 134,217,728 = 2^27 |
| 9 | 8,388,608 = 2^23 | x = 1,073,741,824 = 2^30 |
Answer from giladbarnea on Stack OverflowTo a precision of 1 decimal digits, the maximum number you can work with is 562949953421311.
To a precision of 2 decimal digits, it's 70368744177663.
Interestingly, the first number is equal to:
(Number.MAX_SAFE_INTEGER + 1) / 16 - 1
And the second number is equal to:
(Number.MAX_SAFE_INTEGER + 1) / 128 - 1
What we're looking for, is the maximum safe number to support a precision of d digits after the decimal point.
By "support" I mean "can reliably do basic arithmetic".
For example, we know that Number.MAX_SAFE_INTEGER (aka 2**53-1) is not safe, because basic arithmetic is broken:
Number.MAX_SAFE_INTEGER - 0.1 === Number.MAX_SAFE_INTEGER
>>> true // unsafe
And we know that 0 is safe, since:
0 + 0.1 === 0
>>> false // safe
BTW, 0 is reliable as far as 1e-323 (including):
0 + 1e-323 === 0
>>> false // safe
0 + 1e-324 === 0
>>> true // unsafe
I binary-searched between 0 and Number.MAX_SAFE_INTEGER for the biggest number that answers that definition, and came up with these numbers.
Here's the code (pass any other number to findMaxSafeFloat() at the end of snippet)
/**Returns whether basic arithmetic breaks between n and n+1, to a precision of `digits` after the decimal point*/
function isUnsafe(n, digits) {
// digits = 1 loops 10 times with 0.1 increases.
// digits = 2 means 100 steps of 0.01, and so on.
let prev = n;
for (let i = 10 ** -digits; i < 1; i += 10 ** -digits) {
if (n + i === prev) { // eg 10.2 === 10.1
return true;
}
prev = n + i;
}
return false;
}
/**Binary search between 0 and Number.MAX_SAFE_INTEGER (2**53 - 1) for the biggest number that is safe to the `digits` level of precision.
* digits=9 took ~30s, I wouldn't pass anything bigger.*/
function findMaxSafeFloat(digits, log = false) {
let n = Number.MAX_SAFE_INTEGER;
let lastSafe = 0;
let lastUnsafe = undefined;
while (true) {
if (log) {
console.table({
'': {
n,
'Relative to Number.MAX_SAFE_INTEGER': `(MAX + 1) / ${(Number.MAX_SAFE_INTEGER + 1) / (n + 1)} - 1`,
lastSafe,
lastUnsafe,
'lastUnsafe - lastSafe': lastUnsafe - lastSafe
}
});
}
if (isUnsafe(n, digits)) {
lastUnsafe = n;
} else { // safe
if (lastSafe + 1 === n) { // Closed in as far as possible
console.log(`\n\nMax safe number to a precision of ${digits} digits after the decimal point: ${n}\t((MAX + 1) / ${(Number.MAX_SAFE_INTEGER + 1) / (n + 1)} - 1)\n\n`);
return n;
} else {
lastSafe = n;
}
}
n = Math.round((lastSafe + lastUnsafe) / 2);
}
}
console.log(findMaxSafeFloat(1));
An interesting thing I've found by lining up the safe numbers, is that the exponents don't step up in a consistent manner. Look at the table below; once in a while, the exponent increases (or decreases) by 4, and not 3. Not sure why.
| Precision | First UNsafe | 2^53/x |
|-----------|-----------------------------|--------------------------|
| 1 | 562,949,953,421,312 = 2^49 | x = 16 = 2^4 |
| 2 | 70,368,744,177,664 = 2^46 | x = 128 = 2^7 |
| 3 | 8,796,093,022,208 = 2^43 | x = 1,024 = 2^10 |
| 4 | 549,755,813,888 = 2^39 | x = 16,384 = 2^14 |
| 5 | 68,719,476,736 = 2^36 | x = 131,072 = 2^17 |
| 6 | 8,589,934,592 = 2^33 | x = 1,048,576 = 2^20 |
| 7 | 536,870,912 = 2^29 | x = 16,777,216 = 2^24 |
| 8 | 67,108,864 = 2^26 | x = 134,217,728 = 2^27 |
| 9 | 8,388,608 = 2^23 | x = 1,073,741,824 = 2^30 |
Update: My understanding about this question is: Is there a maximum floating number, between 0 and that, all floating number operation can be safely delivered.
If that is the question, short answer is: No
Actually, there is no MAX_SAFE_FLOAT in all programming language (will be very glad if there is one). Number in programming language is stored by 0 or 1 bits. As long as there is a limit for the storage (32bits, 64bits etc), numbers that can be represented is finite. However, the number of floating-number is infinite.
Consider floating-number between 0 and 0.000000001, how many numbers need to be represented? Infinite. It's impossible to let computer store infinite possibility accurately. That's why there would never be MAX_SAFE_FLOAT.
p.s. In JavaScript, all numbers are 64bit double-precision floating-number. There is no floating-number v.s. interger-number in JavaScript.
In JS max int value is 1e+309 but why?
and what is Infinity
JavaScript has two number types: Number and BigInt.
The most frequently-used number type, Number, is a 64-bit floating point IEEE 754 number.
The largest exact integral value of this type is Number.MAX_SAFE_INTEGER, which is:
- 253-1, or
- +/- 9,007,199,254,740,991, or
- nine quadrillion seven trillion one hundred ninety-nine billion two hundred fifty-four million seven hundred forty thousand nine hundred ninety-one
To put this in perspective: one quadrillion bytes is a petabyte (or one thousand terabytes).
"Safe" in this context refers to the ability to represent integers exactly and to correctly compare them.
From the spec:
Note that all the positive and negative integers whose magnitude is no greater than 253 are representable in the
Numbertype (indeed, the integer 0 has two representations, +0 and -0).
To safely use integers larger than this, you need to use BigInt, which has no upper bound.
Note that the bitwise operators and shift operators operate on 32-bit integers, so in that case, the max safe integer is 231-1, or 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
Technical note on the subject of the number 9,007,199,254,740,992: There is an exact IEEE-754 representation of this value, and you can assign and read this value from a variable, so for very carefully chosen applications in the domain of integers less than or equal to this value, you could treat this as a maximum value.
In the general case, you must treat this IEEE-754 value as inexact, because it is ambiguous whether it is encoding the logical value 9,007,199,254,740,992 or 9,007,199,254,740,993.
>= ES6:
Number.MIN_SAFE_INTEGER;
Number.MAX_SAFE_INTEGER;
<= ES5
From the reference:
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