Major Addition Bug?

S

Sean O'Dell

Doing this:

raise "false" if ((625.91 + 900.00 + 22.00) != 1547.91)

...raises the exception.

Seems like a pretty major addition bug to me. Anyone know of a good
workaround?

Sean O'Dell
 
T

ts

S> raise "false" if ((625.91 + 900.00 + 22.00) != 1547.91)

Well, this is well known

svg% ruby -e 'p "%.24f" % (625.91 + 900.00 + 22.00)'
"1547.909999999999854480847716"
svg%

svg% ruby -e 'p "%.24f" % 1547.91'
"1547.910000000000081854523160"
svg%


Guy Decoux
 
P

Phil Tomson

S> raise "false" if ((625.91 + 900.00 + 22.00) != 1547.91)

Well, this is well known

I'm not sure how well known this is. Is it well known as being a problem
or well known as in "you should never do this sort of thing".

Seems to present a major problem if you want to deal with financial
figures, for example. Are there any workarounds?



Phil
 
S

Sean O'Dell

S> raise "false" if ((625.91 + 900.00 + 22.00) != 1547.91)

Well, this is well known

Well known? I had no idea this bug existed until I wrote a line of code that
double-checked the arithmetic from a different app. I have code all over
doing simple arithmetic like this. Ruby can't add 3 simple numbers? I don't
mean to be disproportionately negative, but that shakes my faith more than a
little. It's just simple arithmetic. How old is this bug? When is it
getting fixed?

Sean O'Dell
 
J

Jim Freeze

Well known? I had no idea this bug existed until I wrote a line of code that
double-checked the arithmetic from a different app. I have code all over
doing simple arithmetic like this. Ruby can't add 3 simple numbers? I don't
mean to be disproportionately negative, but that shakes my faith more than a
little. It's just simple arithmetic. How old is this bug? When is it
getting fixed?

Sean O'Dell

Sorry, to shake your faith, but consider the following:

jfn@juno 124 /home/jfn/tmp > cat n.c
int main()
{
printf("%.24f\n", 625.91+900.00+22.00);
}
jfn@juno 125 /home/jfn/tmp > ./a.out
1547.909999999999854480847716


You might want to try the rational library.

Jim

--
Jim Freeze
Police: Good evening, are you the host?
Host: No.
Police: We've been getting complaints about this party.
Host: About the drugs?
Police: No.
Host: About the guns, then? Is somebody complaining about the guns?
Police: No, the noise.
Host: Oh, the noise. Well that makes sense because there are no guns
or drugs here. (An enormous explosion is heard in the
background.) Or fireworks. Who's complaining about the noise?
The neighbors?
Police: No, the neighbors fled inland hours ago. Most of the recent
complaints have come from Pittsburgh. Do you think you could
ask the host to quiet things down?
Host: No Problem. (At this point, a Volkswagon bug with primitive
religious symbols drawn on the doors emerges from the living
room and roars down the hall, past the police and onto the
lawn, where it smashes into a tree. Eight guests tumble out
onto the grass, moaning.) See? Things are starting to wind
down.
 
T

ts

S> Well known? I had no idea this bug existed until I wrote a line of code that
S> double-checked the arithmetic from a different app. I have code all over
S> doing simple arithmetic like this. Ruby can't add 3 simple numbers? I don't
S> mean to be disproportionately negative, but that shakes my faith more than a
S> little. It's just simple arithmetic. How old is this bug? When is it
S> getting fixed?


http://docs.sun.com/source/806-3568/ncg_goldberg.html


Guy Decoux
 
D

Dave Thomas

How old is this bug? When is it
getting fixed?

It's about 40 years old, and unlikely to be fixed. Floating point
numbers are not represented exactly inside computers, and so floating
point comparisons are routinely deprecated in books on programming.
Certain values cannot ever be expressed in floating point
representation.

If you want exact, fractional, math, you should probably use the
'rational' library and investigate 'mathn'.


Cheers

Dave
 
S

Sean O'Dell

