472,363 Members | 2,039 Online

# Weird result returned from adding floats depending on order I add them

I'm getting different results when I add up a list of floats depending
on the order that I list the floats. For example, the following returns
False:
def check():
totalProp=0
inputs=[0.2,0.2,0.2,0.1,0.2,0,0.1]
for each in inputs:

totalProp+=each
print "totalProp=",totalProp
if totalProp != 1:
print "Your proportions must add up to 1"

return False
return True

However, if I swap, the 4th and 5th list items like this:

totalProp=0
inputs=[0.2,0.2,0.2,0.2,0.1,0,0.1]
for each in inputs:

totalProp+=each
print "totalProp=",totalProp
if totalProp != 1:
print "Your proportions must add up to 1"

return False
return True

I get True returned. Can anyone tell me whats going on and how I can
avoid the problem. Thanks

Joanne Matthews
Feb 20 '07 #1
9 1482
joanne matthews (RRes-Roth) a écrit :
I'm getting different results when I add up a list of floats depending
on the order that I list the floats. For example, the following returns
False:
def check():
totalProp=0
inputs=[0.2,0.2,0.2,0.1,0.2,0,0.1]
for each in inputs:

totalProp+=each
print "totalProp=",totalProp
if totalProp != 1:
print "Your proportions must add up to 1"

return False
return True

However, if I swap, the 4th and 5th list items like this:

totalProp=0
inputs=[0.2,0.2,0.2,0.2,0.1,0,0.1]
for each in inputs:

totalProp+=each
print "totalProp=",totalProp
if totalProp != 1:
print "Your proportions must add up to 1"

return False
return True

I get True returned. Can anyone tell me whats going
Its related to the internal representation of real numbers using a
finite number of binary digits - intermediate additions may (here the
order is have an impact) produce results which have no representation,
and lead to dismiss of an epsilon value.

http://en.wikipedia.org/wiki/Floating_point
on and how I can
avoid the problem. Thanks
Use an ad-hoc library with numerical types using a different
representation (other posters may give examples of libraries they use).
Feb 20 '07 #2
Hi,
I'm getting different results when I add up a list of floats depending
on the order that I list the floats. For example, the following returns

[snip summation]

if totalProp != 1:
From a numerical analysis point of view, never ever do this. The values
you are adding are approximations to the numbers you require, you then
test for equality (the real no no)...

There is even a section in the Python tutorial about it:

http://docs.python.org/tut/node16.html

Cheers,
John McCallum
Edinburgh
Feb 20 '07 #3
On Feb 20, 11:29 pm, "joanne matthews (RRes-Roth)"
<joanne.matth...@bbsrc.ac.ukwrote:
I'm getting different results when I add up a list of floats depending
on the order that I list the floats.
This is quite expected. Floating point arithmetic is subject to
rounding errors.

