BigDecimal from json loses precision - javascript

The network call shows that the backend is sending this:
"uom" : "EA",
"qty" : 1.123456789012345678
but when it reaches the frontend, using console.log:
{
qty: 1.1234567890123457,
uom: "EA"
}
why is the javascript losing the last digit or truncating the number?
The number is represented using a BigDecimal in java. The frontend use AngularJs framework, makes a GET call to the backend requesting a JSON.

Javascript floating point numbers hold 64 bits of precision, similar to a double in Java. If you have to use BigDecimal in Java to extend beyond that level of precision, you'll need to do something similar in Javascript to extend beyond its similar boundary. The NPM package js-big-decimal is probably your best bet and you can transfer the values as strings in JSON to prevent JSON.parse from interpreting them as Number.

Thanks for the help. I found that adding
#JsonSerialize(using = ToStringSerializer.class)
public getQty(){
return this.qty;
}
to the java domain object solves the issue.

Related

JavaScript misinterpretes number

I perform an AJAX call to generate an ID. This ID is sent back to the client in the response and shown in an input field. I was made aware that the ID displayed in the browser is not the one generated - the last digit differs. On the serverside I serialize data to pass it back to the client using Adobe ColdFusion's own serializeJSON() function. It recognizes the sequence of digits and serializes it as a number. I logged the contents of my variables on different places in my codde, it looked fine all the way. Only the browser does not do what I want/expect.
I boiled it down to this simple sample:
var stru = {"MYID":2761602017000540006};
console.dir(stru);
The console logs 2761602017000540000 instead of 2761602017000540006
Why is that? Is this number too large to be stored in JavaScript?
Is the number too large to be stored in JavaScript?
Yes, the max safe integer is 9,007,199,254,740,991 and the number you're attempting to send is 2,761,602,017,000,540,006 (which is a factor of ~1000x larger).
This is because the JavaScript number type follows the IEEE 754 64-bit floating point number format, which doesn't allow as for as large of numbers as a 64-bit integer normally would. You can see the definition of the number type value here in the ECMAScript spec 4.3.20.
I suggest you send the ID over as a String.
In JavaScript, one has at most 53 bits for integers. so you can not put integers larger that 53bits into javascript variables, so the other way is to use strings for saving this long id . I hope that this help you
As Arash said, your number is too long (more than 53 bits).
You can have more information on this topic: Javascript long integer
The only solution seems to be using string instead of numbers

converting LARGE string to an integer [duplicate]

How do I parse a 20-digit number using JavaScript and jQuery?
A 20-digit number is generally too big for a JavaScript native numeric type, so you'll need to find a "big number" package to use. Here's one that I've seen mentioned on Stack Overflow and that looks interesting: http://silentmatt.com/biginteger/
That one is just integers. If you need decimal fractions too, you'll have to find something else.
If you just want to check that a 20-digit string looks like a number, and you don't need to know the value, you can do that with a regular expression.
You can't have a 20-digit number in JavaScript - it'll get floated off on you.
You can keep 20 digits (or 200 or 2000) intact as a string, or as an array of digits, but to do any math on it you need a big integer object or library.
Normally you use Number() or parseInt("", [radix]) to parse a string into a real number.
I am guessing you are asking about what happens when the string you parse is above the int - threshold. In this case it greatly depends on what you are trying to accomplish.
There are some libraries that allow working with big numbers such as https://silentmatt.com/biginteger/ - see answer - (did not test it, but it looks OK). Also try searching for BigInt JavaScript or BigMath.
In short: working with VERY large number or exact decimals is a challenge in every programming language and often requires very specific mathematical libraries (which are less convenient and often a lot slower than when you work in "normal" (int/long) areas) - which obviously is not an issue when you REALLY want those big numbers.

Handling 64-bit numbers using AngularJS' $http.get()

In my Angular app I am making a $http.get() request to a URL that is responding with a json object. This object contains a value that is occasionally a very large number (e.g. 9106524608436223400). Looking at the network profiler in Chrome I can see that the number is coming down properly but when $http.get() has it's callback hit the number will be corrupted somewhat. I assume this is because the number is very large and not a string. Is there any way to get Angular to handle this response correctly or do I need to wrap my server's output as a string? Thanks.
Numbers in JavaScript are double precision floating point numbers. This means that they can only handle integer numbers with full precision up to 52 bits.
Any code for parsing the JSON that will represent the number as a regular number in JavaScript will be unable to give you the unchanged value.
The JSON standard doesn't specify any limitation for the range or precision for numbers. However, as JSON is based on a subset of the JavaScript syntax, one could argue that the format doesn't support numbers outside of what could be represented in JavaScript.
To safely get the value unchanged, you would need to put it as a string in the JSON, or split it up into two or more smaller numbers.