Sorry, to shake your faith, but consider the following:

jfn@juno 124 /home/jfn/tmp > cat n.c
int main()
{
printf("%.24f\n", 625.91+900.00+22.00);
}
jfn@juno 125 /home/jfn/tmp > ./a.out
1547.909999999999854480847716


You might want to try the rational library.

I don't expect a script language to have those same rounding problems, so I
hope this gets fixed quickly. Thanks for the tip.

Sean O'Dell
 
M

Michael Neumann

Well known? I had no idea this bug existed until I wrote a line of code that
double-checked the arithmetic from a different app. I have code all over
doing simple arithmetic like this. Ruby can't add 3 simple numbers? I don't
mean to be disproportionately negative, but that shakes my faith more than a
little. It's just simple arithmetic. How old is this bug? When is it
getting fixed?

Try the same in Python. It's the same.

In Ruby you can use BigDecimal:

require 'bigdecimal'
BigDecimal.new("625.91") + 900 + 22 == BigDecimal.new("1547.91") # => true

Regards,

Michael
 
J

Jamis Buck

Sean said:
Well known? I had no idea this bug existed until I wrote a line of code that
double-checked the arithmetic from a different app. I have code all over
doing simple arithmetic like this. Ruby can't add 3 simple numbers? I don't
mean to be disproportionately negative, but that shakes my faith more than a
little. It's just simple arithmetic. How old is this bug? When is it
getting fixed?

Sean O'Dell

.

For what its worth, it appears (on my box, at least) that perl and
python both give the same result. It is not a Ruby bug, but rather a
problem with floating point round off.

--
Jamis Buck
(e-mail address removed)
http://www.jamisbuck.org/jamis

ruby -h | ruby -e
'a=[];readlines.join.scan(/-(.)\[e|Kk(\S*)|le.l(..)e|#!(\S*)/) {|r| a <<
r.compact.first };puts "\n>#{a.join(%q/ /)}<\n\n"'
 
S

Sean O'Dell

It's about 40 years old, and unlikely to be fixed. Floating point
numbers are not represented exactly inside computers, and so floating
point comparisons are routinely deprecated in books on programming.
Certain values cannot ever be expressed in floating point
representation.

If you want exact, fractional, math, you should probably use the
'rational' library and investigate 'mathn'.

Funny though, if I set a variable to 1547.91 exactly, it is represented just
fine. A value during the arithmetic must be a value which can't be
represented.

I had to massage my floating point math in C/C++ a lot many years ago, but I
always assumed it was a flaw in the MS compiler, and once I got in the habit
of doing it, I forgot about it.

Thanks for the info. I'm far less bitter now about having to round the
numbers for comparison. =)

Sean O'Dell
 
A

Ara.T.Howard

Well known? I had no idea this bug existed until I wrote a line of code that
double-checked the arithmetic from a different app. I have code all over
doing simple arithmetic like this. Ruby can't add 3 simple numbers? I don't
mean to be disproportionately negative, but that shakes my faith more than a
little. It's just simple arithmetic. How old is this bug? When is it
getting fixed?

i'd say no time soon unless ruby decides to implement it's own floating point
hardware emulator:

~ > cat a.c
#include <stdlib.h>
#include <stdio.h>

int
main (argc, argv, env)
int argc;
char **argv;
char **env;
{

float total = 1547.91;
float a = 625.91;
float b = 900.00;
float c = 22.00;
float sum;

sum = a + b + c;

fprintf (stdout, "total <%f>\n", total);
fprintf (stdout, "sum <%f>\n", sum);

return 0;
}

~ > gcc a.c -o a

~ > ./a
total <1547.910034>
sum <1547.909912>

-a
--
===============================================================================
| EMAIL :: Ara [dot] T [dot] Howard [at] noaa [dot] gov
| PHONE :: 303.497.6469
| ADDRESS :: E/GC2 325 Broadway, Boulder, CO 80305-3328
| URL :: http://www.ngdc.noaa.gov/stp/
| TRY :: for l in ruby perl;do $l -e "print \"\x3a\x2d\x29\x0a\"";done
===============================================================================
 
