Skip to main content
January 25, 2008
Answered

ArraySum() problem

  • January 25, 2008
  • 7 replies
  • 843 views
I have found that given an array with certain values, its sum does not always test true when compared to the a literal of the same value (i.e. The sum of array X is 100, but ArraySum(x) eq 100 results in false.)

When run, the example below results in:
The sum of the array is: 100
The sum of the array does not equal 100.

I'm using CF 7.01 on Win XP with Sun JVM 1.4.2_05

Any help would be appreciated!
Thanks.
    This topic has been closed for replies.
    Correct answer -__cfSearching__-
    It appears the arraySum value is actually being represented as a java.lang.Double internally. Using java's toString() method, you can see the value is actually 99.9999...etcetera..

    <cfset theList = "20,20,9.4,7.9,7.8,7.6,7.4,7.3,7.3,5.3">
    <cfset theArraySum = ArraySum(ListToArray(theList))>
    <cfdump var="#theArraySum.toString()#"><br>
    <cfdump var="#theArraySum.getClass().getName()#"><br>
    <cfoutput>
    Val Test: <cfif val(theArraySum) eq 100>Equal<cfelse>Not Equal</cfif><br>
    Round Test: <cfif round(theArraySum) eq 100>Equal<cfelse>Not Equal</cfif>
    </cfoutput>

    7 replies

    Inspiring
    January 26, 2008
    > I find it appalling that even Java gets it wrong (in Adam's first AddTest)!

    Note that Java is *not* necessarily "getting it wrong" (I doubt it is).
    Floating point numbers only have a set scale of precision, so the higher a
    number is, the less precise it is, and this has a cumulative effect.

    Let's saw we're using a special helpful programming language, which has
    special de-ooked floating point numbers of only a two-digit precision
    (anything else is just ugly!), and are adding a list of numbers up:

    0
    + 0.33 = 0.33
    + 0.33 = 0.66
    + 6.5 = 7.1 (note we've lost the 0.06)
    + 5.3 = 12 (now all the precision is to the left of the decimal point, so
    we only get the whole-number part, irrespective that the addend has a
    decimal part: we don't have the precision to deal with "12.4")
    + 10 = 22

    If we start the other way around, we immediately lose all precision right
    of the decimal place:

    0
    + 10 = 10
    + 5.3 = 15
    + 6.5 = 21
    + 0.33 = 21
    + 0.33 = 21

    Floating point numbers are *innately* inaccurate.

    You have to bear in mind that whilst we see something like "5.3", in binary
    - which is the only option a computer has for computations, "5.3" is going
    to be an irrational number, so precision issues kick in straight away.
    It's the same as if we as humans were adding up the value of 1/7 - which is
    a number not expressible in decimal with absolute accuracy - with only a
    set level of precision: errors will creep in fairly quickly, because 1/7 is
    not 0.1, nor is it 0.14, nor is it 0.142, nor is it 0.1428, etc.

    However if the language presents and works these numbers uniformly, there
    is little problem with this.

    CF's problem is it's not being uniform in the way it handles the numbers,
    leading to unexepcted situations like having 100 not equalling 100.

    --
    Adam
    Inspiring
    January 26, 2008
    Paul@Boeing,

    No. I imagine it is subject to the same limitations as the other methods.
    January 26, 2008
    I can understand languages having precision difficulties, but come on folks, these aren't extremely precise numbers!

    I find it appalling that even Java gets it wrong (in Adam's first AddTest)!

    cfSearching: I'm hoping I'm safe with Val() since the input numbers will only have single decimal places. Think Evaluate() is safer?

    Thanks everybody for all the help.
    Inspiring
    January 26, 2008
    Paul@Boeing,

    Added to what Adam Cameron said, I would certainly do more extensive testing with the val() function. There may be nuances to CF's handling of floating point values that it does not deal well with. IIRC there is a limit on the number of digits when using val(). After which CF converts numbers to scientific notation. Just something to keep in mind.
    Inspiring
    January 25, 2008
    Read up on floating point arithmetic inaccuracy: CF is quite prone to it.

    Tip: try starting accumlulating your total by adding the most precise
    numbers first, rather than the least precise. This will help. But on the
    whole, one should never expect accurate arithmetic results with floats on
    CF. I single out CF because this is an *appalling* example of how crap CF
    is at this sort of thing. Or do I mean *excellent* example?

    By way of comparison, try these two wee java programs:

    AddTest.java
    class AddTest{

    public static void main(String sArgs[]){
    Float f1 = new Float(20);
    Float f2 = new Float (20);
    Float f3 = new Float (9.4);
    Float f4 = new Float (7.9);
    Float f5 = new Float (7.8);
    Float f6 = new Float (7.6);
    Float f7 = new Float (7.4);
    Float f8 = new Float (7.3);
    Float f9 = new Float (7.3);
    Float f10 = new Float (5.3);

    Float fSum = f1 + f2 + f3 + f4 + f5 + f6 + f7 + f8 + f9 + f10;

    System.out.println("Sum: " + fSum);
    }
    }

    Outputs "Sum: 100.000015".


    AddTest2.java
    class AddTest2{

    public static void main(String sArgs[]){
    Float f1 = new Float(20);
    Float f2 = new Float (20);
    Float f3 = new Float (9.4);
    Float f4 = new Float (7.9);
    Float f5 = new Float (7.8);
    Float f6 = new Float (7.6);
    Float f7 = new Float (7.4);
    Float f8 = new Float (7.3);
    Float f9 = new Float (7.3);
    Float f10 = new Float (5.3);

    Float fSum = f10 + f9 + f8 + f7 + f6 + f5 + f4 + f3 + f2 + f1;

    System.out.println("Sum: " + fSum);
    }
    }

    Outputs "Sum: 100.0".


    I would say CF is doing the former (or facsimile thereof) under the hood,
    but being "helpful" and truncating (from view, if not from actual value)
    the results. I do not see how doing this could possibly be construed as a
    sensible thing to do.

    {editorial}
    I wish the CF dev team would just stop trying to make CF "helpful" when
    doing stuff like this ("ooh, let's lop off that nasty '000015': it's all
    ooky and no one will want that"). This behaviour is about as helpful as
    the paper-clip in MS Office is.

    If someone wants to lop off the ooky decimal part of the result of a FP
    calculation, *they will*, using int(), numberFormat(), listFirst(),
    whatever. But the language should *leave it up to the developer* to do
    that. Not second guess them, and in the process bugger it up.
    {editorial}

    --
    Adam
    January 25, 2008
    Adam, I agree with your editorial 100.000015%
    :)
    January 25, 2008
    Paul -

    i've played around with this for about a half hour, and can't figure out why it's not evaluating true.

    the only way i could get it to output the expected result was to wrap the variable in an evaluate:
    <h3>The sum of the array #iif(evaluate(theArraySum) eq 100,de("does"),de("does not"))# equal 100.</h3>

    Dan -

    the iif() comparing 100 and 100.0 evaluated false for me (CF 8). but even if the arraySum() is returning 100.0, i modified the iif() to read:
    <h3>The sum of the array #iif(theArraySum eq 100.0,de("does"),de("does not"))# equal 100.</h3>

    and still got "does not".

    weird.
    -__cfSearching__-Correct answer
    Inspiring
    January 25, 2008
    It appears the arraySum value is actually being represented as a java.lang.Double internally. Using java's toString() method, you can see the value is actually 99.9999...etcetera..

    <cfset theList = "20,20,9.4,7.9,7.8,7.6,7.4,7.3,7.3,5.3">
    <cfset theArraySum = ArraySum(ListToArray(theList))>
    <cfdump var="#theArraySum.toString()#"><br>
    <cfdump var="#theArraySum.getClass().getName()#"><br>
    <cfoutput>
    Val Test: <cfif val(theArraySum) eq 100>Equal<cfelse>Not Equal</cfif><br>
    Round Test: <cfif round(theArraySum) eq 100>Equal<cfelse>Not Equal</cfif>
    </cfoutput>
    January 25, 2008
    Great! Thanks CJ and cfSearching, at least we found a workaround!
    I think I'll use the Val() function.
    I can't use Round since the input number may actually be 99.5 and I don't want that to test as 100.

    Now the question really is:
    Why would numbers, without any division, aquire repeating decimals?
    ...and how many other CF expressions does this affect?
    Inspiring
    January 25, 2008
    Forget the array and try that iif thing on 100 and 100.0. Do you get the same result?