f



Behavior of 0 and 0.0...

I was playing around with the basic math functions, and I had some
questions about the way Ruby handles operations with 0 and 0.0.

first we have:

$ ruby -v
ruby 1.8.6 (2007-09-24 patchlevel 111) [i486-linux]
$ irb
irb(main):001:0> 0/0
ZeroDivisionError: divided by 0
        from (irb):1:in `/'
        from (irb):1

This is OK, it lets us know that we made a mistake somewhere, but when
we try 0.0/0.0 we get:

irb(main):002:0> 0.0/0.0
=> NaN

Mathematically, this is preferable to division error, but, maybe not
from a programming standpoint? The question here is why should these two
events generate different results?

Now, if we try something like 4.0/0.0 we get, what I would consider,
really weird behavior:

irb(main):003:0> 4.0/0.0
=> Infinity

It is true that as x approaches 0 the limit of 1/x goes to infinity, but
this is not the same as 1/0 = infinity. In this case why would infinity
be preferable to the simpler result, NaN? At first I thought this might
be a precision error, that is the parser is saying that 0.0 is not
really 0, just very close. But, if that was the case then 0.0/0.0 would
be 1 instead of NaN.

Thanks!
-- 
Posted via http://www.ruby-forum.com/.

0
1/9/2009 8:51:56 PM
comp.lang.ruby 48885 articles. 0 followers. Post Follow

15 Replies
1025 Views

Similar Articles

[PageSpeed] 59

[Note:  parts of this message were removed to make it a legal post.]


On Jan 9, 2009, at 3:51 PM, Raphael Clancy wrote:

> I was playing around with the basic math functions, and I had some
> questions about the way Ruby handles operations with 0 and 0.0.

I'm guessing that you are seeing IEEE floating point behavior with
the floating point operations and that there isn't a perfect analog
to that behavior with integer operations. IEEE floating
point defines  binary representations of negative and positive zero,
negative and positive infinity, and two types of NaN (not a number).
These 'numbers' aren't available when working with integers at the
machine level nor at the Ruby Fixnum or Bignum level.

Gary Wright




0
gwtmp01 (829)
1/9/2009 9:22:08 PM
Gary Wright wrote:
> 
> On Jan 9, 2009, at 3:51 PM, Raphael Clancy wrote:
> 
>> I was playing around with the basic math functions, and I had some
>> questions about the way Ruby handles operations with 0 and 0.0.
> 
> I'm guessing that you are seeing IEEE floating point behavior with
> the floating point operations and that there isn't a perfect analog
> to that behavior with integer operations. IEEE floating
> point defines  binary representations of negative and positive zero,
> negative and positive infinity, and two types of NaN (not a number).
> These 'numbers' aren't available when working with integers at the
> machine level nor at the Ruby Fixnum or Bignum level.
> 
> Gary Wright

And just to underline the point... these behaviors are not ruby spec, 
but rather IEEE fp spec.

-- 
       vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407

0
vjoel (2601)
1/9/2009 9:25:06 PM
On Jan 9, 2009, at 4:22 PM, Gary Wright wrote:

>
> On Jan 9, 2009, at 3:51 PM, Raphael Clancy wrote:
>
>> I was playing around with the basic math functions, and I had some
>> questions about the way Ruby handles operations with 0 and 0.0.
>
> I'm guessing that you are seeing IEEE floating point behavior with
> the floating point operations and that there isn't a perfect analog
> to that behavior with integer operations. IEEE floating
> point defines  binary representations of negative and positive zero,
> negative and positive infinity, and two types of NaN (not a number).
> These 'numbers' aren't available when working with integers at the
> machine level nor at the Ruby Fixnum or Bignum level.
>
> Gary Wright

In particular, look at how IEEE defines operations such as 0.0/0.0

   http://steve.hollasch.net/cgindex/coding/ieeefloat.html

-Rob

Rob Biedenharn		http://agileconsultingllc.com
Rob@AgileConsultingLLC.com



0
Rob7461 (594)
1/9/2009 9:25:34 PM
Thanks for the quick replies (and the cool link!). I thought this might 
be a hold over from the "good old days". ;)

I wonder if there is any impetus to move beyond this, since I see that 
sticking to the IEEE might cause other problems as well. (Warning, 
grumpy blog ahead)

http://infinitesecond.blogspot.com/2008/03/floating-point-arithmetic-bug-reports.html

On the other hand, the effort of re-doing the whole math framework might 
not be worth the return...
-- 
Posted via http://www.ruby-forum.com/.

0
1/9/2009 10:27:46 PM
On Friday 09 January 2009 23:27:46 Raphael Clancy wrote:
> Thanks for the quick replies (and the cool link!). I thought this might
> be a hold over from the "good old days". ;)
>
> I wonder if there is any impetus to move beyond this, since I see that
> sticking to the IEEE might cause other problems as well. (Warning,
> grumpy blog ahead)
>
> http://infinitesecond.blogspot.com/2008/03/floating-point-arithmetic-bug-re
>ports.html
>
> On the other hand, the effort of re-doing the whole math framework might
> not be worth the return...

Programming languages generally 'sticks' to IEEE 754 simply because that's 
what the hardware can do. You take the numbers and operator, pass it to the 
CPU (or more precise to CPU's math coprocessor) and you'll get output number 
(or NaN,+Inf, etc.). Doing floating point in software is possible if you really 
want to (and there are scientific libraries for precise real number 
calculations that do that), but it is not something you would *like* to do as 
common case, performance-wise.

Jan


0
jan.dvorak (32)
1/9/2009 11:10:03 PM
On Jan 9, 2009, at 4:27 PM, Raphael Clancy wrote:
>
> I wonder if there is any impetus to move beyond this, since I see that
> sticking to the IEEE might cause other problems as well. (Warning,
> grumpy blog ahead)
>
> http://infinitesecond.blogspot.com/2008/03/floating-point-arithmetic-bug-reports.html

Written by someone who does not understand floating point arithmetic.

As Jan Dvorak indicated in another message, most languages stick to  
IEEE spec because the hardware implements the spec. And with good  
reason: it's a good spec.

Your blogger is upset that things don't work the way he wants; perhaps  
he should create a new FP spec and implement it. I guarantee you --  
even ignoring the hardware implemented IEEE -- he won't make a  
representation as complete as IEEE.


0
matt9097 (95)
1/9/2009 11:22:49 PM
I agree that the IEEE spec is closer to what the FPU is doing (actually, 
it is what the FPU is doing ;-D), and this surely gives it a speed 
advantage. But honestly, if speed was what I was after, Ruby might not 
be my first choice. Also, I'm not sure that simply being closer to the 
hardware is always a good thing. After all, I'm pretty glad that Ruby 
doesn't force me to use things like pointers or malloc(), even though 
that's much closer to how the MMU works. The IEEE spec also has one big 
strike against it, it's representation of how numbers work is (just 
slightly) wrong. It's a hold over from the days when computers couldn't 
do any better, but we can certainly do better now.

All that being said, I can come up with several reasons why we should 
keep the IEEE spec. First, it's "traditional" and Ruby always tries to 
work in the way programmers expect it should. Second, dropping the IEEE 
spec in favor of something more mathematically correct would very likely 
break a lot of things that depend on Floats working the IEEE way. And, 
finally, who cares if the IEEE spec is broken? The number of people it 
affects is tiny, and they are likely to use higher precision math 
libraries anyway. The work needed to fix it would far out weigh the 
benefit.

So I guess I'm all for keeping the spec, IEEE is practical, but it 
doesn't seem very "Ruby". ;-D
-- 
Posted via http://www.ruby-forum.com/.

0
1/10/2009 4:13:35 AM
Raphael Clancy <raphael.clancy@gmail.com> wrote:
> 
> [...] I can come up with several reasons why we should 
> keep the IEEE spec. First, it's [ ... ]

One important reason was not mentioned here: In floating point processing we
have limited precision which leads to different semantics. Doing integer
arithmetics 5 is 5, 1 is 1 and 0 is 0. In floating point arithmetics 5.0,
1.0 and 0.0 represent an interval. See the following in irb (on a 32 bit
Linux box):

irb(main):007:0> 10**-200/10.0**200
=> 0.0
irb(main):008:0> -10**-200/10.0**200
=> -0.0
irb(main):009:0> 42.23 / (10**-200/10.0**200) 
=> Infinity
irb(main):010:0> 42.23 / (-10**-200/10.0**200) 
=> -Infinity
irb(main):011:0> (10**200/10.0**-200)
=> Infinity
....

That's simply the closest we can get with limited precision.

Floating point arithmetics _differs_ from doing math on R, and it's
important to know this:

irb(main):031:0> 0.1**2 == 0.01
=> false
irb(main):032:0> 0.1**2 - 0.01
=> 1.73472347597681e-18
irb(main):033:0> (0.1**2 - 0.01) < 1e-9
=> true

> So I guess I'm all for keeping the spec, IEEE is practical, but it 
> doesn't seem very "Ruby". ;-D

You could also claim floating point arithmetics is not very "Ruby2...

Klaus
-- 
http://lapiz.istik.de/

The Answer is 42. And I am the Answer. Now I am looking for the Question.
0
1/10/2009 9:11:53 AM
I've had a little time to think on this (and a little sleep ;-D) and I 
realize that I got sidetracked by the precision issue and it really 
isn't what bothers me. I know that precision has been the focus of most 
of the grumping about the IEEE spec, but keeping track of precision is 
part of using a computer. what bothers me it that using the IEEE spec 
causes Ruby to handle division by zero inconsistently and incorrectly. 
While the precision issue is part of the hardware, but the division by 
zero stuff is a design choice. I realize that the IEEE doesn't set out 
these specs arbitrarily and there must be many good reasons for this 
behavior. But, it seems inelegant to me.

Like I said before, Ruby should stick with the IEEE spec, switching away 
would be a huge hassle, and the benefits would be negligible. But, that 
doesn't mean we shouldn't acknowledge that the IEEE spec has some 
issues. And that even though it's been "good enough" for long time, at 
some point in the future that could possibly change.

Thanks for the good discussion!
-- 
Posted via http://www.ruby-forum.com/.

0
1/10/2009 2:23:12 PM
On Saturday 10 January 2009 15:23:12 Raphael Clancy wrote:
> I've had a little time to think on this (and a little sleep ;-D) and I
> realize that I got sidetracked by the precision issue and it really
> isn't what bothers me. I know that precision has been the focus of most
> of the grumping about the IEEE spec, but keeping track of precision is
> part of using a computer. what bothers me it that using the IEEE spec
> causes Ruby to handle division by zero inconsistently and incorrectly.
> While the precision issue is part of the hardware, but the division by
> zero stuff is a design choice. I realize that the IEEE doesn't set out
> these specs arbitrarily and there must be many good reasons for this
> behavior. But, it seems inelegant to me.

It's still coming from the hardware, you pass fdiv(x,0.0) to FPU and you get 
floating point number back that is either NaN or Infinity. So the "design 
choice" is actually "don't do any additional checking, let the hardware handle 
it". 

I realize that other script languages are more consisent about throwing 
exception, eg. in Python:

>>> 1.0/0.0
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ZeroDivisionError: float division

or Perl:
1.0/0.0
Illegal division by zero at - line 1.

and the same for other operations producing NaN (eg. sqrt(-1)). I don't know 
how much of a good idea would be to follow the same way, but if you wish so, 
you can always use monkey patching to add the checks you need, eg.:

class Float
	alias :olddiv :/
	def /(y)
		if (y==0)
			raise ZeroDivisionError
		else
			self.olddiv(y)
		end
	end
end

p 1.0/0.0

$ruby test.rb
test.rb:7:in `/': ZeroDivisionError (ZeroDivisionError)
	from test.rb:14


