Hello and welcome to our community! Is this your first visit?
Register
Enjoy an ad free experience by logging in. Not a member yet? Register.
Results 1 to 10 of 10
  1. #1
    New Coder
    Join Date
    Mar 2012
    Posts
    60
    Thanks
    65
    Thanked 0 Times in 0 Posts

    help with safe decimal maths

    Hi

    I have read that doing maths in JavaScript if decimals and rounding are involved is not accurate.

    So how would you approach this to have an accurate answer every time.

    a and b below might not always have the same number of decimal places but the answer must always have 3 decimal places


    var a = 123.12345
    var b = 123456.1234567

    var c = a * b

    var d = a / b

    The answer of c and d must always have three decimal places.



    How do I do this accurately?




    Thanks for the help


    PS is this accurate:
    http://www.mredkj.com/javascript/nfbasic2.html
    Last edited by code-in-time; 05-30-2012 at 05:36 AM.

  • #2
    Supreme Master coder! Philip M's Avatar
    Join Date
    Jun 2002
    Location
    London, England
    Posts
    17,732
    Thanks
    202
    Thanked 2,508 Times in 2,486 Posts
    Use .toFixed(3).

    Code:
    <script type = "text/javascript">
    
    var a = 123.12345
    var b = 123456.1234567
    var c = (a*b).toFixed(3);  //  15200343.844
    alert (c);
    var d = (a/b).toFixed(3);  // 0.001
    alert (d);
    
    </script>

    ECMAScript numbers are represented in binary as IEEE-754 (IEC 559) Doubles, with a resolution of 53 bits, giving an accuracy of 15-16 decimal digits; integers up to just over 9e15 are precise, but few decimal fractions are. Given this, arithmetic is as exact as possible, but no more. Operations on integers are exact if the true result and all intermediates are integers within that range.

    If you need an exact answer to a set number of decimal places then shift the decimal point in all your numbers that many places to the right to make integers before doing the calculation and then shift it back after the calculation. For example with currencies that use two decimal places you should always multiply them all by 100 at the start and divide by 100 at the end or the answer might not be exact.

    Example:-

    Code:
    <script type = "text/javascript">
    var a = 0.06;
    var b = 0.01;
    var c = a + b;
    alert (c);  //0.06999999999999999 
    alert (c.toFixed(2));  // 0.07 -  Note that the output of .toFixed() is a string, not a number;
    var d = ((a*100) + (b*100))/100;
    alert (d);   // 0.07
    </script>

    All advice is supplied packaged by intellectual weight, and not by volume. Contents may settle slightly in transit.
    Last edited by Philip M; 05-30-2012 at 07:48 AM.

    All the code given in this post has been tested and is intended to address the question asked.
    Unless stated otherwise it is not just a demonstration.

  • Users who have thanked Philip M for this post:

    code-in-time (06-08-2012)

  • #3
    Master Coder felgall's Avatar
    Join Date
    Sep 2005
    Location
    Sydney, Australia
    Posts
    6,472
    Thanks
    0
    Thanked 634 Times in 624 Posts
    Quote Originally Posted by code-in-time View Post
    I have read that doing maths in JavaScript if decimals and rounding are involved is not accurate.
    Substitute any other programming language for JavaScript in that statement and the statement will still be true. The only difference with JavaScript is because it has weak typing it doesn't treat 3.0 any differently from 3 and so doesn't have the problem where the numbers can be converted to integers.

    It happens because computers work in binary so they convert your number to the nearest binary equivalent first and then convert the binary back into the nearest decimal equivalent at the end.

    As Phillip said - the solution is to move the decimal point at the start and move it back at the end - so for three decimal places multiply everything by 1000 first, then do the calculations, then work out how many places to move the decimal point back at the end (divide by 1000 if just adding and subtracting, then add up the mumber of multiplications and subtract the number of divisions and further divide by 1000 that many more times).
    Stephen
    Learn Modern JavaScript - http://javascriptexample.net/
    Helping others to solve their computer problem at http://www.felgall.com/

    Don't forget to start your JavaScript code with "use strict"; which makes it easier to find errors in your code.

  • Users who have thanked felgall for this post:

    code-in-time (06-08-2012)

  • #4
    Supreme Master coder! Old Pedant's Avatar
    Join Date
    Feb 2009
    Posts
    25,020
    Thanks
    75
    Thanked 4,323 Times in 4,289 Posts
    Quote Originally Posted by felgall View Post
    As Phillip said - the solution is to move the decimal point at the start and move it back at the end - so for three decimal places multiply everything by 1000 first, then do the calculations, then work out how many places to move the decimal point back at the end...
    STILL doesn't GUARANTEE "accuracy".

    Code:
    var x = 1234567890123456.888;
    var y = 987.000;
    
    var x1 = x * 1000;
    var x2 = y * 1000;
    var z1 = x1 * y1;
    var z = z1 / 1000000;
    
    var answer = z.toFixed(3);
    If at ANY POINT during the calculations the integer part of your result exceeds 9e15, you are hosed. You cannot at all be sure your final result will be accurate to 3 decimal places (or even, in the above example, to 1 decimal place).

    If you are working with amounts of money, other than the amount of the US National Debt or something on that order, the "trick" works. But it simply doesn't work if you need answers where lots of digits are involved.
    An optimist sees the glass as half full.
    A pessimist sees the glass as half empty.
    A realist drinks it no matter how much there is.

  • Users who have thanked Old Pedant for this post:

    code-in-time (06-08-2012)

  • #5
    Master Coder felgall's Avatar
    Join Date
    Sep 2005
    Location
    Sydney, Australia
    Posts
    6,472
    Thanks
    0
    Thanked 634 Times in 624 Posts
    Quote Originally Posted by Old Pedant View Post
    STILL doesn't GUARANTEE "accuracy".
    You have introduced a completely different issue to the discussion.

    What was being discussed is how the fact that the computer using binary means that you can't add 0.1 and 0.2 on a computer and get an answer of 0.3 (unless you apply rounding).

    Numbers overflowing the number of significant binary digits that the computer makes available to store each number in is a completely separate issue with all its own completely separate set of problems. That particular problem can occur just as easily with integers as it can with fractions.
    Stephen
    Learn Modern JavaScript - http://javascriptexample.net/
    Helping others to solve their computer problem at http://www.felgall.com/

    Don't forget to start your JavaScript code with "use strict"; which makes it easier to find errors in your code.

  • Users who have thanked felgall for this post:

    code-in-time (06-08-2012)

  • #6
    Supreme Master coder! Old Pedant's Avatar
    Join Date
    Feb 2009
    Posts
    25,020
    Thanks
    75
    Thanked 4,323 Times in 4,289 Posts
    No, I don't think I did introduce a new issue. I think you avoided a complete answer to the original question.

    Because his original question was based on this:
    Code:
    var a = 123.12345
    var b = 123456.1234567
    
    var c = a * b
    
    var d = a / b
    
    The answer of c and d must always have three decimal places.
    If we use your (and Philip's) suggestion, you would have him do:
    Code:
    var a = 123.12345;
    var b = 123456.1234567;
    
    var a1 = 123123.45;  // by multiplying a * 1000
    var b1 = 123456123.4567; // simiilarly
    
    var c1 = a1 * b1;
    var c = c1 / 1000000;
    var answer = c.toFixed(3);
    Now c1 is (precisely) 15200343843614.829615

    And so, in this example (with only 14 integer digits), the trick works.

    But read his sentence just prior to the example:
    a and b below might not always have the same number of decimal places
    It would only take his a and b values being two orders of magnitude larger to get a precise value of
    152003438436148296.15
    which is 18 significant digits and so his result, to 3 decimal places, could *NOT* be guaranteed to be correct.

    So I think my answer is quite germane to his original question.

    **********

    Please note what I stated:
    If at ANY POINT during the calculations the integer part of your result exceeds 9e15, you are hosed.
    I think that *must* be stated as the ruling limitation of the "multiply by the number of significant digits" method.
    An optimist sees the glass as half full.
    A pessimist sees the glass as half empty.
    A realist drinks it no matter how much there is.

  • Users who have thanked Old Pedant for this post:

    code-in-time (06-08-2012)

  • #7
    Master Coder felgall's Avatar
    Join Date
    Sep 2005
    Location
    Sydney, Australia
    Posts
    6,472
    Thanks
    0
    Thanked 634 Times in 624 Posts
    Quote Originally Posted by Old Pedant View Post
    No, I don't think I did introduce a new issue. I think you avoided a complete answer to the original question.
    You did introduce a new issue - the half of the problem that neither Phillip nor I had considered in providing our answers - since it wasn't as clearly stated in the question as the half that we did answer.
    Stephen
    Learn Modern JavaScript - http://javascriptexample.net/
    Helping others to solve their computer problem at http://www.felgall.com/

    Don't forget to start your JavaScript code with "use strict"; which makes it easier to find errors in your code.

  • Users who have thanked felgall for this post:

    code-in-time (06-08-2012)

  • #8
    Regular Coder Lerura's Avatar
    Join Date
    Aug 2005
    Location
    Denmark
    Posts
    878
    Thanks
    0
    Thanked 114 Times in 113 Posts
    Quote Originally Posted by code-in-time View Post
    How do I do this accurately?
    Guess it means that OP want the result to be as accurate as possible.

    AFAIK inaccuracy is only a problem with division. -> Where a solution similar to Old P's would be a good choice

  • Users who have thanked Lerura for this post:

    code-in-time (06-08-2012)

  • #9
    Supreme Master coder! Philip M's Avatar
    Join Date
    Jun 2002
    Location
    London, England
    Posts
    17,732
    Thanks
    202
    Thanked 2,508 Times in 2,486 Posts
    Quote Originally Posted by felgall View Post
    You did introduce a new issue - the half of the problem that neither Phillip nor I had considered in providing our answers - since it wasn't as clearly stated in the question as the half that we did answer.
    Actually, I thought that I had dealt with that issue:-

    ECMAScript numbers are represented in binary as IEEE-754 (IEC 559) Doubles, with a resolution of 53 bits, giving an accuracy of 15-16 decimal digits; integers up to just over 9e15 are precise, but few decimal fractions are. Given this, arithmetic is as exact as possible, but no more. Operations on integers are exact if the true result and all intermediates are integers within that range.
    Or, as Old Pedant put it, "if at ANY POINT during the calculations the integer part of your result exceeds 9e15, you are hosed."
    Last edited by Philip M; 05-31-2012 at 08:15 AM. Reason: Typo

    All the code given in this post has been tested and is intended to address the question asked.
    Unless stated otherwise it is not just a demonstration.

  • Users who have thanked Philip M for this post:

    code-in-time (06-08-2012)

  • #10
    Master Coder felgall's Avatar
    Join Date
    Sep 2005
    Location
    Sydney, Australia
    Posts
    6,472
    Thanks
    0
    Thanked 634 Times in 624 Posts
    Quote Originally Posted by Philip M View Post
    Actually, I thought that I had dealt with that issue:-
    You're right. I was the only one who wasn't thinking about that half of the problem. There isn't a JavaScript solution to that part of the problem though - you'd need to swap to a language that supports larger numbers to get around that one.
    Last edited by felgall; 05-31-2012 at 08:19 AM.
    Stephen
    Learn Modern JavaScript - http://javascriptexample.net/
    Helping others to solve their computer problem at http://www.felgall.com/

    Don't forget to start your JavaScript code with "use strict"; which makes it easier to find errors in your code.

  • Users who have thanked felgall for this post:

    code-in-time (06-08-2012)


  •  

    Posting Permissions

    • You may not post new threads
    • You may not post replies
    • You may not post attachments
    • You may not edit your posts
    •