[doesn't add to 1.0]
inputs=[0.2,0.2,0.2,0.1,0.2,0,0.1]

However, if I swap, the 4th and 5th list items like this:

inputs=[0.2,0.2,0.2,0.2,0.1,0,0.1]

What is happening:

print repr(whatever_you_are_puzzled_by) is a Very Good Idea (TM).
>>a = [0.2, 0.2, 0.2, 0.1, 0.2, 0.1]
b = [0.2, 0.2, 0.2, 0.2, 0.1, 0.1]
sum(a)
1.0000000000000002
>>sum(b)
1.0
>>tot = 0.0
for x in a:
.... tot += x
.... print repr(x), repr(tot)
....
0.20000000000000001 0.20000000000000001
0.20000000000000001 0.40000000000000002
0.20000000000000001 0.60000000000000009
0.10000000000000001 0.70000000000000007
0.20000000000000001 0.90000000000000013
0.10000000000000001 1.0000000000000002
>>tot = 0.0
for x in b:
.... tot += x
.... print repr(x), repr(tot)
....
0.20000000000000001 0.20000000000000001
0.20000000000000001 0.40000000000000002
0.20000000000000001 0.60000000000000009
0.20000000000000001 0.80000000000000004
0.10000000000000001 0.90000000000000002
0.10000000000000001 1.0
>>>
As you can see, 0.1 and 0.2 can't be represented exactly as floating
point numbers. Consequently there is only a rough chance that they
will add up to what you think they should add up to.

Fixes:

(1) Round the sums to a suitable precision.
>>round(sum(a), 3)
1.0
>>round(sum(b), 3)
1.0
>>>
(2) Test against a range, rather than for equality:
>>abs(sum(a) - 1.0) < 0.001
True
>>abs(sum(b) - 1.0) < 0.001
True
>>>
(3) Use the Decimal module

(4) Google this group (or the Python cookbok, I forget which) for
fancy algorithms for doing accurate sums of lists of floats.

HTH,
John

Feb 20 '07 #4
On 2007-02-20, joanne matthews (RRes-Roth) <jo*************@bbsrc.ac.ukwrote:
I'm getting different results when I add up a list of floats depending
on the order that I list the floats.
That's how floats work.
For example, the following returns
False:
def check():
totalProp=0
inputs=[0.2,0.2,0.2,0.1,0.2,0,0.1]
for each in inputs:

totalProp+=each
print "totalProp=",totalProp
if totalProp != 1:
Floating point operations are not exact. This test requires
them to be.

[...]
Can anyone tell me whats going on
IEEE floating point can not exactly represent 0.2 nor 0.1, so
you get approximations.
and how I can avoid the problem.
Don't use floating point if you expect exact results.

--
Grant Edwards grante Yow! I feel better about
at world problems now!
visi.com
Feb 20 '07 #5
On Feb 21, 2:05 am, Grant Edwards <gra...@visi.comwrote:
On 2007-02-20, joanne matthews (RRes-Roth) <joanne.matth...@bbsrc.ac.ukwrote:
I'm getting different results when I add up a list of floats depending
on the order that I list the floats.
>
Don't use floating point if you expect exact results.
It's not the floating point that's the problem, it's the radix, in
this case 2, not being able to express n/10 exactly. As the tutorial
points out, radix-10 has problems representing n/3 (and n/7 and ...)
exactly.

Another take: Don't expect exact results. If the input is exact to 1
or two decimal places, don't expect the sum to be exact to 15 or more
decimal places.

Feb 20 '07 #6
On 2007-02-20, John Machin <sj******@lexicon.netwrote:
On Feb 21, 2:05 am, Grant Edwards <gra...@visi.comwrote:
>On 2007-02-20, joanne matthews (RRes-Roth) <joanne.matth...@bbsrc.ac.ukwrote:
I'm getting different results when I add up a list of floats depending
on the order that I list the floats.
>>
Don't use floating point if you expect exact results.

It's not the floating point that's the problem, it's the radix, in
this case 2, not being able to express n/10 exactly. As the tutorial
points out, radix-10 has problems representing n/3 (and n/7 and ...)
exactly.
No matter what radix you choose, you're going to be able to
exactly represent 0% of the rational numbers within the range
of the representation. Since you have no control over the FP
representation (and hence radix), and little control over input
values, the only sane thing to do is to write your code under
the assumption that FP can't represent any values exactly.
Another take: Don't expect exact results.
Which is what I said. :)
If the input is exact to 1 or two decimal places, don't expect
the sum to be exact to 15 or more decimal places.
In this case the input values have about 14 significant digits.
So does the output. Unfortunately, the algorithm as written
requires an infinite number of significant digits.

--
Grant Edwards grante Yow! WHOA!! Ken and
at Barbie are having TOO
visi.com MUCH FUN!! It must be the
NEGATIVE IONS!!
Feb 20 '07 #7
On Feb 21, 3:44 am, Grant Edwards <gra...@visi.comwrote:
On 2007-02-20, John Machin <sjmac...@lexicon.netwrote:
On Feb 21, 2:05 am, Grant Edwards <gra...@visi.comwrote:
On 2007-02-20, joanne matthews (RRes-Roth) <joanne.matth...@bbsrc.ac.ukwrote:
Don't use floating point if you expect exact results.

Another take: Don't expect exact results.

Which is what I said. :)
It may well be what you said. I didn't hear that. What you wrote was
"Don't use floating point if you expect exact results." That is *not*
the same as "Don't expect exact results".

Feb 20 '07 #8
On Feb 20, 6:08 am, "John Machin" <sjmac...@lexicon.netwrote:
>for x in b:

... tot += x
... print repr(x), repr(tot)
...
0.20000000000000001 0.20000000000000001
0.20000000000000001 0.40000000000000002
0.20000000000000001 0.60000000000000009
0.20000000000000001 0.80000000000000004
0.10000000000000001 0.90000000000000002
0.10000000000000001 1.0

As you can see, 0.1 and 0.2 can't be represented exactly as floating
point numbers. Consequently there is only a rough chance that they
will add up to what you think they should add up to.
Although your point is correct, this is actually a myth about repr.
The goal of repr is to be able to round-trip all numbers, so
eval(repr(n)) == n. From that perspective it would be perfectly legal
if it printed out a nice and short "0.2" or "0.1".

As for the actual value, although you can't express all non-repeating
base-10 values with non-repeating base-2, you can express base-2 with
base-10. It just gets a little long:
>>'%.60f' % 0.2
'0.20000000000000001110223024625156540423631668090 8203125000000'
>>'%.60f' % 0.1
'0.10000000000000000555111512312578270211815834045 4101562500000'

Unfortunately this method of printing out floats won't work for
smaller values, since the %f formatting limits the number of decimal
places.

