floating point rounding error?

R

Roger Pack

1999.0.ceil
19992000

is this expected?
Is there any BigFloat that avoids this?
Thanks!
-=r
 
T

Tom Link

Is there any BigFloat that avoids this?

BigDecimal:

require 'bigdecimal'
((BigDecimal("12.99")+BigDecimal("7.0"))*100).ceil
=> # said:
((BigDecimal("12.99")+BigDecimal("7.0"))*100).to_f.ceil
=> 1999

I think you have to take care though that the BigDecimal isn't
converted back into a normal float.
(BigDecimal("12.99")+7.0).class
=> Float
 
R

Robert Klemme

2000

is this expected?

Float computer math is full of those effects - and so are the archives
of this list with articles similar to yours.

Kind regards

robert
 
R

Roger Pack

Float computer math is full of those effects - and so are the archives
of this list with articles similar to yours.

I hate those subtle rounding errors. Any thoughts if I were to suggest
Ruby by default use BigDecimal instead of float?
i.e.
7.0 + 7.0
is parsed as two bigdecimals, and to use floats you do Float(7.0) or
Float.new(7.0)
?
 
R

Robert Klemme

I hate those subtle rounding errors. Any thoughts if I were to suggest
Ruby by default use BigDecimal instead of float?

Yes. There are several reasons against IMHO:

1. existing code might be broken

2. efficiency (Float is faster than BigDecimal)

3. standards (AFAIK the Float implementation is backed by an ISO
standard while I am not sure whether this is the case for BigDecimal).

4. limited use: while your particular example will work as you expect,
BigDecimal is still not a real number (in math terms) but still a
rational number => rounding errors for other numbers will be introduced
when switching from Float to BigDecimal by default.

Sorry to disappoint you, but I'd say this is the learning experience
everybody in programming has to undergo: floats are inherently unsafe,
even more, computer representations of mathematical constructs like
numbers are always imperfect and it is your responsibility of the writer
of a program to ensure you properly deal with this mismatch.

One solution which comes to mind is this: have an extension or rather a
command line switch which changes the default behavior. But this in
itself is not without problems either: library code might suddenly start
to fail when Ruby is started with the BigDecimal flag etc.

Kind regards

robert
 
R

Roger Pack

1. existing code might be broken

True
2. efficiency (Float is faster than BigDecimal)

Can't disagree with that.

3. standards (AFAIK the Float implementation is backed by an ISO
standard while I am not sure whether this is the case for BigDecimal).
True.

4. limited use: while your particular example will work as you expect,
BigDecimal is still not a real number (in math terms) but still a
rational number => rounding errors for other numbers will be introduced
when switching from Float to BigDecimal by default.

The only real benefit of it is that it won't bite "as often," for better
or worse.
This is a learning curve that could hit you at the edges [adding
extremely small and extremely large numbers, for example] and not during
normal day use :)

One "almost good" answer would be to have ruby output float to strings
by default with enough precision to be able to recreate the original.


Thoughts?
-=r
 
R

Raphael Clancy

Roger said:
Can't disagree with that.



True.

In this case, I think it's IEEE.
4. limited use: while your particular example will work as you expect,
BigDecimal is still not a real number (in math terms) but still a
rational number => rounding errors for other numbers will be introduced
when switching from Float to BigDecimal by default.

The only real benefit of it is that it won't bite "as often," for better
or worse.
This is a learning curve that could hit you at the edges [adding
extremely small and extremely large numbers, for example] and not during
normal day use :)

You don't even have to get into numbers that are that big...

irb(main):001:0> a = (10.11 * 100).to_i
=> 1011
irb(main):002:0> b = (10.12 * 100).to_i
=> 1011
irb(main):003:0> a == b
=> true
One "almost good" answer would be to have ruby output float to strings
by default with enough precision to be able to recreate the original.


Thoughts?
-=r

This behavior isn't limited to ruby, any language which uses the IEEE
spec for floating point exhibits the same behavior. For example the C++
code that matches the ruby above gives the same result...

#include <iostream>

using namespace std;

int main(int argc, char* argv[]) {
float x = 10.12;
int y = (int) (x * 100.0);
cout << x << " , " << y << endl;
return(0);
}

gives: 10.12 , 1011

I guess the take home is to avoid floats whenever you'll be doing any
rounding or truncating.
 
R

Robert Klemme

Roger Pack wrote:

In this case, I think it's IEEE.

Right, thanks for the correction!
I guess the take home is to avoid floats whenever you'll be doing any
rounding or truncating.

I would not go as far. IMHO the take home should be awareness of the
fact that mathematical numbers do not blend well with any computerized
representation and that you always have to be careful when dealing with
them. Floats are perfectly ok for a large number of applications so
generally avoiding them seems a too harsh rule. Btw, if that were true
then we could throw them out of the language without loss but I am
pretty sure if you suggest that there would be vigorous objection. :)

Kind regards

robert
 
R

Raphael Clancy

Robert said:
I would not go as far. IMHO the take home should be awareness of the
fact that mathematical numbers do not blend well with any computerized
representation and that you always have to be careful when dealing with
them. Floats are perfectly ok for a large number of applications so
generally avoiding them seems a too harsh rule. Btw, if that were true
then we could throw them out of the language without loss but I am
pretty sure if you suggest that there would be vigorous objection. :)

Kind regards

robert

I totally agree with you, I guess what I was trying to say is that due
to rounding error floats aren't appropriate for low precision
computations or areas where you are likely to have to convert to int.
It's better to use BigDecimal or to handle the decimal portion in some
other way.

R.
 

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
473,755
Messages
2,569,537
Members
45,021
Latest member
AkilahJaim

Latest Threads

Top