javascript - What are my client-side options? - javascript

I love javascript, don't get me wrong, but my problem is I currently want to develop open source web applications for scientific computations and javascript's arithmetic isn't exactly the most precise. I've scripted server-side, but I prefer client-side for the obvious reasons that the experience for the user is generally smoother and there is less load on the server.
What are my options as far as working around this issue? I've read somewhere that you can implement languages on top of javascript--would this be worth it and what does this look like? If I do, say, implement python on top of javascript, does that mean the client needs a python interpreter to use the site?
I just can't handle
0.1 + 0.2 == 0.3 // is False

Floating points operations are approximated calculations
This is not wrong see more about it
Weird programing behavior
THis is not specific to javascript but common in programming as a whole
Here is what i get on chrome:
0.1 + 0.2 = 0.30000000000000004;
And here is a simple but excellent read on the subject:
What Every Programmer Should Know About Floating-Point Arithmetic
Why don’t my numbers, like 0.1 + 0.2 add up to a nice round 0.3, and instead I get a weird result like 0.30000000000000004?
Because internally, computers use a format (binary floating-point)
that cannot accurately represent a number like 0.1, 0.2 or 0.3 at all.
When the code is compiled or interpreted, your “0.1” is already
rounded to the nearest number in that format, which results in a small
rounding error even before the calculation happens.

There are a few libraries that allow for much better mathematical operations:
Big Number
Big Js (Different library)
However, I would very strongly suggest doing this server side. You could easily do it via AJAX and not have to worry about responsiveness. Javascript just wasn't really built for numbers.

Related

Working with accurate currency values in Javascript

I'm working on a system that uses financial data. I'm getting subtle rounding errors due to the use of floating point numbers. I'm wondering if there's a better way to deal with this.
One of the issues is that I'm working with a mixture of different currencies, which might have up to 12 decimals, and large numbers for other currencies.
This means that the smallest number I need to represent is 0.000000000001 * (1*10^-12) and the largest 100,000,000,000 (1*10^11).
Are there any recommended ways to work with numbers of this size and not lose precision?
If you're really trying to stay in the JS realm you might consider Decimal.js which should cover your precision range.
If I were writing this and needed to make sure there were no rounding errors I would likely try and use a GMP extension for another lang inside a microservice which was only tasked with the financial math. GMPY2 for Python3 is probably a good bet for something quick and easy.

Can javascript be trusted when making calculations?