Jan


0
jan.dvorak (32)
1/10/2009 3:16:18 PM
> eg. in Python:
> or Perl:
> 1.0/0.0
> Illegal division by zero at - line 1.

What would the equivalent of the following code return in perl or
python then?

a = 1.0; 50.times { a /= 1_000_000_000; p 1.0 / a }

What would you expect to be the result of:

p 1.0 / 0.1 < 1.0 / a

In ruby, it's true.

Maybe it helps to think of 0.0 as 0.0 + eta with eta being too small
to be represented, maybe not. The integer 0 is just 0 and x / 0 is not
a number.

0
micathom (296)
1/10/2009 3:30:57 PM
I learnt a long time ago (probably in Fortran) that it's always a good 
idea to check the value of a divisor before you use it in a division. 
Now doing that comes as second nature.

In Ruby I'd raise an exception. Or if I'm actually expecting to get a 
lot of zeroes and they're not really errors but valid data (e.g. someone 
has used them to mark incomplete data or similar) then I'd take 
appropriate action in place.

Relying on IEEE results is likely to cause problems downstream, so it's 
best to catch these things at the earliest opportunity IMHO. (A bit like 
checking for null pointers in C.)

Dave
-- 
Posted via http://www.ruby-forum.com/.

0
davebass (128)
1/12/2009 11:44:10 AM
> Relying on IEEE results is likely to cause problems downstream, so it's
> best to catch these things at the earliest opportunity IMHO.