But if you want a more compact exact representation I have bodged
together a way of printing out floats in base-16:
>>hexfloat(0.2)
hexfloat('0.33333333333334')
>>hexfloat(0.1)
hexfloat('0.1999999999999A')

Interesting, if a bit confusing.

Feb 21 '07 #9
Hello Joanne,
... [float problem] ...
I get True returned. Can anyone tell me whats going on and how I can
avoid the problem. Thanks
If you want to be truly accurate, you can use gmpy.mpq (http://
gmpy.sourceforge.net/).
>>a = [0.2, 0.2, 0.2, 0.1, 0.2, 0.1]
b = [0.2, 0.2, 0.2, 0.2, 0.1, 0.1]
qa = [gmpy.mpq(int(i * 10), 10) for i in a]
qb = [gmpy.mpq(int(i * 10), 10) for i in b]
sum(qa)
mpq(1)
>>sum(qb)
mpq(1)
>>sum(qa) == sum(qb)
True

HTH,
--
Miki <mi*********@gmail.com>
http://pythonwise.blogspot.com

Feb 21 '07 #10

This thread has been closed and replies have been disabled. Please start a new discussion.

### Similar topics

 3 by: redneck_kiwi | last post by: Hi all: I have a really weird problem. I am developing a customer catalog system for my company and as such have delved into sessions for authentication and access levels. So far, I have managed... 10 by: Charles Law | last post by: For some reason, when I click the X to close my MDI parent form, the action appears to be re-directed to one of the MDI child forms, and the parent remains open. I am then unable to close the... 3 by: lagj | last post by: Using MySQL 5.0.15 I am no expert so maybe I am deeply misundertanding how this should work. I have a relatively complex quey with joins and a subquery (it is probably far from optimized, but... 38 by: baong | last post by: dear all i have use this line to time in many my web base appl. but now i found a weird problem the javascript line is the same but i use the calculation 2 time @ the first time, it is ok, 3 *... 5 by: kelmen | last post by: Try the below simple program. It give expected result. 1 1 2 2 Then toggle the statements in private static int sinc(), to use Test._num ++ . 12 by: syn1kk | last post by: 1: float (*data); 2: data = malloc(31 * sizeof(data)); 3: data = VARIABLE; Question 1: The variable data is a float pointer? Question 2: When the is used. Does that mean it is an... 9 by: serge | last post by: /* Subject: How to build a procedure that returns different numbers of columns as a result based on a parameter. You can copy/paste this whole post in SQL Query Analyzer or Management Studio... 18 by: atv | last post by: at least to me it is. I can't figure out for the life what it is i'm doing wrong here. i have a function called assign_coordinate. usually, i pass a malloced pointer to it, then individual... 135 by: robinsiebler | last post by: I've never had any call to use floating point numbers and now that I want to, I can't! *** Python 2.5.1 (r251:54863, May 1 2007, 17:47:05) on win32. *** 0.29999999999999999 0.29999999999999999 0 by: antdb | last post by: Ⅰ. Advantage of AntDB: hyper-convergence + streaming processing engine In the overall architecture, a new "hyper-convergence" concept was proposed, which integrated multiple engines and... 0 by: AndyPSV | last post by: HOW CAN I CREATE AN AI with an .executable file that would suck all files in the folder and on my computerHOW CAN I CREATE AN AI with an .executable file that would suck all files in the folder and... 0 by: WisdomUfot | last post by: It's an interesting question you've got about how Gmail hides the HTTP referrer when a link in an email is clicked. While I don't have the specific technical details, Gmail likely implements measures... 1 by: Matthew3360 | last post by: Hi, I have been trying to connect to a local host using php curl. But I am finding it hard to do this. I am doing the curl get request from my web server and have made sure to enable curl. I get a... 0 by: Oralloy | last post by: Hello Folks, I am trying to hook up a CPU which I designed using SystemC to I/O pins on an FPGA. My problem (spelled failure) is with the synthesis of my design into a bitstream, not the C++... 0 by: BLUEPANDA | last post by: At BluePanda Dev, we're passionate about building high-quality software and sharing our knowledge with the community. That's why we've created a SaaS starter kit that's not only easy to use but also... 0 by: Rahul1995seven | last post by: Introduction: In the realm of programming languages, Python has emerged as a powerhouse. With its simplicity, versatility, and robustness, Python has gained popularity among beginners and experts... 1 by: Ricardo de Mila | last post by: Dear people, good afternoon... I have a form in msAccess with lots of controls and a specific routine must be triggered if the mouse_down event happens in any control. Than I need to discover what... 1 by: ezappsrUS | last post by: Hi, I wonder if someone knows where I am going wrong below. I have a continuous form and two labels where only one would be visible depending on the checkbox being checked or not. Below is the...