GWT's JSONParser producing incorrect values for numbers

I'm work with GWT and parsing a JSON result from an ASP.NET webservice method that returns a DataTable. I can parse the result into a JSONvalue/JSONObject just fine. The issue I'm having is that one my columns in a DECIMAL(20, 0) and the values that are getting parsed into JSON aren't exact. To demonstrate w/o the need for a WS call, in GWT I threw this together:
String jsonString = "{value:4768428229311981600}";
JSONObject jsonObject = JSONParser.parse( jsonString ).isObject();
Window.alert( jsonObject.toString() );
This in turn alerts:
{"value":4768428229311982000}
I'm under the understanding that GWT's JSONParser is just using eval() to do the parsing, so is this some sort of number/precision issue with JavaScript that I've never been aware of. I'll admit I don't work with numbers that much in JavaScript and I might be able to work around this by changing the .NET WebService to return this column as string, but I'd really rather not do that.
Thanks for any help.
There was a similar question I answered sometime ago - Arbitrary precision in GWT
A more up to date answer is that BigDecimal support looks on track for GWT 2.1
Until then, if you don't need to do calculation with the numbers client side, I recommend passing them around as strings.
Additionally, looking at your example, you could transfer them as strings and maybe use the emulated GWT java.lang.Long.
Last ditch, you can try the svn version of BigDecimal GWT-Math - it shouldn't be all that bad to drop the java files into your jar (It would not need to be compiled, since it's all emul code)
If you go that route, you would still have to pass the numbers as JSON strings, but you could perform meaningful math.
Well, Javascript just uses ordinary IEEE 754 64-bit floating point, so there's an inherent precision limit. The language does not provide support for arbitrary-sized integers (or, really, any pure integer at all). You're going to have to use a string representation when you need to manipulate the values in Javascript, and hopefully you won't have to do any math.
edit: I've looked before at this: http://www-cs-students.stanford.edu/~tjw/jsbn/
It seems like a fairly hairy solution if you don't need to do much manipulating of the numbers, but it might be worth looking at. There may be less ambitious variations on that idea out there.
In any case, that's not going to help you with straight interpretation of JSON unless you also wired up a variant JSON parser to construct numeric values using such a library.

JavaScript 64 bit numeric precision

Is there a way to represent a number with higher than 53-bit precision in JavaScript? In other words, is there a way to represent 64-bit precision number?
I am trying to implement some logic in which each bit of a 64-bit number represents something. I lose the lower significant bits when I try to set bits higher than 2^53.
Math.pow(2,53) + Math.pow(2,0) == Math.pow(2,53)
Is there a way to implement a custom library or something to achieve this?
Google's Closure library has goog.math.Long for this purpose.
The GWT team have added a long emulation support so java longs really hold 64 bits. Do you want 64 bit floats or whole numbers ?
I'd just use either an array of integers or a string.
The numbers in javascript are doubles, I think there is a rounding error involved in your equation.
Perhaps I should have added some technical detail. Basically the GWT long emulation uses a tuple of two numbers, the first holding the high 32 bits and the second the low 32 bits of the 64 bit long.
The library of course contains methods to add stuff like adding two "longs" and getting a "long" result. Within your GWT Java code it just looks like two regular longs - one doesn't need to fiddle or be aware of the tuple. By using this approach GWT avoids the problem you're probably alluding to, namely "longs" dropping the lower bits of precision which isn't acceptable in many cases.
Whilst floats are by definition imprecise / approximations of a value, a whole number like a long isn't. GWT always holds a 64 bit long - maths using such longs never use precision. The exception to this is overflows but that accurately matches what occurs in Java etc when you add two very large long values which require more than 64 bits - eg 2^32-1 + 2^32-1.
To do the same for floating point numbers will require a similar approach. You will need to have a library that uses a tuple.
The following code might work for you; I haven't tested it however yet:
BigDecimal for JavaScript
Yes, 11 bit are reserved for exponent, only 52 bits containt value also called fraction.
Javascript allows bitwise operations on numbers but only first 32 bits are used in those operations according to Javascript standard specification.
I do not understand misleading GWT/Java/long answers in Javascript/double question though? Javascript is not Java.
Why would anyone need 64 bit precision in javascript ?
Longs sometimes hold ID of stuff in a DB so its important not to lose some of the lower bits... but floating point numbers are most of the time used for calculations. To use floats to hold monetary or similar exacting values is plain wrong. If you truely need 64 bit precision do the maths on the server where its faster and so on.

Categories

Resources