# Really crazy about this (do/while)

**URL:** <https://www.ruby-forum.com/t/really-crazy-about-this-do-while/179322>\
**Category:** Ruby\
**Created:** [November 22, 2009, 4:09am UTC](https://www.ruby-forum.com/t/really-crazy-about-this-do-while/179322 "2009-11-22T04:09:59Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![rubynut](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/8e8cbc/32.png) [@rubynut](https://www.ruby-forum.com/u/rubynut)\
**Post date:** [November 22, 2009, 4:09am UTC](https://www.ruby-forum.com/t/really-crazy-about-this-do-while/179322/1 "2009-11-22T04:09:59Z")

</div>

Hello,

Please see the code and running result below:

# 

# case one

# 

[root@localhost tmp]# cat t5.rb  
temp = 98.4  
i = 0

begin  
i += 1  
puts “step” + i.to\_s + " befre adding is " + temp.to\_s  
temp += 0.1  
puts “step” + i.to\_s + " after adding is " + temp.to\_s  
puts  
end while temp \< 98.6

[root@localhost tmp]# ruby t5.rb  
step1 befre adding is 98.4  
step1 after adding is 98.5

step2 befre adding is 98.5  
step2 after adding is 98.6

OK I think the result is pretty right.

Now I change temp’s original value to 98.3:

# 

# case two

# 

[root@localhost tmp]# cat t5.rb  
temp = 98.3  
i = 0

begin  
i += 1  
puts “step” + i.to\_s + " befre adding is " + temp.to\_s  
temp += 0.1  
puts “step” + i.to\_s + " after adding is " + temp.to\_s  
puts  
end while temp \< 98.6

[root@localhost tmp]# ruby t5.rb  
step1 befre adding is 98.3  
step1 after adding is 98.4

step2 befre adding is 98.4  
step2 after adding is 98.5

step3 befre adding is 98.5  
step3 after adding is 98.6

step4 befre adding is 98.6  
step4 after adding is 98.7

The output of step4 let me crazy.  
Why the loop doesn’t break after step3?  
Because after step3 temp’s value is 98.6, the loop condition was  
checked, and the loop should be end.

Since I think case one is right, so case two get wrong result. Why?  
Thank you.

---

<div class="post-metadata">

**Author:** ![rubynut](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/8e8cbc/32.png) [@rubynut](https://www.ruby-forum.com/u/rubynut)\
**Post date:** [November 22, 2009, 4:17am UTC](https://www.ruby-forum.com/t/really-crazy-about-this-do-while/179322/2 "2009-11-22T04:17:35Z")

</div>

My guess is because floats aren’t exact, so adding .1 ten times isn’t  
precisely the same as adding 1.

Use BigDecimal if you wanna be really accurate.

Julian

Blog: [http://random8.zenunit.com/](http://random8.zenunit.com/)  
Twitter: [http://twitter.com/random8r](http://twitter.com/random8r)  
Learn: [http://sensei.zenunit.com/](http://sensei.zenunit.com/)  
New video up now at [http://sensei.zenunit.com/](http://sensei.zenunit.com/) real fastcgi rails  
deploy process! Check it out now!

---

<div class="post-metadata">

**Author:** ![rubynut](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/8e8cbc/32.png) [@rubynut](https://www.ruby-forum.com/u/rubynut)\
**Post date:** [November 22, 2009, 4:31am UTC](https://www.ruby-forum.com/t/really-crazy-about-this-do-while/179322/3 "2009-11-22T04:31:38Z")

</div>

Ruby N. wrote:

> Since I think case one is right, so case two get wrong result. Why?  
> Thank you.

Welcome to the wonderful world of floating point numbers:

> > 98.4 + 0.1 + 0.1 \< 98.6

# =\> false

> > 98.3 + 0.1 + 0.1 + 0.1 \< 98.6

# =\> true

---

<div class="post-metadata">

**Author:** ![rubynut](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/8e8cbc/32.png) [@rubynut](https://www.ruby-forum.com/u/rubynut)\
**Post date:** [November 22, 2009, 4:45am UTC](https://www.ruby-forum.com/t/really-crazy-about-this-do-while/179322/4 "2009-11-22T04:45:06Z")

</div>

2009/11/22 Florian F. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid):

> # =\> false
> 
> > > 98.3 + 0.1 + 0.1 + 0.1 \< 98.6
> 
> # =\> true

oops that looks amazing.  
thanks~

---

<div class="post-metadata">

**Author:** ![rubynut](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/8e8cbc/32.png) [@rubynut](https://www.ruby-forum.com/u/rubynut)\
**Post date:** [November 22, 2009, 8:15am UTC](https://www.ruby-forum.com/t/really-crazy-about-this-do-while/179322/5 "2009-11-22T08:15:13Z")

</div>

On Saturday 21 November 2009 09:21:59 pm Florian F. wrote:

> Welcome to the wonderful world of floating point numbers:
> 
> > > 98.4 + 0.1 + 0.1 \< 98.6
> 
> # =\> false
> 
> > > 98.3 + 0.1 + 0.1 + 0.1 \< 98.6
> 
> # =\> true

If you want accuracy, and don’t care about performance, you could always  
use  
rationals (fractions):

> > Rational(983,10) + Rational(1,10) + Rational(1,10) + Rational(1,10) \<  
> > Rational(986,10)  
> > =\> false

Of course, beware of trying to convert from floats to rationals:

> > Rational(98.3)  
> > =\> (6917247552664371/70368744177664)

If you look carefully:

> > Rational(98.3).denominator == 2\*\*46  
> > =\> true

That also explains why floats behave strangely in general, for the  
newbies out  
there. When we see 98.3, we see 98 and 3/10ths. But the computer doesn’t  
use  
10ths any more than it uses 10s, 100s, etc. It uses binary, powers of  
two. So  
it converts those 3/10ths to some fraction of a power of two.

Unless, of course, you’re on a mainframe. Then you can do packed decimal  
arithmetic… But it’ll be slower and perversely hard to work with for  
other  
reasons.

So my compromise is, when I want to work with some fraction of a number,  
and I  
want it to be as precise as possible (with no regard for performance), I  
make  
it a Rational as long as I can get away with. I can always call to\_f on  
the  
end result.

I might be Doing It Wrong, though. Maybe BigDecimal is the way to go?

---

<div class="post-metadata">

**Author:** ![rubynut](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/8e8cbc/32.png) [@rubynut](https://www.ruby-forum.com/u/rubynut)\
**Post date:** [November 22, 2009, 3:49pm UTC](https://www.ruby-forum.com/t/really-crazy-about-this-do-while/179322/6 "2009-11-22T15:49:53Z")

</div>

> 

BigDecimal is probably easier to code with, but can kill performance as  
has  
been mentioned previously. Recalling the old Fortran days, we always  
had a  
constant called EPS we used in these kind of situations. EPS (short for  
epsilon) was set to a small number, usually 1e-7. Anytime we needed to  
compare two floating point values, we would not compare them directly,  
but  
rather compare the absolute value of their difference to EPS.

In the original poster’s code, here is how we would have dealt with the  
issue:

eps = 1e-7  
temp = 98.3  
i = 0

begin  
i += 1  
puts “step” + i.to\_s + " befre adding is " + temp.to\_s  
temp += 0.1  
puts “step” + i.to\_s + " after adding is " + temp.to\_s  
puts “temp - 98.6: #{temp-98.6}”  
puts  
#end while temp \< 98.6  
end while (temp - 98.6) \< -eps

Having to remember to do this all the time is difficult and annoying.

-Doug Seifert

---

<div class="post-metadata">

**Author:** ![rubynut](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/8e8cbc/32.png) [@rubynut](https://www.ruby-forum.com/u/rubynut)\
**Post date:** [November 22, 2009, 3:55pm UTC](https://www.ruby-forum.com/t/really-crazy-about-this-do-while/179322/7 "2009-11-22T15:55:09Z")

</div>

David M. wrote:

> So my compromise is, when I want to work with some fraction of a number, and I  
> want it to be as precise as possible (with no regard for performance), I make  
> it a Rational as long as I can get away with. I can always call to\_f on the  
> end result.
> 
> I might be Doing It Wrong, though. Maybe BigDecimal is the way to go?

Another possibility is using a small, but \>0, epsilon and check if the  
distance between the number and the limit is less than its value. Ruby  
does this automatically for you, if you use its #step functions:

> > 98.3.step(98.6, 0.1).to\_a

# =\> [98.3, 98.4, 98.5, 98.6]

> > 98.4.step(98.6, 0.1).to\_a

# =\> [98.4, 98.5, 98.6]

> > (98.3…98.6).step(0.1).to\_a

# =\> [98.3, 98.4, 98.5, 98.6]

> > (98.4…98.6).step(0.1).to\_a

# =\> [98.4, 98.5, 98.6]

Maybe the general advice here is, don’t do it yourself, if Ruby offers a  
better way itself.

---

<div class="post-metadata">

**Author:** ![rubynut](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/r/8e8cbc/32.png) [@rubynut](https://www.ruby-forum.com/u/rubynut)\
**Post date:** [November 22, 2009, 5:09pm UTC](https://www.ruby-forum.com/t/really-crazy-about-this-do-while/179322/8 "2009-11-22T17:09:54Z")

</div>

David M. wrote:  
[…]

> So my compromise is, when I want to work with some fraction of a number,  
> and I  
> want it to be as precise as possible (with no regard for performance), I  
> make  
> it a Rational as long as I can get away with. I can always call to\_f on  
> the  
> end result.
> 
> I might be Doing It Wrong, though. Maybe BigDecimal is the way to go?

I think it is. Rational makes sense if you’re starting from an integer  
division. But the OP is starting from a float (98.3), so BigDecimal is  
probably the way to go.

## Best,

Marnen Laibow-Koser  
[http://www.marnen.org](http://www.marnen.org)  
removed\_email\_address@domain.invalid
