JavaScript and Numeric Precision

When dealing with numbers, there can sometimes be a discrepancy between numbers that are stored in databases and the numbers that are defined in JavaScript. Understanding this discrepancy is important if you deal with very large numbers (greater than about 1017) or very precise numbers (with a precision of less than about 10-10).
lac31
When dealing with numbers, there can sometimes be a discrepancy between numbers that are stored in databases and the numbers that are defined in JavaScript. Understanding this discrepancy is important if you deal with very large numbers (greater than about 1017) or very precise numbers (with a precision of less than about 10-10).
Numbers in Databases
Most databases support very large and very precise numbers. For instance, MySQL supports decimal numbers up to 65 digits:
create table HugeNumbers(
  ident int primary key,
  huge_number decimal(65,20)
) ENGINE=InnoDB;
In this example table, very large numbers and numbers with a lot of precision are stored, with up to 45 digits before the decimal point, and up to 20 digits after:
insert into HugeNumbers (ident, huge_number) values (1, 123456789012345678901234567890123456789012345.99999999999999999999);
insert into HugeNumbers (ident, huge_number) values (2, 123456789012345678901234567890123456789012345.99999999999999999998);
insert into HugeNumbers (ident, huge_number) values (3, 0.00000000000000000001);
In addition, some databases support other values, such as infinity and NaN (Not a Number). Typically, you cannot manipulate these values from JavaScript.
Numbers in JavaScript
In JavaScript, all numbers are IEEE 754 double-precision. This has significant consequences if you try to manipulate very large or very precise numbers, because you might experience a loss of precision.
For example, if you retrieve the value for row 1, the resulting number might not be what you might have expected:
out.println("huge_number is: " + row.huge_number);
// Output: huge_number is: 1.2345678901234567e+44
This resulting value is not the full value. All digits beyond the 17th digit are now assumed to be 0, and the decimal part has been lost. The number was converted to a JavaScript number, thereby losing precision. This is a well-known problem with IEEE floating-point numbers.
As another example, the values for row 1 and 2 would be considered equal in JavaScript, even though the two numbers do in fact differ by 0.00000000000000000001.
Use the Underlying Java Number Types
If you deal with very large or very precise numbers, avoid using JavaScript numbers and use the underlying Java number types, which do not suffer from loss of precision.
The following is a simple example:
var huge_number = row.getRawObject("huge_number");
out.println("huge_number is now: " + huge_number);
// Output: huge_number is now: 123456789012345678901234567890123456789012345.99999999999999999999
This time, there was no loss of precision, and the number is exactly correct. However, the price to pay for this is that the value is no longer a JavaScript number, but rather a number object (more specifically, in this case, a object). If your database column is defined as a decimal type, and you retrieve its value using the 
getRawObject()
 method, it will be represented as a
BigDecimal
object. If it is defined as an integer type, it will be represented as a java.math.BigInteger number.
Using the
java.math.BigDecimal
number object is more ponderous than using the built-in JavaScript number type, which is why this is not done by default.
To avoid any precision loss, you must do all operations on these number objects using the methods that are defined on the underlying Java class, for example:
var huge = row.getRawObject("huge_number");
var BigDecimal = Java.type("java.math.BigDecimal");
var multiplier = new BigDecimal("1.1234567890123456789");
var result = huge.multiply(multiplier);
out.println("Multiplication result: " + result);
// Output: Multiplication result: 138698367765584515651577503665157750366515775.397392165471851699388765432109876543211
The Dark Side of Precision
Unfortunately, precision is never infinite. In the previous example, we multiplied two numbers together and got an exact result, with all 39 decimal digits. But you cannot store that number with full precision in the database, because in our example, we only specified 20 decimal digits. Therefore there will still be a loss of precision if you store this result in the database. This is unavoidable.
In addition, you cannot store numbers such as 10/3 with perfect precision, no matter how many decimals you specify. Once again, there will be a loss of precision that cannot be avoided.
When calling your
Layer7 Live API Creator
 REST API, the resulting JSON (or XML) will always contain the values stored in the database. If you process this in JavaScript, or any language that uses floating-point numbers to parse JSON (or XML), you might lose some precision. You could even encounter an error because the number is too large for the data type. You must address this in the client code.