L

Lloyd Zusman

Sean O'Dell said:
Well known? I had no idea this bug existed until I wrote a line of
code that double-checked the arithmetic from a different app. I have
code all over doing simple arithmetic like this. Ruby can't add 3
simple numbers? I don't mean to be disproportionately negative, but
that shakes my faith more than a little. It's just simple arithmetic.
How old is this bug? When is it getting fixed?

In 1969 I took a course called Introduction to Computer Programming. In
one of the early chapters of the textbook, we learned about a concept
called "floating point arithmetic". One aspect of this topic that was
drilled into us is the way that floating point arithmetic does not yield
exact results.

I want to add that this concept, which is so basic to the understanding
of programming that it was taught in an introductory course before we
even wrote a line of code, was old information even in 1969.

This basic concept of floating point arithmetic is every bit as
pertinent today as it was in 1969 and the years prior to that. Did you
actually not learn this concept before starting to program in Ruby?

In the off chance that you were absent that day when they talked about
this in school, or that the 5 pages that discussed this in your
Introduction to Computer Programming book accidentally got eaten by your
dog, I want you to know that the case that you are describing here is
_not_ a bug, but rather, an intrisic feature of how computers do certain
kinds of arithmetic.

Do a search in Google on "floating point arithmetic" (best to put
that entire phrase in double quotes) for more information.
 
L

Lloyd Zusman

Sean O'Dell said:
Funny though, if I set a variable to 1547.91 exactly, it is
represented just fine. A value during the arithmetic must be a value
which can't be represented.

Even the value 1547.91 might not be stored exactly as that value in its
internal floating point representation. Doing the arithmentic isn't the
only way that "exact" values to become inexact. Even the mere storing
the number internally in a floating point value might cause it it lose
accuracy. Doing arithmetic simply causes these errors to accumulate,
and therefore be more likely to occur in a result.

For example, this number looks exact, but actually, it's an infinitely
repeating fraction in binary: 0.1

This is true for many "exact" values.

Therefore, you will lose accuracy simply by referencing many decimal
numbers in floating point.

I had to massage my floating point math in C/C++ a lot many years ago,
but I always assumed it was a flaw in the MS compiler, and once I got
in the habit of doing it, I forgot about it.

You have a basic misunderstanding of floating point math if you consider
its rounding and truncation characteristics to be a compiler bug.

As other people have mentioned, there is a BigDecimal class in Ruby
that behaves closer to the way that you want.

Also, consider this: if you always want the computer to give you exact
results, what should these exact results be for each of the following
arithmetic evaluations? ...

a = 1/3
b = Math.atan2(1.0, 1.0)
c = Math.sqrt(5)

How many decimal points should they go to. Where should they round?
 
S

Sean O'Dell

You have a basic misunderstanding of floating point math if you consider
its rounding and truncation characteristics to be a compiler bug.

This is absolutely true; I've never taken any computer class, so I completely
missed that basic information.
As other people have mentioned, there is a BigDecimal class in Ruby
that behaves closer to the way that you want.

Now that I know what it is, I'm fine with returning to old behavior and just
massaging my comparisons.
Also, consider this: if you always want the computer to give you exact
results, what should these exact results be for each of the following
arithmetic evaluations? ...

a = 1/3

Well, this has an infinite decimal value even in plain math. Everyone should
expect his sort of rounding problem. But the simple arithmetic rounding
error is not something you would anticipate without, say, having a professor
point your nose right at it.

Anyway, thanks for the info everyone,

Sean O'Dell
 
P

Phil Tomson

I'm not sure how well known this is. Is it well known as being a problem
or well known as in "you should never do this sort of thing".

Seems to present a major problem if you want to deal with financial
figures, for example. Are there any workarounds?

Sorry to respond to my own post:

Probably the easiest workaround is not to use '==' or '!=' to compare
floating point numbers. Use '>','<' instead.

