Why is JavaScript's number *display* for large numbers inaccurate? - javascript

So in JavaScript, 111111111111111111111 == 111111111111111110000. Just type any long number – at least about 17 digits – to see it in action ;-)
That is because JavaScript uses double-precision floating-point numbers, and certain very long numeric literals can not be expressed accurately. Instead, those numbers get rounded to the nearest representable number possible. See e.g. What is JavaScript's highest integer value that a Number can go to without losing precision?
However, doing the math according to IEEE-754, I found out that every number inside [111111111111111106560, 111111111111111122944] will be replaced by 111111111111111114752 internally. But instead of showing this ...4752 number, it gets displayed as 111111111111111110000. So JavaScript is showing those trailing zeros which obfuscates the real behavior. This is especially annoying because even numbers like 263, which are accurately representable, get "rounded" as described.
So my question is: Why does JavaScript behave like this when displaying the number?

JavaScript integers can only be +/- 253, which is:
9007199254740992
One of your numbers is
111111111111111106560
which is considerably outside of the range of numbers that can accurately represented as an integer.
This follows the IEEE 754:
Sign bit: 1 bit
Exponent width: 11 bits
Significand precision: 53 bits (52 explicitly stored)
EDIT
The Display of numbers is sometimes rounded by the JavaScript engine, yes. However, that can be over-ridden using the toFixed method. (Warning, toFixed is known to be broken under some versions of IE).
In your console, type:
111111111111111122944..toFixed(0)
"111111111111111114752"

Related

Js how to increase a big number [duplicate]

