Fun With Numbers

Discussion in 'Javascript' started by Gene Wirchenko, Feb 3, 2012.

  1. Dear JavaScripters:

    I need to do work with fixed-decimal quantities (mainly dollar
    amounts but others as well). I need to be able to do reliable
    arithmetic with them.

    0.1 + 0.1 + 0.1 equals 0.15 + 0.15 mathematically, but not with
    floating point. I need to have it equal.

    So I am cheating. I am storing fixed-decimal amounts internally
    as integers. When I need to output a value, I scale it, but any
    arithmetic or comparison operations will be on the integers.

    My first thought was that I was safe for nine digits worth,
    because ECMAScript does a lot of 32-bit operations. That is on the
    edge of what I need. The non-JavaScript system that I maintain now
    has reports that generate nine digits worth in some reports.

    I did some experimenting, and it appears that I might be able to
    get 15 digits of precision, but not 16. After determining this, I
    referred to the ECMAScript standard (ECMA-262 5.1 Edition of June
    2011) to see if this matched. That standard says that it uses the
    IEEE 754 floating point format, and some documentation on that says
    that it is good for 15.95 digits of precision.

    So far, so good.

    But am I safe?

    Can I count on exact arithmetic with integers of up to 15 digits
    of precision?

    If yes, can you please point to a reference? If no, please give
    me a counterexample.

    I would rather not have to mess around like this, but one of
    JavaScript's nasty bits is only one number type.

    Sincerely,

    Gene Wirchenko
     
    Gene Wirchenko, Feb 3, 2012
    #1
    1. Advertising

  2. Gene Wirchenko

    Tom de Neef Guest

    "Gene Wirchenko" <>
    > I need to do work with fixed-decimal quantities (mainly dollar
    > amounts but others as well). I need to be able to do reliable
    > arithmetic with them.
    >
    > 0.1 + 0.1 + 0.1 equals 0.15 + 0.15 mathematically, but not with
    > floating point. I need to have it equal.
    >
    > So I am cheating. I am storing fixed-decimal amounts internally
    > as integers. When I need to output a value, I scale it, but any
    > arithmetic or comparison operations will be on the integers.
    >


    Just wondering: how do you calculate 3,62% of ($4.56 + $14.13) and equal it
    to 3,62% of $4.56 plus 3,62% of $14.13 ?
    Or go from euro to dollar, etc ?
    Tom
     
    Tom de Neef, Feb 3, 2012
    #2
    1. Advertising

  3. On Fri, 3 Feb 2012 10:29:56 +0100, "Tom de Neef" <>
    wrote:

    >"Gene Wirchenko" <>
    >> I need to do work with fixed-decimal quantities (mainly dollar
    >> amounts but others as well). I need to be able to do reliable
    >> arithmetic with them.
    >>
    >> 0.1 + 0.1 + 0.1 equals 0.15 + 0.15 mathematically, but not with
    >> floating point. I need to have it equal.
    >>
    >> So I am cheating. I am storing fixed-decimal amounts internally
    >> as integers. When I need to output a value, I scale it, but any
    >> arithmetic or comparison operations will be on the integers.
    >>

    >
    >Just wondering: how do you calculate 3,62% of ($4.56 + $14.13) and equal it
    >to 3,62% of $4.56 plus 3,62% of $14.13 ?
    >Or go from euro to dollar, etc ?


    I have so far tested with addition, but multiplication is only a
    bit more complicated.

    3.62% = 0.0362 requires a precision of (4,4) [meaning total
    digits and decimal digits]. The dollar amounts are (3,2) and (4,2).
    Whenever a dollar amount and a percentage are multiplied, the result
    requires 6 decimal places. When it matters for it to be converted to
    a dollar value, I will round and rescale the value.
    $4.56 + $14.13 = $18.69 then * 0.0362 = $0.676578
    0.0362 * $4.56 = $0.165072
    0.0362 * $14.13 = $0.511506
    sum: $0.676578
    So the amounts are equal. I would round after completing all
    operations and rescale to get $0.68. (If you round partway through,
    yes, you can get rounding errors.)

    Internally, the above is done with integers with the parened
    numbers indicating the number of decimal digits:
    $456(2) + $1413(2) = $1869(2) then * 362(4) = $676578(6)
    362(4) * $456(2) = $165072(6)
    362(4) * $1413(2) = $511506(6)
    sum: $676578(6)
    Round and scale to $68(2) which is $0.68.

    Sincerely,

    Gene Wirchenko
     
    Gene Wirchenko, Feb 3, 2012
    #3
  4. Gene Wirchenko

    Evertjan. Guest

    Gene Wirchenko wrote on 03 feb 2012 in comp.lang.javascript:

    >>Just wondering: how do you calculate 3,62% of ($4.56 + $14.13) and
    >>equal it to 3,62% of $4.56 plus 3,62% of $14.13 ?
    >>Or go from euro to dollar, etc ?

    >


    integer multiplication [20 items sole at ...] of currency needs to be
    exact, so do this multiplication on integer cents.
    And do not convert from and to binary floating point dollars at all,
    use strings.

    Percentage or currency conversion needs to be rounded anyway,
    so here the problem of binary math does not really exist.

    ============

    We used to have Basic implementations with BNC [Binary Coded Decimal]-math,
    those where the days!

    I wrote here 20 Jan 2006:
    > "Central Data Basic" for the Signetics 2650 microprocessor,
    > rumored to be coded by a William Gates in the early 1980's,
    > had excellent BCD support.


    Nice to read that threaad again with those familiar names:
    <http://bytes.com/topic/javascript/answers/447636-show-hex-numbers>


    --
    Evertjan.
    The Netherlands.
    (Please change the x'es to dots in my emailaddress)
     
    Evertjan., Feb 3, 2012
    #4
  5. Tom de Neef wrote:

    > "Gene Wirchenko" <>
    >> I need to do work with fixed-decimal quantities (mainly dollar
    >> amounts but others as well). I need to be able to do reliable
    >> arithmetic with them.
    >>
    >> 0.1 + 0.1 + 0.1 equals 0.15 + 0.15 mathematically, but not with
    >> floating point. I need to have it equal.
    >>
    >> So I am cheating. I am storing fixed-decimal amounts internally
    >> as integers. When I need to output a value, I scale it, but any
    >> arithmetic or comparison operations will be on the integers.

    >
    > Just wondering: how do you calculate 3,62% of ($4.56 + $14.13) and equal
    > it to 3,62% of $4.56 plus 3,62% of $14.13 ?
    > Or go from euro to dollar, etc ?


    You store the floating-point number n as an integer value (i.e., this.value
    % 1 = 0) and store the number of significant decimal digits of n
    (this.scale) along with it in an object. Then

    n = this.value × 10^(−this.scale).

    Of course, in order to do basic arithmetic with the object, you need special
    methods that account for the scale. That is,

    a.b + c.de
    ~ ab:scale1 + cde:scale2
    ~ (ab × 10^(scale2 − scale1) + cde)):max(scale1, scale2)
    ~ (ab × 10^(scale2 − scale1) + cde) × 10^(−max(scale1, scale2)),

    and

    a.b + c.de
    ~ ab:scale1 × cde:scale2
    ~ (ab × 10^(scale2 − scale1) × cde):(scale1 × scale2)
    ~ (ab × 10^(scale2 − scale1) × cde) × 10^(−scale1 × scale2)

    where scale1 <= scale2 (here: scale1 = 1, scale2 = 2).

    The idea is anything but new. For example, Java has had this for many
    years:
    <http://docs.oracle.com/javase/1.5.0/docs/api/java/math/BigDecimal.html>

    The precision of an implementation of this in an ECMAScript implementation
    is limited by the precision for integer values (number values `i' with i % 1
    == 0), as the unscaled value and the scale are still IEEE-754 floating-point
    values. But the precision of computation is indeed better than with plain
    floating-point values, that is 1:1 + 1:1 + 1:1 ~ 3:1 ~ 0.3.


    PointedEars
    --
    When all you know is jQuery, every problem looks $(olvable).
     
    Thomas 'PointedEars' Lahn, Feb 4, 2012
    #5
  6. Tom de Neef wrote:

    > "Gene Wirchenko" <>
    >> I need to do work with fixed-decimal quantities (mainly dollar
    >> amounts but others as well). I need to be able to do reliable
    >> arithmetic with them.
    >>
    >> 0.1 + 0.1 + 0.1 equals 0.15 + 0.15 mathematically, but not with
    >> floating point. I need to have it equal.
    >>
    >> So I am cheating. I am storing fixed-decimal amounts internally
    >> as integers. When I need to output a value, I scale it, but any
    >> arithmetic or comparison operations will be on the integers.

    >
    > Just wondering: how do you calculate 3,62% of ($4.56 + $14.13) and equal
    > it to 3,62% of $4.56 plus 3,62% of $14.13 ?
    > Or go from euro to dollar, etc ?


    You store the floating-point number n as an integer value (i.e., this.value
    % 1 = 0) and store the number of significant decimal digits of n
    (this.scale) along with it in an object. Then

    n = this.value × 10^(−this.scale).

    Of course, in order to do basic arithmetic with the object, you need special
    methods that account for the scale. That is,

    a.b × c.de
    ~ ab:scale1 + cde:scale2
    ~ (ab × 10^(scale2 − scale1) + cde)):max(scale1, scale2)
    ~ (ab × 10^(scale2 − scale1) + cde) × 10^(−max(scale1, scale2)),

    and

    a.b + c.de
    ~ ab:scale1 × cde:scale2
    ~ (ab × 10^(scale2 − scale1) × cde):(scale1 × scale2)
    ~ (ab × 10^(scale2 − scale1) × cde) × 10^(−scale1 × scale2)

    where scale1 <= scale2 (here: scale1 = 1, scale2 = 2).

    The idea is anything but new. For example, Java has had this for many
    years:
    <http://docs.oracle.com/javase/1.5.0/docs/api/java/math/BigDecimal.html>

    The precision of an implementation of this in an ECMAScript implementation
    is limited by the precision for integer values (number values `i' with i % 1
    == 0), as the unscaled value and the scale are still IEEE-754 floating-point
    values. But the precision of computation is indeed better than with plain
    floating-point values, that is 1:1 + 1:1 + 1:1 ~ 3:1 ~ 0.3.


    PointedEars
    --
    When all you know is jQuery, every problem looks $(olvable).
     
    Thomas 'PointedEars' Lahn, Feb 4, 2012
    #6
  7. Tom de Neef wrote:

    > "Gene Wirchenko" <>
    >> I need to do work with fixed-decimal quantities (mainly dollar
    >> amounts but others as well). I need to be able to do reliable
    >> arithmetic with them.
    >>
    >> 0.1 + 0.1 + 0.1 equals 0.15 + 0.15 mathematically, but not with
    >> floating point. I need to have it equal.
    >>
    >> So I am cheating. I am storing fixed-decimal amounts internally
    >> as integers. When I need to output a value, I scale it, but any
    >> arithmetic or comparison operations will be on the integers.

    >
    > Just wondering: how do you calculate 3,62% of ($4.56 + $14.13) and equal
    > it to 3,62% of $4.56 plus 3,62% of $14.13 ?
    > Or go from euro to dollar, etc ?


    You store the floating-point number n as an integer value (i.e., this.value
    % 1 = 0) and store the number of significant decimal digits of n
    (this.scale) along with it in an object. Then

    n = this.value × 10^(−this.scale).

    Of course, in order to do basic arithmetic with the object, you need special
    methods that account for the scale. That is,

    a.b + c.de
    ~ ab:scale1 + cde:scale2
    ~ (ab × 10^(scale2 − scale1) + cde)):max(scale1, scale2)
    ~ (ab × 10^(scale2 − scale1) + cde) × 10^(−max(scale1, scale2)),

    and

    a.b × c.de
    ~ ab:scale1 × cde:scale2
    ~ (ab × 10^(scale2 − scale1) × cde):(scale1 × scale2)
    ~ (ab × 10^(scale2 − scale1) × cde) × 10^(−scale1 × scale2)

    where scale1 <= scale2 (here: scale1 = 1, scale2 = 2).

    The idea is anything but new. For example, Java has had this for many
    years:
    <http://docs.oracle.com/javase/1.5.0/docs/api/java/math/BigDecimal.html>

    The precision of an implementation of this in an ECMAScript implementation
    is limited by the precision for integer values (number values `i' with i % 1
    == 0), as the unscaled value and the scale are still IEEE-754 floating-point
    values. But the precision of computation is indeed better than with plain
    floating-point values, that is 1:1 + 1:1 + 1:1 ~ 3:1 ~ 0.3.


    PointedEars
    --
    When all you know is jQuery, every problem looks $(olvable).
     
    Thomas 'PointedEars' Lahn, Feb 4, 2012
    #7
  8. In comp.lang.javascript message <v3rmi7l1i7ji615ltsn7mncfsh2tf6ip2k@4ax.
    com>, Thu, 2 Feb 2012 21:23:43, Gene Wirchenko <> posted:

    > I need to do work with fixed-decimal quantities (mainly dollar
    >amounts but others as well). I need to be able to do reliable
    >arithmetic with them.


    Dollars are integers. No problem, up to and including 2^53.

    > 0.1 + 0.1 + 0.1 equals 0.15 + 0.15 mathematically, but not with
    >floating point. I need to have it equal.


    You only get assured exact results if all numbers, including
    intermediates, can be expressed in fixed-point binary with the most
    significant and least significant bits no more than about 53 buts apart.

    But the PC FPU, and maybe others, can work with 64-bit mantissa numbers,
    so "internal" intermediates could be more precise - which might or might
    not be standards-compliant.

    Aside : we should be able to think of a test for that/

    If you want to do exact addition, subtraction, multiplication,
    comparison with dollar-cent prices, work in cents.


    > So I am cheating. I am storing fixed-decimal amounts internally
    >as integers. When I need to output a value, I scale it, but any
    >arithmetic or comparison operations will be on the integers.
    >
    > My first thought was that I was safe for nine digits worth,
    >because ECMAScript does a lot of 32-bit operations. That is on the
    >edge of what I need. The non-JavaScript system that I maintain now
    >has reports that generate nine digits worth in some reports.


    The 32-bit operations are logical, not arithmetic. They are not needed
    in calculating finance.

    > I did some experimenting, and it appears that I might be able to
    >get 15 digits of precision, but not 16. After determining this, I
    >referred to the ECMAScript standard (ECMA-262 5.1 Edition of June
    >2011) to see if this matched. That standard says that it uses the
    >IEEE 754 floating point format, and some documentation on that says
    >that it is good for 15.95 digits of precision.


    Not entirely so. A single non-integer addition operation is good to
    about that, depending on by how much the answer is below the nearest
    power of two above. But subtraction of two inexactly-represented
    quantities of similar magnitude loses precision.

    Have you had the lesson on how to code the solutions of a potentially
    ill-conditioned quadratic equation, concerning
    -b +- root(b^2-4ac) / 2a // ???

    > But am I safe?
    >
    > Can I count on exact arithmetic with integers of up to 15 digits
    >of precision?


    Only if you really understand what you are doing. And not always then,
    since most arithmetic expressions involving division have ideal results
    which cannot be exactly represented in an IEEE Double.

    And if you're not using a P60's FPU.

    > If yes, can you please point to a reference? If no, please give
    >me a counterexample.


    You could read my Web site, to reduce the frequency with which you
    "discover" quite well-known wheels.


    If it is necessary to reproduce the results which would be obtained by a
    professional accountant using pre-computer equipment, then you are only
    safe if you follow his methods exactly. That does not mean getting the
    right answer, it means getting the same answer.


    Happily, modern computers are so fast, and accounting is so simple, that
    you^H^H^Hone can write an exact arbitrary-length decimal arithmetic
    package without too much difficulty.
    Via <http://www.merlyn.demon.co.uk/programs/00index.htm longcalc, for
    example.

    --
    (c) John Stockton, nr London UK ?@merlyn.demon.co.uk IE8 FF8 Op11 Sf5 Cr15
    news:comp.lang.javascript FAQ <http://www.jibbering.com/faq/index.html>.
    <http://www.merlyn.demon.co.uk/js-index.htm> jscr maths, dates, sources.
    <http://www.merlyn.demon.co.uk/> TP/BP/Delphi/jscr/&c, FAQ items, links.
     
    Dr J R Stockton, Feb 4, 2012
    #8
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Andy Fish
    Replies:
    65
    Views:
    1,762
    Mabden
    May 18, 2004
  2. Graham Nicholls

    Fun with numbers - dammit, but I want a cast!

    Graham Nicholls, Aug 11, 2003, in forum: Python
    Replies:
    18
    Views:
    573
    Carl Banks
    Aug 12, 2003
  3. dolphin
    Replies:
    4
    Views:
    322
    Jorgen Grahn
    Aug 25, 2007
  4. Replies:
    45
    Views:
    4,678
  5. er
    Replies:
    2
    Views:
    509
Loading...

Share This Page