I am implementing an invoice system, where everything is dynamically added on the dom through javascript and I am making some calculations on the browser itself with javascript.
for eg I am calculating each invoice line with quantity and price of unit and generating a total sum
price can be a floating point number
but I am not sure if this should be trusted or not, if someone has the same toughts about javascript please comment :)
I don't know but javascript doesn't seem to me to be trusted like other programming languages like PHP or so, this is my opinion, but if you can convince me please do
Thanks
Javascript uses the same data type that almost all languages use for floating point calculations. The double precision floating point data type is very common, because processors have built in support for it.
Floating point numbers have a limited precision, and most numbers with a fractional part can't be represented exactly. However, for what you are going to use it for, the precision is more than enough to show a correct result.
You should just be aware of the limited precision. When displaying the result, you should make sure that it's formatted (and rounded) to the precision that you want to show. Otherwise the limited precision might show up as for example a price of 14.9500000000000001 instead 14.95.
According to JavaScript's specifications, all numbers are 64bit precision (as in 64bit floating point precision).
From this post, you have 3 solutions:
use some implementation of Decimal for JavaScript, as BigDecimal.js
just choose a fixed number of digits to keep, like this (Math.floor(y/x) * x).toFixed(2)
switch to pure integers, treating prices as number of cents. This could lead you to big changes across the whole project
Financial calculations usually require specific fixed rules about (for example) when and how to round (in which direction), etc.
That means you'll often maintain an internal sub-total precision until you move to a next section of your calculation (like adding the tax, as per rules set).
IEEE-754 Floating point (as used in javascript) will give you a maximum accuracy of 2^53 (if you think about it like an integer).
Now your 'job' is to pretend javascript doesn't support floating point and substitute it yourself using the simplest possible way: decrease your maximum integer range to obtain the required floating point precision and see if that resulting range is suitable to your needs. If not, then you might need an external high precision math library (although most basic operations are pretty easy to implement).
First determine your desired internal precision (incl overflow digit for your expected rounding behavior): for example 3 digits:
FLOOR((2^53)/(10^3))=FLOOR(9.007.199.254.740.992/1000)=9.007.199.254.740,000
If this range is sufficient, then you need no other library, just multiply your input 10^float_digits and maintain that internal precision per calculation-section, while rounding each step according to the rules required for your calculation (you'd still need to do that when using a high-precision external math library).
For (visual) output, again, apply proper rounding and just divide your remaining value by 10^(floatDigits-roundingDigit(s)) and pass it through Number.prototype.toFixed() (which then just pads zero's when required).
As to your other question regarding trustworthiness of javascript vs other programming languages: one can even boot/run and use LINUX on javascript inside the browser: http://bellard.org/jslinux/
Let that sink in for a moment...
Now what if I told you this even works in IE6... Pretty humbling. Even servers can run on javascript (node.js)..
Hope this helps (it didn't fit in a comment).
Other answers have addressed issues that JavaScript has with using floating point numbers to represent money.
There's a separate issue with using JavaScript for calculations involving financial transactions that comes to mind.
Because the code is executed in a browser on the client machine, You can only trust the result to the extent that you can trust the client.
Therefore you should really only rely on JavaScript to calculate something that you could take for granted if the client told you.
For instance, if you were writing an e-commerce site, you could trust code that told you what the client wanted to buy, and what the clients shipping address was, but you would need to calculate the price of the goods yourself to prevent the client from telling you a lower price.
It's entirely possible that the invoicing system you're working on will only be used internally to your organisation.
If this is the case, you can disregard this entire answer.
But, if your applications is going to be used by customers to access and manipulate their invoices and orders, then this is something you'd have to consider.

Another floating point question

I have read most of the posts on here regarding floating point, and I understand the basic underlying issue that using IEEE 754 (and just by the nature of storing numbers in binary) certain fractions cannot be represented. I am trying to figure out the following: If both Python and JavaScript use the IEEE 754 standard, why is it that executing the following in Python
.1 + .1
Results in
0.20000000000000001 (which is to be expected)
Where as in Javascript (in at least Chrome and Firefox) the answer is .2
However performing
.1 + .2
In both languages results in
0.30000000000000004
In addition, executing
var a = 0.3; in JavaScript and printing a results in
0.3
Where as doing a = 0.3 in Python results in 0.29999999999999999
I would like to understand the reason for this difference in behavior.
In addition, many of the posts on OS link to a JavaScript port of Java's BigDecimal, but the link is dead. Does anyone have a copy?
doing a = 0.3 in Python results in
0.29999999999999999
Not quite -- watch:
>>> a = 0.3
>>> print a
0.3
>>> a
0.29999999999999999
As you see, printing a does show 0.3 -- because by default print rounds to 6 or 7 decimal digits, while typing an expression (here a is a single-variable expression) at the prompt shows the result with over twice as many digits (thus revealing floating point's intrinsic limitations).
Javascript may have slightly different rounding rules about how to display numbers, and the exact details of the rounding are plenty enough to explain the differences you observe. Note, for example (on a Chrome javascript console):
> (1 + .1) * 1000000000
1100000000
> (1 + .1) * 100000000000000
110000000000000.02
see? if you manage to see more digits, the anomalies (which inevitably are there) become visible too.
and printing.
They might both have the same IEEE 754 underlying representation, but that doesn't mean they're forced to print the same way. It looks like Javascript is rounding the output when the difference is small enough.
With floating point numbers, the important part is how the binary data is structured, not what it shows on the screen.
I would like to understand the reason for this difference in behavior.
They're different languages.
They use different underlying packages.
They have different implementations.
When you say "Python" -- which implementation are you talking about? C, Jython, IronPython? Did you compare each of those?
The Javascript folks seem to handle repeating binary fractions differently from the way the Python folks handle repeating binary fractions.
Sometimes Javascript quietly suppresses the error bits at the end. Sometimes it doesn't.
That's the reason.
You have the source code for both. If you want to know more, you can. Knowing the source code doesn't change much, however.

Why am I seeing inexact floating-point results in ECMAScript / ActionScript 3?

Hey all, let's jump straight to a code sample to show how ECMAScript/JavaScript/AS3 can't do simple math right (AS3 uses a 'IEEE-754 double-precision floating-point number' for the Number class which is supposedly identical to that used in JavaScript)...
trace(1.1); //'1.1': Ok, fine, looks good.
trace(1.1*100); //'110.00000000000001': What!?
trace((1.1*100)/100); //'1.1': Brings it back to 1.1 (since we're apparently multiplying by *approximately* 100 and then dividing by the same *approximate* '100' amount)
trace(1.1*100-110); //'1.4210854715202004e-14': Proof that according to AS3, 1.1*100!=110 (i.e. this isn't just a bug in Number.toString())
trace(1.1*100==110); //'false': Even further proof that according to AS3, 1.1*100!=110
What gives?
Welcome to the wonderful world of floating point calculation accuracy. In general, floating point calculations will give you results that are very very nearly correct, but comparing outputs for absolute equality is unlikely to give you results you expect without the use of rounding functions.
This is just a side effect of using floating point numbers - these are binary representations of decimal numbers, there will always be some approximations.
Long explanation
Floating point inconsistencies are a known problem in many languages. This is because computers aren't designed to handle floating point numbers.
Have fun
As moonshadow states, you're running into issues with floating point precision. Floating point numbers aren't suited to the task of representing and performing arithmetic upon decimal values in the manner that you would expect. These kinds of problems are seen most often when people try to using floating point numbers for financial calculations. The wikipedia entry is good, but you might get more out of this page, which steps through an error-prone financial calculation: http://c2.com/cgi/wiki?FloatingPointCurrency
To accurately deal with decimal numbers you need a decimal library. I've outlined two BigDecimal-style libraries written in javascript that may suit your needs in another SO post, hopefully you'll find them useful:
https://stackoverflow.com/questions/744099/javascript-bigdecimal-library/1575569

Is there a definitive solution to javascript floating-point errors?

I write line of business applications. I'd like to build a front-end end using Javascript and am trying to figure out how to deal with, for a business user, are floating point errors (I understand from a computer science perspective they might not be considered errors). I've read plenty on this and seen all kinds of rounding hacks that work on examples given but seem prone to break down unexpectedly. Is there a definitive way to do decimal math in javascript?
According to Douglas Crockford, the only way around this problem is scale your values to integer. Make sure it really is an integer by using Math.round on the scaled value. (DC does not talk about the rounding part, but I discovered it was necessary. e.g. Math.round(1.1 *100)) Do calculation(s). When you are done with the math scale back to original precision. See JavaScript: The Good Parts "Floating Point" section.
One answer is to do the math in decimal instead of binary. Then you never have to worry about the decimal <=> binary conversion errors. You'd represent the numbers as binary digits in an array or a string and write the math routines yourself.
Here are some bignumber libraries you can look into if you don't want to go to that trouble:
http://jsfromhell.com/classes/bignumber
http://stz-ida.de/html/oss/js_bigdecimal.html.en
the only definite solution seems to be writing your own arbitrary precision number type working on strings internally -- which will be complicated and horribly slow.

Categories

Resources