look at this picture.(The underLine is input.)
why the end of JavaScript Number with trailing zeros or a not predictable number?
I checked the document with https://www.ecma-international.org/ecma-262/5.1/#sec-9.7
But I can't find anything useful for this problem.
Numbers in Javascript use Double-precision floating-point format which can represent numbers from -(2^53 - 1) and (2^53 - 1). This limits the maximum safe number (Number.MAX_SAFE_INTEGER) to 9007199254740991.
Hence any number above that will be not be represented accurately.
so the thing is there is maximum integer which can be safely manipulated in javascript after that you are supposed to get some unexpected results based on implementation
read about that max safe integer https://www.ecma-international.org/ecma-262/6.0/#sec-number.max_safe_integer
BTW there is a new bigint type which can handle large numbers https://developers.google.com/web/updates/2018/05/bigint
bigint however is not a standard yet i think
Related
I have a scenario where I need to parsefloat 19 digit string to number.
e.g. parseFloat("1000000000100000043") gives me 1000000000100000000
but the expected output required is 1000000000100000043
This is likely a precision overflow error.
The Number data type (but also int and float in other languages) have a finite number of bits available to represent a number. Typically around 15-16 decimal digits worth.
When length of original number in the string exceeds available precision, such number can no longer be represented by the target data type.
In this case the parseFloat function fails silently. If you want to catch this situation you need to add code to check incoming data or use another function, possibly a custom one.
Alternatively, you can convert the numeric value back to string and compare it with original to detect a discrepancy.
See also a question regarding double.Parse
You are running into how Javascript numbers are stored. See, e.g., here: https://www.w3schools.com/js/js_numbers.asp
You can use a library like decimal.js to work with large, exact numbers. These libraries store the number as string, but allow you to do mathematical operations.
BigInt and Number conversions
When working with numbers in JavaScript there are two primitive types to choose from - BigInt and Number. One could expect implicit conversion from "smaller" type to "bigger" type which isn't a case in JavaScript.
Expected
When computing some combination of BigInt and Number user could expect implicit cast from Number to BigInt like in below example:
const number = 16n + 32; // DOESN'T WORK
// Expected: Evaluates to 48n
Actual behavior
Expressions operating on both BigInt and Number are throwing an error:
const number = 16n + 32;
// Throws "TypeError: Cannot mix BigInt and other types, use explicit conversions"
Why explicit conversion is needed in above cases?
Or in other words what is the reason behind this design?
This is documented in the original BigInt proposal: https://github.com/tc39/proposal-bigint/blob/master/README.md#design-goals-or-why-is-this-like-this
When a messy situation comes up, this proposal errs on the side of throwing an exception rather than rely on type coercion and risk giving an imprecise answer.
It's a design choice. In statically typed languages, coercion might give loss of information, like going from float to int the fractional part just gets truncated. JavaScript does type coercion and you may expect 16n + 32 to just use 32 as if it were a BigInt instead of a Number and there wouldn't be a problem.
This was purely a design choice which is motivated here in this part of the documentation
They are not "smaller" and "bigger". One has real but potentially imprecise numbers, the other has integral but precise ones. What do you think should be the result of 16n + 32.5? (note that type-wise, there is no difference between 32 and 32.5). Automatically converting to BigInt will lose any fractional value; automatically converting to Number will risk loss of precision, and potential overflow. The requirement for explicit conversion forces the programmer to choose which behaviour they desire, without leaving it to chance, as a potential (very likely) source of bugs.
You probably missed an important point:
BigInt is about integers
Number is about real numbers
Implicit conversion from 32 to 32n might have sense, but implicit conversion from floating point number e.g. 1.555 to BigInt would be misleading.
When I run the following:
parseInt('96589218797811259658921879781126'.slice(0, 16), 10);
the output is
9658921879781124
whereas the expected is, as you can see:
9658921879781125
What is the cause? I understand vaguely in googling around that there are issues with large numbers in JS and that this indeed appears to be above that threshold, but I don't know what to do about it, or what is happening in this specific case. Thank you.
Edit: Thanks for the answers, I see that depending on an integer this size is bad news. The reason for using an integer is because I need to increment by one, then compare to the rest of the string. In this case, the first half of the string should equal the second half after incrementing the first half by one. What is an alternative approach?
It is not a JavaScript issue.
JavaScript uses the double-precision 64-bit floating point format (IEEE 754) to store both integer and rational numbers.
This format allows the exact representation of integer numbers between -253 and 253 (-9007199254740992 to 9007199254740992). Outside this interval, some integer values cannot be represented by this format; they are rounded to the nearest integer value that can be represented. For example, from 253 to 254, everything is multiplied by 2, so the representable numbers are the even ones.
The JavaScript global object Number provides the constant Number.MAX_SAFE_INTEGER that represents the maximum integer value that can be stored by the IEEE 574 format (253-1).
It also provides the method Number.isSafeInteger() you can use to find out if an integer number can be safely stored by the Number JavaScript type.
The number you use (9658921879781124) is too large to be stored correctly in JavaScript or any other language that uses the double-precision floating point format to store the numbers.
I am facing weird issued.
parseFloat(11111111111111111) converts it to 11111111111111112.
I noticed that it works fine till length is 16 but rounds off higher when input length is > 16.
I want to retain the original value passed in parseFloat after it is executed.
Any help?
Integers (numbers without a period or exponent notation) are considered accurate up to 15 digits.
More information here
Numbers in javascript are represented using 64 bit floating point values (so called doubles in other languages).
doubles can hold at most 15/16 significant digits (depends on number magnitute). Since range of double is 1.7E+/-308 some numbers can only be aproximated by double, in your case 11111111111111111 cannot be represented exactly but is aproximated by 11111111111111112 value. If this sounds strange then remember that 0.3 cannot be represented exactly as double too.
double can hold exact integers values in range +/-2^53, when you are operating in this range - you may expect exact values.
Javascript has a constant, Number.MAX_SAFE_INTEGER which is the highest integer that can be exactly represented.
Safe in this context refers to the ability to represent integers exactly and to correctly compare them. For example, Number.MAX_SAFE_INTEGER + 1 === Number.MAX_SAFE_INTEGER + 2 will evaluate to true, which is mathematically incorrect.
The value is 9007199254740991 (2^53 - 1) which makes a maximum of 15 digits safe.
JavaScript now has BigInt
BigInt is a built-in object that provides a way to represent whole numbers larger than 253 - 1, which is the largest number JavaScript can reliably represent with the Number primitive.
BigInt can be used for arbitrarily large integers.
As you can see in the following blog post, JavaScript only supports 53 bit integers.
if you type in the console
var x = 11111111111111111
and then type
x
you'll get
11111111111111112
This has nothing to do with the parseFloat method.
There's also a related question here about working with big numbers in JavaScript.
Try using the unary + operator.
Like this + ("1111111111111111") + 1 = 1111111111111112
So my problem is this, I'm writing a program that checks if number is even or odd without division. So I decided to take the number, turn it into a String with the
number.toString()
method. The problem I'm having is that if you put a number that is about 17 or more digits long the string is correct for about the first 17 digits then it's just 0's and sometimes 2's. For example,
function toStr (number)
{
return number.toString(10);
}
console.log(toStr(123456789123456789));
prints,
123456789123456780
any ideas?
The problem has nothing to do with strings or your function at all. Try going to your console and just entering the expression 123456789123456789 and pressing return.
You will likewise obtain 123456789123456780.
Why?
The expression 123456789123456789 within the JavaScript language is interpreted as a JavaScript number type, which can only be represented exactly to a certain number of base two significant figures. The input number happens to have more significant digits when expressed in base two than the number of base two significant figures available in JavaScript's representation of a number, and so the value is automatically rounded in base two as follows:
123456789123456789 =
110110110100110110100101110101100110100000101111100010101 (base two)
123456789123456780 =
110110110100110110100101110101100110100000101111100001100 (base two)
Note that you CAN accurately represent some numbers larger than a certain size in JavaScript, but only those numbers with no more significant figures in base two than JavaScript has room for. For instance, 2 times a very large power of 10, which would have only one significant figure in base two.
If you are designing this program to accept user input from a form or dialog box, then you will receive the input as a string. You only need to check the last digit in order to determine if the input number is odd or even (assuming it is indeed an integer to begin with). The other answer has suggested the standard way to obtain the last character of a string as well as the standard way to test if a string value is odd or even.
If you go beyond Javascript's max integer size (9007199254740992) you are asking for trouble: http://ecma262-5.com/ELS5_HTML.htm.
So to solve this problem, you must treat it as a string only. Then extract the last digit in the string and use it to determine whether the number is even or odd.
if(parseInt(("123456789123456789").slice(-1)) % 2)
//odd
else
//even
It's a 64-bit floating point number, using the IEEE 754 specification. A feature of this spec is that starting at 2^53 the smallest distance between two numbers is 2.
var x = Math.pow(2, 53);
console.log( x == x + 1 );
This difference is the value of the unit in the last place, or ULP.
This is similar in principle to trying to store fractional values in integral types in other languages; values like .5 can't be represented, so they are discarded. With integers, the ULP value is always 1; with floating point, the ULP value depends on how big or small the number you're trying to represent.