This question already has answers here:
What is JavaScript's highest integer value that a number can go to without losing precision?
(21 answers)
Closed 4 months ago.
How to increase this number(you can try it on the browser console):
36893488147419103000 + 1
The result of this is:
36893488147419103000
The number stays the same no changes to it why is that? and how can I increase it by 1?
For big integers you should use the BigInt (Big Integer) type.
Note 1: you almost always cannot mix BigInt numbers with Numbers (eg for math operations) without first performing an explicit conversion.
Note 2: JSON does not currently natively support BigInt values. As a workaround you can use strings (eg. '1n' for the values and then use a reviver function when calling JSON.parse.
JavaScript currently only has two numeric types: double-precision IEEE 754 floating point Numbers, and Big Integers which can be used to represent arbitrarily large integers. You can declare a BigInt number literal using the suffix n, eg. 1n.
IEEE 754 Numbers can "only" accurately represent integers up to and including Number.MAX_SAFE_INTEGER, which has a value of 2^53 - 1 or 9,007,199,254,740,991 or ~9 quadrillion.
From MDN:
Double precision floating point format only has 52 bits to represent the mantissa, so it can only safely represent integers between -(253 – 1) and 253 – 1. "Safe" in this context refers to the ability to represent integers exactly and to compare them correctly. For example, Number.MAX_SAFE_INTEGER + 1 === Number.MAX_SAFE_INTEGER + 2 will evaluate to true, which is mathematically incorrect. See Number.isSafeInteger() for more information.
A "Decimal" number type, that will be able to represent arbitrarily precise decimal numbers, is under development.
Obviously the number is internally represented as a floating point number.When the value you want do add to this number is less then the value of the least significant bit, it will not change the the value.
The only way would be to use floating point numbers with a higher resolution i.e. with a higher number of significant bits.
Double precision floating point format only has 52 bits to represent the mantissa, so it can only safely represent integers between -(253 – 1) and 253 – 1. See Number.MAX_SAFE_INTEGER. Larger numbers may not be able to be represented exactly.

How does Javascript store a numeric value?

I am new to JavaScript programming and referring to Eloquent JavaScript, 3rd Edition by Marijn Haverbeke.
There is a statement in this book which reads like,
"JavaScript uses a fixed number of bits, 64 of them, to store a single number value. There are only so many patterns you can make with 64 bits, which means that the number of different numbers that can be represented is limited. With N decimal digits, you can represent 10^N numbers. Similarly, given 64 binary digits, you can represent 2^64 different numbers, which is about 18 Quintilian (an 18 with 18 zeros after it). That’s a lot."
Can someone help me with the actual meaning of this statement. I am confused as to how the values more than 2^64 are stored in the computer memory.
Can someone help me with the actual meaning of this statement. I am
confused as to how the values more than 2^64 are stored in the
computer memory.
Your questions is related with more generic concepts in Computer Science. For this question Javascript stays at higher level.
Please understand basic concepts for memory and storage first;
https://study.com/academy/lesson/how-do-computers-store-data-memory-function.html
https://www.britannica.com/technology/computer-memory
https://www.reddit.com/r/askscience/comments/2kuu9e/how_do_computers_handle_extremely_large_numbers/
How do computers evaluate huge numbers?
Also for Javascript please see this ECMAScript section
Ref: https://www.ecma-international.org/ecma-262/5.1/#sec-8.5
The Number type has exactly 18437736874454810627 (that is, 264−253+3) values, representing the double-precision 64-bit format IEEE 754 values as specified in the IEEE Standard for Binary Floating-Point Arithmetic, except that the 9007199254740990 (that is, 253−2) distinct “Not-a-Number” values of the IEEE Standard are represented in ECMAScript as a single special NaN value. (Note that the NaN value is produced by the program expression NaN.) In some implementations, external code might be able to detect a difference between various Not-a-Number values, but such behaviour is implementation-dependent; to ECMAScript code, all NaN values are indistinguishable from each other.
There are two other special values, called positive Infinity and negative Infinity. For brevity, these values are also referred to for expository purposes by the symbols +∞ and −∞, respectively. (Note that these two infinite Number values are produced by the program expressions +Infinity (or simply Infinity) and -Infinity.)
The other 18437736874454810624 (that is, 264−253) values are called the finite numbers. Half of these are positive numbers and half are negative numbers; for every finite positive Number value there is a corresponding negative value having the same magnitude.
Note that there is both a positive zero and a negative zero. For brevity, these values are also referred to for expository purposes by the symbols +0 and −0, respectively. (Note that these two different zero Number values are produced by the program expressions +0 (or simply 0) and -0.)
The 18437736874454810622 (that is, 264−253−2) finite nonzero values are of two kinds:
18428729675200069632 (that is, 264−254) of them are normalised, having the form
s × m × 2e
where s is +1 or −1, m is a positive integer less than 253 but not less than 252, and e is an integer ranging from −1074 to 971, inclusive.
The remaining 9007199254740990 (that is, 253−2) values are denormalised, having the form
s × m × 2e
where s is +1 or −1, m is a positive integer less than 252, and e is −1074.
Note that all the positive and negative integers whose magnitude is no greater than 253 are representable in the Number type (indeed, the integer 0 has two representations, +0 and -0).
A finite number has an odd significand if it is nonzero and the integer m used to express it (in one of the two forms shown above) is odd. Otherwise, it has an even significand.
In this specification, the phrase “the Number value for x” where x represents an exact nonzero real mathematical quantity (which might even be an irrational number such as π) means a Number value chosen in the following manner. Consider the set of all finite values of the Number type, with −0 removed and with two additional values added to it that are not representable in the Number type, namely 21024 (which is +1 × 253 × 2971) and −21024 (which is −1 × 253 × 2971). Choose the member of this set that is closest in value to x. If two values of the set are equally close, then the one with an even significand is chosen; for this purpose, the two extra values 21024 and −21024 are considered to have even significands. Finally, if 21024 was chosen, replace it with +∞; if −21024 was chosen, replace it with −∞; if +0 was chosen, replace it with −0 if and only if x is less than zero; any other chosen value is used unchanged. The result is the Number value for x. (This procedure corresponds exactly to the behaviour of the IEEE 754 “round to nearest” mode.)
Some ECMAScript operators deal only with integers in the range −231 through 231−1, inclusive, or in the range 0 through 232−1, inclusive. These operators accept any value of the Number type but first convert each such value to one of 232 integer values. See the descriptions of the ToInt32 and ToUint32 operators in 9.5 and 9.6, respectively.
Probably you have learned about big numbers of mathematics.
For example Avogadro constant is 6.022x10**23
Computers can also store numbers in this format.
Except for two things:
They store it as a binary number
They would store Avogadro as 0.6022*10**24, more precisely
the precision: a value that is between 0 and 1 (0.6022); this is usually 2-8 byte
the size/greatness of the number (24); this is usually only 1 byte because of 2**256 is already a very big number.
As you can see this method can be used to store an inexact value of a very big/small number.
An example of inaccuracy: 0.1 + 0.2 == 0.30000000000000004
Due to performance issues, most engines are often using the normal format, if it makes no difference in the results.

Parsing amount with JSON.parse

Dos it exist a maximum float number with two digits after decimal point that can be parsed with JSON.parse without losing precision?
For example:
JSON.parse('{"amount": 9999999999999.99}')
{amount: 9999999999999.99} // not lose (probably)
JSON.parse('{"amount": 99999999999999.99}')
{amount: 99999999999999.98} // lose
If x is a decimal floating-point number with 15 significant digits or fewer, then converting x to JavaScript’s Number type and then converting the result back to a decimal floating-point number with the same number of significant digits produces exactly x, provided the number is within normal bounds. Therefore, all decimal numerals with two digits after the decimal point from “.00” to “9999999999999.99” can be parsed, stored, and reformatted with two digits after the decimal point, and the result will be the original numeral.
The stored value will generally not equal the original value. For example, when “.99” is parsed, the result will be exactly 0.9899999999999999911182158029987476766109466552734375. However, the stored value will be sufficiently close to the original value that, when converted back to the original number of digits, the original value is recovered. Note that you must know the original number of digits; it is not inherently a part of the Number value.
15 is a lower bound for this property. There may be some exponent values for which all 16-digit decimal numerals survive a round trip. However, since 99999999999999.99 (16 digits) produces 99999999999999.98, we know this is not one of those intervals.
If you want to know the specific number between 9999999999999.99 and 99999999999999.99 where this round-trip property first fails, you may have to hunt for it computationally. It many not be a value that is easy to calculate directly by mathematical properties.

Converting string to base36 inconsistencies between languages.

I have noticed some inconsistencies between Python and JavaScript when converting a string to base36.
Python Method:
>>> print int('abcdefghijr', 36)
Result: 37713647386641447
Javascript Method:
<script>
document.write(parseInt("abcdefghijr", 36));
</script>
Result: 37713647386641450
What causes the different results between the two languages? What would be the best approach to produce the same results irregardless of the language?
Thank you.
That number takes 56 bits to represent. JavaScript's numbers are actually double-precision binary floating point numbers, or double for short. These are 64 bit in total, and can represent a far wider range of values than a 64 bit integers, but due to how they achieve that (they represent a number as mantissa * 2^exponent), they cannot represent all numbers in that range, just the ones that are a multiple of 2^exponent where the multiple fits into the mantissa (which includes 2^0 = 1, so you get all integers the mantissa can handle directly). The mantissa is 53 bits, which is insufficient for this number. So it gets rounded to a number which can be represented.
What you can do is use an arbitrary precision number type defined by a third party library like gwt-math or Big.js. These numbers aren't hard to implement if you know your school arithmetic. Doing it efficiently is another matter, but also an area of extensive research. And not your problem if you use an existing library.

Parse Float has a rounding limit? How can I fix this?

I set up a system that parses a compact data string into JSON. I'm using a 19 digit number to store ids. Unfortunately any number greater than 17 digits, parseFloat() rounds the last few digits.
This breaks the whole data string. Can I fix this?
For example 8246295522085275215 gets turned into 8246295522085276000. Why is this?
http://jsfiddle.net/RobertWHurst/mhZ7Q/
JavaScript has only one numeric type, which is an IEEE 754 double precision floating-point. That means, you have a maximum of 52 bits of precision, which is a bit more than 15 decimal places.
If you need more precision than that, you have to use a bignum library or work with strings.
Numbers in JavaScript lose precision if they are higher than a certain value.
According to http://www.hunlock.com/blogs/The_Complete_Javascript_Number_Reference, integers are only reliable up to 15 digits (9 * 10^15 to be exact).
Try one of these
1. Use a string
2. Split your number in two and save the smaller parts to an array
3. Bignum library
4. Use a smaller number if you can

Categories