You're probably right. This thread made me wonder though if I'd
actually consider a division by zero error more ruby-like as the OP
seemed to suggest. BTW in the meantime, I also checked maple and R and
they both report 1.0/0.0 as infinity.

0
micathom (296)
1/12/2009 1:28:35 PM
I think this is probably is a case of 0.0 is not really 0. After all, as 
much as I might wish it were, a float is not a real. What we really have 
is the case mentioned before, that is 0.0 is really 0 + eta, where eta 
is some very small number which represents a precision error. Earlier, I 
was thrown off by the 0.0/0.0 case, because that would really be (0 + 
eta)/(0 + eta'), and since eta and eta' have similar magnitude this 
value should be around 1, even though we can't know what the number is, 
it certainly in a number. I'm not sure why the IEEE chose to define this 
case as NaN, I think it must have been shorthand for "undefined".

As an interesting (to nerds ;-D) aside, there are several systems in 
which 1/0 is infinity, but they usually depend on fancy geometrical 
tricks, like making the reals occupy a circle or some more complicated 
form instead of a line. So that +infinity == -infinity. That way you can 
make the function f(x)=1/x be "well" defined everywhere. I don't like 
it, but, plenty of people do...
-- 
Posted via http://www.ruby-forum.com/.

0
1/13/2009 3:27:44 PM
On Jan 13, 2009, at 10:27 AM, Raphael Clancy wrote:

> I think this is probably is a case of 0.0 is not really 0. After =20
> all, as
> much as I might wish it were, a float is not a real. What we really =20=

> have
> is the case mentioned before, that is 0.0 is really 0 + eta, where eta
> is some very small number which represents a precision error.

Actually, there are both positive 0 and negative 0 representations in =20=

the IEEE spec.  They are considered equal (-0.0 =3D=3D +0.0).  I believe =
=20
that FORTRAN has both -0.0 and +0.0, too.  There is no =CE=B5 (epsilon) =
for =20
0.0.

> Earlier, I
> was thrown off by the 0.0/0.0 case, because that would really be (0 +
> eta)/(0 + eta'), and since eta and eta' have similar magnitude this
> value should be around 1, even though we can't know what the number =20=

> is,
> it certainly in a number. I'm not sure why the IEEE chose to define =20=

> this
> case as NaN, I think it must have been shorthand for "undefined".

Read the spec.  There are actually two different types of NaN -- one =20
that indicates an indeterminate value (quiet NaN or QNaN) and one that =20=

indicates an operation is not defined (signaling NaN or SNan).

>
>
> As an interesting (to nerds ;-D) aside, there are several systems in
> which 1/0 is infinity, but they usually depend on fancy geometrical
> tricks, like making the reals occupy a circle or some more complicated
> form instead of a line. So that +infinity =3D=3D -infinity. That way =
you =20
> can
> make the function f(x)=3D1/x be "well" defined everywhere. I don't =
like
> it, but, plenty of people do...
> --=20
> Posted via http://www.ruby-forum.com/.

There are similar conventions that give things like 0 raised to the =20
0th power is 1, but 0 raised to any non-zero power is 0.  (You can try =20=

that one in Ruby, too.)

-Rob

Rob Biedenharn		http://agileconsultingllc.com
Rob@AgileConsultingLLC.com



0
Rob7461 (594)
1/13/2009 4:18:10 PM
Reply: