1

I understand about Number.MAX_SAFE_INTEGER and Number.MIN_SAFE_INTEGER.

I understand that Number.MAX_SAFE_INTEGER + 1 === Number.MAX_SAFE_INTEGER + 2 equals true.

But I've only recently realised that:

var number = 2007199254740991;
var float  = 2007199254740991.123;

console.log(number === float);
// => true

But

var number = 1007199254740991;
var float  = 1007199254740991.123;

console.log(number === float);
// => false

So my question is, how do we find the "max safe float"?

EDIT

My question:

At what point does comparing between an "integer" and a "float" equals true?

yqlim
  • 6,898
  • 3
  • 19
  • 43
  • 1
    There are no floats and integers in JS - every number is represented by IEEE 754 float. – VLAZ Aug 14 '19 at 07:06

3 Answers3

3

There is no such thing, because Javascript numbers have limited precision, or significant digits (effectively).

const n1 = 1e-10;
const n2 = 1e-30;
console.log(n1 - n2 === n1);

Even a very small number like 1e-10 will have imprecise behavior when manipulated in combination with numbers significantly smaller than it. The same sort of thing is happening with your snippet - ~1e15 (close to the value of your 1007199254740991) is too large in comparison to 0.123.

There's also the famous imprecise 0.1 + 0.2:

console.log(0.1 + 0.2);

In addition to significant digits being effectively limited, numbers which cannot be precisely represented in binary will have this sort of problem.

CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
  • Can we find at what point does the representations become "imprecise"? – yqlim Aug 14 '19 at 07:13
  • 1
    Well, there is [`Number.EPSION`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/EPSILON) for the minimum representable value between 1 and the next distinct number. [Further reading on floating point arithmetic (also has lots of links)](https://stackoverflow.com/questions/588004/is-floating-point-math-broken) – VLAZ Aug 14 '19 at 07:15
  • 1
    @YongQuan I *think* any number which isn't accurately representable using binary can't be trusted. Eg, mathematical manipulations of `0.5`, `0.25`, `0.125`, `0.625` around the same order of magnitude work, because they can be represented perfectly in binary, but any other decimal number isn't. – CertainPerformance Aug 14 '19 at 07:21
  • 1
    @CertainPerformance just to clarify - `0.5` is `2 ^ -1`, and since it's a power of two, it can be easily represented in bits. Same idea with `0.25` (`2 ^ -2`) and `0.125` (`2 ^ -3`). That's why those values are "better" than, say, `0.1` – VLAZ Aug 14 '19 at 07:23
3

Asking when comparing fails is the wrong question. Comparing two numbers always works correctly; it evaluates to true if and only if the two numbers being compared have the same value.

The problem actually occurs in earlier operations. Converting a numeral in source code to a Number, adding numbers, and other operations introduce errors when the exact real-number mathematical value is rounded to a value representable in floating-point.

JavaScript uses IEEE-754 binary64, which has a 53-bit significand (the fraction portion of a floating-point number). This means any number with a magnitude of 252 or greater does not have any bits that can represent values less than 1—they have no fraction portion. So, when any number 252 or greater is converted to a JavaScript Number, the result is an integer.

But smaller numbers are rounded too. From 251 to 252, the least significant bit available represents 2−1, or ½. So any number in this interval that is converted to a Number must produce either an integer or an integer plus ½. That means some numbers, like 2251799813685248.6, will produce non-integers (2251799813685248.5), while others, like 2251799813685248.8 will produce integers (2251799813685249).

At every magnitude below 252, there are some numbers that will be rounded to integers when converted to Number and some numbers that will not be rounded to integers. (Above 252, all numbers are rounded to integers.) At smaller magnitudes, only numbers closer to integers are rounded to integers—the format becomes more “sensitive” as the magnitude decreases.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
0

You can't find a "max safe float" in JavaScript. It simply doesn't exist.

@CertainPerformance is right, there's a limited precision in JS. Besides, remember that a number in a programming language is stored by 0 or 1 bits, and remember that you can have infinite decimals, so... can you have infinite 0's and 1's? .

As any computer can store infinite numbers, there's no max safe float number.

xale94
  • 424
  • 5
  • 12