i have issue with floating point rounding in javascript. As far as i know number in javascript are IEEE-754 floating point under the hood (no option about that), so not all integer value are allowed due to rounding.
For example the following code will produce this value as output -> "637889210422071800" instead of "637889210422071841" as one should expect
document.writeln(parseFloat("637889210422071841"));
document.writeln("<br>");
document.writeln(parseInt("637889210422071841",10));
Problem is that this number (basically a clock) is served in a rest api response, but when i try read the resposne i get the wrong value (probably due to some implicit deserialization over javascript object).
Luckily i have control over the rest api, so i can change how the clock is encoded.
So first option come to my mind is to change the clock format and make it a string, so that i can read the real value from javascript (i have still to interpret it, but at least the value is preserved, so this solution is a bit tricky and is not my first choiche).
Another option i think about is to decrease the size of my clock, reducing it's sensibility, basically instead of use "6378892104220718|41" i will truncate it to "6378892104220718". I prefer the second option, but i am concerned about the fact that maybe the rounding error are not uniformly distributed (due to base-exponent structure of IEEE-754 numbers).
So i would like to ask which if there is a way to handle situation like that in javascript, and if there is not a best practice, i would like to ask if reduced clock version will solve my issue.
Related
In javascript, we know that some floating point arithmetic will result in values that contain a very small remainder. for example if I open my console and do this math I get this result as seen here
Typically one must know to round after doing these operations. When using parse, and using the increment function. If I have a column called Quantity in my DB and it currently has a value of 6.5 and I call myobject.increment("Quantity", -4.1) we end up with an unrounded value in the DB. the use of increment is required here as many entities may be adjusting this column at or near the same time, so race conditions are a concern.
since the arithmetic happens under the hood, how does parse expect one to handle cases like I mentioned above.
You may do one of two:
Change the logic inside increment function.
Do increment outside and use some setter.
Anyway in case you want to prevent non exact values, you should round it manually. Look here for number rounding answer
After doing a lot of looking around, I don't have to describe the precision problem that is apparent in the coding community. However, most solutions rely on converting the number to a string. In my case, that is not an option since I am using an API which requires the passed in number to be well.. a number. And every time I get the imperfect precision the API shoots out an error breaking my application's functionality. Simply catching the error is not really a solution, since I still have to submit the value and the value will not be changing. Here's what I am currently using and it seems to work for the most part, but every once in a while I'm not so lucky, if anyone has an idea of how to work around this all comments will be appreciated!
let rounded = Math.round((n + Number.EPSILON) * Math.round(Math.pow(10, precision))) / Math.round(Math.pow(10, precision))
let fixed = rounded.toFixed(precision)
return Number(fixed)
Side note, both rounded and fixed can cause the same issue, I've tried it both ways, and desired precision is from 2 to 8 depends on the circumstance, I've also tried it with and without EPSILON, I've tried truncating, rounding, nothing seems to work, and I need a number at the end not a string...
decimal.js
Use decimal.js for mathematically precise computations. Similar solutions are available.
Your issues are a known fact about using floating point numbers in programming in general.
You can find more help and tutorials about decimal.js online. Have a look:
https://github.com/MikeMcl/decimal.js/
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.
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.
The ADsafe subset of Javascript prohibits the use of certain things that are not safe for guest code to have access to, such as eval, window, this, with, and so on.
For some reason, it also prohibits the Date object and Math.random:
Date and Math.random
Access to these sources of non-determinism is restricted in order to make it easier to determine how widgets behave.
I still don't understand how using Date or Math.random will accomodate malevolence.
Can you come up with a code example where using either Date or Math.random is necessary to do something evil?
According to a slideshow posted by Douglas Crockford:
ADsafe does not allow access to Date or random
This is to allow human evaluation of ad content with confidence that
behavior will not change in the future. This is for ad quality and
contractual compliance, not for security.
I don't think anyone would consider them evil per se. However the crucial part of that quote is:
easier to determine how widgets behave
Obviously Math.random() introduces indeterminism so you can never be sure how the code would behave upon each run.
What is not obvious is that Date brings similar indeterminism. If your code is somehow dependant on current date it will (again obviously) work differently in some conditions.
I guess it's not surprising that these two methods/objects are non-functional, in other words each run may return different result irrespective to arguments.
In general there are some ways to fight with this indeterminism. Storing initial random seed to reproduce the exact same series of random numbers (not possible in JavaScript) and supplying client code with sort of TimeProvider abstraction rather than letting it create Dates everywhere.
According to their website, they don't include Date or Math.random to make it easier to determine how third party code will behave. The problem here is Math.random (using Date you can make a psuedo-random number as well)- they want to know how third party code will behave and can't know that if the third party code is allowed access to random numbers.
By themselves, Date and Math.random shouldn't pose security threats.
At a minimum they allow you to write loops that can not be shown to be non-terminating, but may run for a very long time.
The quote you exhibit seem to suggest that a certain amount of static analysis is being done (or is at least contemplated), and these features make it much harder. Mind you these restrictions aren't enough to actually prevent you from writing difficult-to-statically-analyze code.
I agree with you that it's a strange limitation.
The justification that using date or random would make difficult to predict widget behavior is of course nonsense. For example implement a simple counter, compute the sha-1 of the current number and then act depending on the result. I don't think it's any easier to predict what the widget will do in the long term compared to a random or date... short of running it forever.
The history of math has shown that trying to classify functions on how they compute their value is a path that leads nowhere... the only sensible solution is classifying them depending on the actual results (black box approach).