Or round off. Maybe mathn does what you need it to do.

Phil
 
D

David Heinemeier Hansson

Seems to present a major problem if you want to deal with financial
figures, for example. Are there any workarounds?

Don't use floats for financial figures. Use a Money object, such as the
one[1] Fowler describes in PoEAA. That way you'll be setup for handling
currency issues as well.

[1] http://www.martinfowler.com/eaaCatalog/money.html
--
David Heinemeier Hansson,
http://www.instiki.org/ -- A No-Step-Three Wiki in Ruby
http://www.basecamphq.com/ -- Web-based Project Management
http://www.loudthinking.com/ -- Broadcasting Brain
http://www.nextangle.com/ -- Development & Consulting Services
 
L

Lloyd Zusman

Sean O'Dell said:
This is absolutely true; I've never taken any computer class, so I
completely missed that basic information.


Now that I know what it is, I'm fine with returning to old behavior
and just massaging my comparisons.

One way that we were taught to do floating point comparisons is
to not check for equality, but rather, to check for the result
to be within a certain "delta" of the targeted value. For example:

target = 1547.91
delta = 0.0005 # some suitably small (but not too small!) number
result = 625.91 + 900.00 + 22.00
if (result > target - delta && result < target + delta)
... etc. ...

Well, this has an infinite decimal value even in plain math. Everyone
should expect his sort of rounding problem. But the simple arithmetic
rounding error is not something you would anticipate without, say,
having a professor point your nose right at it.

That's true. Most people find it counter-intuitive to think that values
like 0.1 are inexact in floating point.

Just as the fraction 1/3 is an infinite repeating decimal in base 10,
the fraction 1/10 is also an infinite repeating decimal in base 2
(binary). It can also be shown that your number, 1547.91, is another
value that doesn't have an exact floating point representation.

Anyway, thanks for the info everyone,

Sean O'Dell

I'm glad to help. And please forgive my flippant reply in my earlier
message. It just seemed appropriate in response to your somewhat
strident call to the Ruby community that we fix this floating point
"bug". :)
 
M

Mark Hubbart

Funny though, if I set a variable to 1547.91 exactly, it is
represented just
fine. A value during the arithmetic must be a value which can't be
represented.

I had to massage my floating point math in C/C++ a lot many years ago,
but I
always assumed it was a flaw in the MS compiler, and once I got in the
habit
of doing it, I forgot about it.

just a point here... floats are just one binary integer times two to
the power of another binary integer:

num = 0b11000001011111010001111010111000010100011110101110001 * 0b10
** -0b101010
==>1547.91
"%.43f"%num
==>"1547.9100000000000818545231595635414123535156250"
"%.43f"%1547.91
==>"1547.9100000000000818545231595635414123535156250"

The BigDecimal class uses actual decimal numbers, IIRC. It might be
more appropriate for a calculator app, or something like that. I
suppose it is much slower, however.
Thanks for the info. I'm far less bitter now about having to round the
numbers for comparison. =)

rather than rounding, you might consider:

(625.91 + 900.00 + 22.00) - 1547.91 > 0.0000000001
==>false

or even, for the scope of your app:

class Float
def ==(other)
self - other < 0.000000000001
end
end
==>nil
(625.91 + 900.00 + 22.00) == 1547.91
==>true

or, if you aren't into redefing #==, you might just make a method, say,
#approx_eql?(other) for Float.

cheers,
--Mark
 
M

Michael Geary

Phil said:
[Floating point imprecision seems] to present a major
problem if you want to deal with financial figures, for
example. Are there any workarounds?

Financial calculations aren't done in floating point. There are various
number formats that are used, but they all boil down to some form of integer
arithmetic. For example, fixed point decimal may be used, where the value
$625.91 is represented as the integer 62591 with a scaling factor of two
decimal places. In other words, the arithmetic is actually done in pennies,
not dollars.

-Mike
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,263
Messages
2,571,064
Members
48,769
Latest member
Clifft

Latest Threads

Top