MDN states:
Numbers in JavaScript are
"double-precision 64-bit format IEEE
754 values", according to the spec.
This has some interesting
consequences. There's no such thing as
an integer in JavaScript, so you have
to be a little careful with your
arithmetic if you're used to math in C
or Java.
This suggests all numbers are floats. Is there any way to use integers, not float?
There are really only a few data types in Javascript: Objects, numbers, and strings. As you read, JS numbers are all 64-bit floats. There are no ints.
Firefox 4 will have support for Typed Arrays, where you can have arrays of real ints and such: https://developer.mozilla.org/en/JavaScript_typed_arrays
Until then, there are hackish ways to store integer arrays as strings, and plucking out each integers using charCodeAt().
I don't think it ever will support integers. It isn't a problem as every unsigned 32 bit integer can be accurately represented as a 64 bit floating point number.
Modern JavaScript engines could be smart enough to generate special code when the numbers are integer (with safeguard checks to make sure of it), but I'm not sure.
Use this:
function int(a) { return Math.floor(a); }
And yo can use it like this:
var result = int(2.1 + 8.7 + 9.3); //int(20.1)
alert(result); //alerts 20
There is zero support for integers. It should be a simple matter of rounding off a variable every time you need it. The performance overhead isn't bad at all.
If you really need to use integers, just use the floor method on each number you encounter.
Other than that, the loose typing of Javascript is one of it's strengths.
Related
I have some data in a node app which are numbers in string format. I'm trying to parse them and round off to 3 decimals by parseFloat(num).toFixed(3). Since the numbers are very large, it is automatically converting them to scientific notation (eg 2.0210702881736412e+37). I switched to using parseInt(), Number() but nothing works. How do I get around this?
The data object is very huge so I'm skeptical to use a custom converter function which converts the exponential form to decimal, since it might impact performance.
Use BigInt
const num = BigInt(2.0210702881736412e+37);
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt
BigInt values are similar to Number values in some ways, but also differ in a few key matters: A BigInt value cannot be used with methods in the built-in Math object and cannot be mixed with a Number value in operations; they must be coerced to the same type. Be careful coercing values back and forth, however, as the precision of a BigInt value may be lost when it is coerced to a Number value.
How you use BigInt for it: BigInt(n).toString();
const num = BigInt(2.0210702881736412e+37);
// 20210702881736411847466551731631947776n
const strNum = num.toString();
// 20210702881736411847466551731631947776
Edit, additional info
Bigint library (or also the builtin data type) can only handle integers. I think try the JavaScript numeric operation library seems to be the fastest way to calculate the decimal point. A bignumber library typically works with arbitrary-precision floating-point numbers. There are several recommended libraries.
bignumber.js Or BigNumber
I have a record
[
"5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY",
1000000000000000000000
],
JSON.stringify() converts it to the form
[
"5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY",
1e+21
],
JSON.stringify() writes it accordingly the same way, can this be somehow solved?
JSON.parse doesn't convert it to 1e+21, it converts it to a number that, when converted to string in the usual way, is output as the string "1e+21". But the number is the same number whether you write it as 1000000000000000000000 or 1e+21.
JSON.stringify may output it in either form; both are valid JSON numbers, and both define exactly the same number.
I should note that you need to beware of numbers of that magnitude in JavaScript (or any other language that uses IEEE-754 double-precision floating point numbers [or single-precision ones, actually]). That number is well into the range where even integers may be imprecisely represented. Any number greater than 9,007,199,254,740,992 (Number.MAX_SAFE_INTEGER + 1) may or may not have a precise representation. It happens that 10,000,00,000,000,000,000,000 (your number) does, but for instance, 9,007,199,254,740,993 doesn't, nor do any odd numbers from that point upward. At some point, you get to where only multiples of 4 can be represented; and then later it's only multiple of 8, etc. See this question's answers for more.
If you still need to get 1e+21 as 1000000000000000000000, you can use (1e+21).toLocaleString().split(',').join('')
but actually, you don't need to convert it if you want to use it as a number, because they are absolutely the same.
Instead, you can keep the number as string and use +'1000000000000000000000' or parseInt('1000000000000000000000') when you need to use it as a number.
Can someone please explain why all these parseInt operations evaluate to the same number 10153593963283296?
parseInt('10153593963283294')
10153593963283294
parseInt('10153593963283295')
10153593963283296
parseInt('10153593963283296')
10153593963283296
parseInt('10153593963283297')
10153593963283296
parseInt('10153593963283298')
10153593963283298
Tested in browsers and node command line.
Thanks!
Your number is larger than Number.MAX_SAFE_INTEGER. JavaScript stores even Integers as floating-point numbers and therefore you lose precision once your number becomes too large.
I assume it's because you've reached the MAX_SAFE_INTEGER.
Please, read this article:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/MAX_SAFE_INTEGER
There's a note:
"The reasoning behind that number is that JavaScript uses double-precision floating-point format numbers as specified in IEEE 754 and can only safely represent numbers between -(253 - 1) and 253 - 1.
Safe in this context refers to the ability to represent integers exactly and to correctly compare them."
I have an interesting question, I have been doing some work with javascript and a database ID came out as "3494793310847464221", now this is being entered into javascript as a number yet it is using the number as a different value, both when output to an alert and when being passed to another javascript function.
Here is some example code to show the error to its fullest.
<html><head><script language="javascript">alert( 3494793310847464221);
var rar = 3494793310847464221;
alert(rar);
</script></head></html>
This has completly baffeled me and for once google is not my friend...
btw the number is 179 more then the number there...
Your number is larger than the maximum allowed integer value in javascript (2^53). This has previously been covered by What is JavaScript's highest integer value that a Number can go to without losing precision?
In JavaScript, all numbers (even integral ones) are stored as IEEE-754 floating-point numbers. However, FPs have limited "precision" (see the Wikipedia article for more info), so your number isn't able to be represented exactly.
You will need to either store your number as a string or use some other "bignum" approach (unfortunately, I don't know of any JS bignum libraries off the top of my head).
Edit: After doing a little digging, it doesn't seem as if there's been a lot of work done in the way of JavaScript bignum libraries. In fact, the only bignum implementation of any kind that I was able to find is Edward Martin's JavaScript High Precision Calculator.
Use a string instead.
179 more is one way to look at it. Another way is, after the first 16 digits, any further digit is 0. I don't know the details, but it looks like your variable only stores up to 16 digits.
That number exceeds (2^31)-1, and that's the problem; javascript uses 32-bit signed integers (meaning, a range from –2,147,483,648 to 2,147,483,647). Your best choice is to use strings, and create functions to manipulate the strings as numbers.
I wouldn't be all too surprised, if there already was a library that does what you need.
One possible solution is to use a BigInt library such as: http://www.leemon.com/crypto/BigInt.html
This will allow you to store integers of arbitrary precision, but it will not be as fast as standard arithmetic.
Since it's to big to be stored as int, it's converted to float. In JavaScript ther is no explicit integer and float types, there's only universal Number type.
"Can't increment and decrement a string easily..."
Really?
function incr_num(x) {
var lastdigit=Number(x.charAt(x.length-1));
if (lastdigit!=9) return (x.substring(0,x.length-1))+""+(lastdigit+1);
if (x=="9") return "10";
return incr_num(x.substring(0,x.length-1))+"0";
}
function decr_num(x) {
if(x=="0") return "(error: cannot decrement zero)";
var lastdigit=Number(x.charAt(x.length-1));
if (lastdigit!=0) return (x.substring(0,x.length-1))+""+(lastdigit-1);
if (x=="10") return "9"; // delete this line if you like leading zero
return decr_num(x.substring(0,x.length-1))+"9";
}
Just guessing, but perhaps the number is stored as a floating type, and the difference might be because of some rounding error. If that is the case it might work correctly if you use another interpreter (browser, or whatever you are running it in)
Some of my data are 64-bit integers. I would like to send these to a JavaScript program running on a page.
However, as far as I can tell, integers in most JavaScript implementations are 32-bit signed quantities.
My two options seem to be:
Send the values as strings
Send the values as 64-bit floating point numbers
Option (1) isn't perfect, but option (2) seems far less perfect (loss of data).
How have you handled this situation?
There is in fact a limitation at JavaScript/ECMAScript level of precision to 53-bit for integers (they are stored in the mantissa of a "double-like" 8 bytes memory buffer). So transmitting big numbers as JSON won't be unserialized as expected by the JavaScript client, which would truncate them to its 53-bit resolution.
> parseInt("10765432100123456789")
10765432100123458000
See the Number.MAX_SAFE_INTEGER constant and Number.isSafeInteger() function:
The MAX_SAFE_INTEGER constant has a value of 9007199254740991. The
reasoning behind that number is that JavaScript uses double-precision
floating-point format numbers as specified in IEEE 754 and can only
safely represent numbers between -(2^53 - 1) and 2^53 - 1.
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. See
Number.isSafeInteger() for more information.
Due to the resolution of floats in JavaScript, using "64-bit floating point numbers" as you proposed would suffer from the very same restriction.
IMHO the best option is to transmit such values as text. It would be still perfectly readable JSON content, and would be easy do work with at JavaScript level.
A "pure string" representation is what OData specifies, for its Edm.Int64 or Edm.Decimal types.
What the Twitter API does in this case, is to add a specific ".._str": field in the JSON, as such:
{
"id": 10765432100123456789, // for JSON compliant clients
"id_str": "10765432100123456789", // for JavaScript
...
}
I like this option very much, since it would be still compatible with int64 capable clients. In practice, such duplicated content in the JSON won't hurt much, if it is deflated/gzipped at HTTP level.
Once transmitted as string, you may use libraries like strint – a JavaScript library for string-encoded integers to handle such values.
Update: Newer versions of JavaScript engines include a BigInt object class, which is able to handle more than 53-bit. In fact, it can be used for arbitrarily large integers, so a good fit for 64-bit integer values. But when serializing as JSON, the BigInt value will be serialized as a JSON string - weirdly enough, but for compatibility purposes I guess.
This seems to be less a problem with JSON and more a problem with Javascript itself. What are you planning to do with these numbers? If it's just a magic token that you need to pass back to the website later on, by all means simply use a string containing the value. If you actually have to do arithmetic on the value, you could possibly write your own Javascript routines for 64-bit arithmetic.
One way that you could represent values in Javascript (and hence JSON) would be by splitting the numbers into two 32-bit values, eg.
[ 12345678, 12345678 ]
To split a 64-bit value into two 32-bit values, do something like this:
output_values[0] = (input_value >> 32) & 0xffffffff;
output_values[1] = input_value & 0xffffffff;
Then to recombine two 32-bit values to a 64-bit value:
input_value = ((int64_t) output_values[0]) << 32) | output_values[1];
Javascript's Number type (64 bit IEEE 754) only has about 53 bits of precision.
But, if you don't need to do any addition or multiplication, then you could keep 64-bit value as 4-character strings as JavaScript uses UTF-16.
For example, 1 could be encoded as "\u0000\u0000\u0000\u0001". This has the advantage that value comparison (==, >, <) works on strings as expected. It also seems straightforward to write bit operations:
function and64(a,b) {
var r = "";
for (var i = 0; i < 4; i++)
r += String.fromCharCode(a.charCodeAt(i) & b.charCodeAt(i));
return r;
}
The JS number representation is a standard ieee double, so you can't represent a 64 bit integer. iirc you get maybe 48 bits of actual int precision in a double, but all JS bitops reduce to 32bit precision (that's what the spec requires. yay!) so if you really need a 64bit int in js you'll need to implement your own 64 bit int logic library.
JSON itself doesn't care about implementation limits.
your problem is that JS can't handle your data, not the protocol.
In other words, your JS client code has to use either of those non-perfect options.
This thing happened to me. All hell broke loose when sending large integers via json into JSON.parse. I spent days trying to debug. Problem immediately solved when i transmitted the values as strings.
Use
{ "the_sequence_number": "20200707105904535" }
instead of
{ "the_sequence_number": 20200707105904535 }
To make it worse, it would seem that where every JSON.parse is implemented, is some shared lib between Firefox, Chrome and Opera because they all behaved exactly the same. Opera error messages have Chrome URL references in it, almost like WebKit shared by browsers.
console.log('event_listen[' + global_weird_counter + ']: to be sure, server responded with [' + aresponsetxt + ']');
var response = JSON.parse(aresponsetxt);
console.log('event_listen[' + global_weird_counter + ']: after json parse: ' + JSON.stringify(response));
The behaviour i got was the sort of stuff where pointer math went horribly bad. Ghosts were flying out of my workstation wreaking havoc in my sleep. They are all exorcised now that i switched to string.