Rounding error?

Hi there,

I’m an absolute beginner in Ruby…

Here’s my problem:

print("Length: ")
s = gets()
length = s.to_f
print("Width: ")
s = gets()
width = s.to_f
surface = length * width
puts(“Surface = #{length} x #{width} = #{surface}”)

When running this code, it asks for Length and Width as expected, but
when I type the values 4.9 and 5.9 it gives 28.910000000000004 as
result.
The values 3.9 and 3.9 give 15.20999999999999 as result.
What do I need to do to avoid these rounding-errors?

Hi,

I don’t face this problem.

When I follow the same code in my machine, I get proper result for
4.9 x 5.9 = 28.91
3.9 x 3.9 = 15.21

I use Ruby 1.8.7. What version are you using?

Cheers,
Vimal

On Fri, Dec 16, 2011 at 1:09 PM, Vimal R. [email protected]
wrote:

Hi,

I don’t face this problem.

When I follow the same code in my machine, I get proper result for
4.9 x 5.9 = 28.91
3.9 x 3.9 = 15.21

You most probably do face the problem, but don’t see it because the
presentation of the result masks the small remainder errors. And
what’s
worse, the result might be dependent on the position of the moon (sorry,
joke, but the result will differ, based on the exact Ruby version, CPU
etc. that is used when the code is ran).

On ruby 1.9.3

peterv@e6500:~$ irb
ruby-1.9.3-p0 :001 > 4.9 * 5.9
=> 28.910000000000004
ruby-1.9.3-p0 :002 > “%35.30f”%(4.9 * 5.9)
=> " 28.910000000000003694822225952521"

On ruby 1.8.7

peterv@e6500:~$ rvm use 1.8.7-p330
Using /home/peterv/.rvm/gems/ruby-1.8.7-p330
peterv@e6500:~$ irb
no such file to load – wirble
ruby-1.8.7-p330 :001 > 4.9 * 5.9
=> 28.91
ruby-1.8.7-p330 :002 > “%35.30f”%(4.9 * 5.9)
=> " 28.910000000000003694822225952521"

HTH,

Peter

On Fri, Dec 16, 2011 at 12:51 PM, Jan Hendrickx
[email protected]wrote:

s = gets()

[Dutch: Dag Jan, welkom op de lijst]

Try to use BigDecimal.

BigDecimal.new(“4.90”) will create an “exact” fractional number in
the decimal system.

Take care that you feed a string to BigDecimal:

Trying this

b = BigDecimal.new(4.9) would still cause the rounding error
so it is not supported.

When ready with calculations, use

big_decimal.to_s to convert back to a string.

A small demo:

peterv@e6500:~$ irb
ruby-1.9.3-p0 :001 > a = BigDecimal.new(“4.90”)
NameError: uninitialized constant BigDecimal
from (irb):1
from /home/peterv/.rvm/rubies/ruby-1.9.3-p0/bin/irb:16:in <main>' ruby-1.9.3-p0 :002 > require 'bigdecimal' => true ruby-1.9.3-p0 :003 > a = BigDecimal.new("4.90") => #<BigDecimal:946ad1c,'0.49E1',18(18)> ruby-1.9.3-p0 :004 > b = BigDecimal.new(4.9) ArgumentError: can't omit precision for a Rational. from (irb):4:in new’
from (irb):4
from /home/peterv/.rvm/rubies/ruby-1.9.3-p0/bin/irb:16:in `’
ruby-1.9.3-p0 :005 > c = BigDecimal.new(“0.245”)
=> #BigDecimal:94238a4,‘0.245E0’,9(18)
ruby-1.9.3-p0 :006 > d = a/c
=> #BigDecimal:941d828,‘0.2E2’,9(45)
ruby-1.9.3-p0 :007 > d.to_s
=> “0.2E2”
ruby-1.9.3-p0 :008 > d.to_s(‘F’)
=> “20.0”

HTH,

Peter

WOW! You guys are realy fast :)))

Vimal R. wrote in post #1037007:

I use Ruby 1.8.7. What version are you using?

I’m using Ruby 1.9.3; downloaded it yesterday, so I suppose that’s the
latest stable version.

Peter V. wrote in post #1037008:

[Dutch: Dag Jan, welkom op de lijst]

[Dutch: Hoi Peter, bedankt voor de verwelkoming :)]

Try to use BigDecimal.
Class: BigDecimal (Ruby 1.9.3)

I changed the test-program like this:

require ‘bigdecimal’
print("Length: ")
s = gets()
length = BigDecimal.new(s)
print("Width: ")
s = gets()
width = BigDecimal.new(s)
surface = length * width
puts(“Surface = #{length.to_f} x #{width.to_f} = #{surface.to_f}”)

It works fine now, but, well… I don’t think it’s very ‘elegant’…
I haven’t had the time yet to read the page on BigDecimal, but I’ll do
that right now.

Mike S. wrote in post #1037010:

It you’re interested in some reading about floating point then
What Every Computer Scientist Should Know About Floating-Point Arithmetic is worth
looking at.

I’ll go and have a look at that too…

Greetings, and thanks to all!
Janosik.

On Fri, Dec 16, 2011 at 2:22 PM, Jan Hendrickx
[email protected]wrote:

puts(“Surface = #{length.to_f} x #{width.to_f} = #{surface.to_f}”)

It works fine now, but, well… I don’t think it’s very ‘elegant’…
I haven’t had the time yet to read the page on BigDecimal, but I’ll do
that right now.

I believe there is no need to convert to float (with to_f).

A problem that I did face is that the default to_s on BigDecimal
gives engineering notation ( the #{length} will execute length.to_s ).

From:

to_s(s) click to toggle source
Converts the value to a string.

The default format looks like 0.xxxxEnn.

I find that non-optimal. I see BigDecimal used mainly for business
calculations
(money, sizes, amounts of goods etc.) and there the ‘g/G’ format
specifier
seems most suited as default …

If the Float (or G) notation was the default, you could simply write
your
original code and it would do the

puts(“Surface = #{length} x #{width} = #{surface}”)

For reference, the “g/G” format specifier (e.g. in C printf):

from: printf - Wikipedia

g, G double in either normal or exponential notation, whichever is more
appropriate for its magnitude. ‘g’ uses lower-case letters, ‘G’ uses
upper-case letters. This type differs slightly from fixed-point notation
in
that insignificant zeroes to the right of the decimal point are not
included. Also, the decimal point is not included on whole numbers.

HTH,

Peter

It you’re interested in some reading about floating point then
What Every Computer Scientist Should Know About Floating-Point Arithmetic is worth
looking at.

Mike

On 2011-12-16, at 7:20 AM, Peter V. wrote:

=> 28.910000000000004
ruby-1.8.7-p330 :001 > 4.9 * 5.9
http://twitter.com/peter_v
http://rails.vandenabeele.com

Mike S. [email protected]
http://www.stok.ca/~mike/

The “`Stok’ disclaimers” apply.