Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does ruby handle zero division?

Tags:

ruby

zero

I am trying to find out how ruby handles zero division. Ruby returns different results based on the class. This is what I tried

0/0     # => ZeroDivisionError: divided by 0    
1/0     # => ZeroDivisionError: divided by 0
1.0/0   # => Infinity
0.0/0.0 # => NaN

What is happening here? Shouldn't I get a ZeroDivisionError for all the above cases?

Update Is "Infinity" a standard data type, then?

(1.0/0).class  # => Float
like image 657
ZX12R Avatar asked Aug 08 '13 12:08

ZX12R


3 Answers

Ruby just tracks the IEEE 754 Floating Point Standard. That Wikipedia page is not bad at explaining what you are seeing. Many modern languages take the same approach.

Intuitively, the behavior you see makes perfect sense. In general,

1/<small number> = <big number>

Therefore in the limit,

1/0 -> Infinity    and similarly    -1/0 -> -Infinity

Infinity is a constant understood by the floating point subsystem. On the other hand

0 / <any non-zero> = 0

So we have a conflict on 0/0. Should it be zero or infinity? The IEEE standard answer is "Not a Number", the NaN you are seeing, another floating point constant.

The constants NaN and plus or minus Infinity propagate through expressions in a way that also makes sense. For example:

Infinity + <any (necessarly finite) number> = Infinity

and

<any number> + NaN = NaN

And more interestingly:

1 / Infinity = 0

Which you can try yourself:

irb(main):005:0> 1.0 / (1.0 / 0.0)
=> 0.0

In this manner a floating point calculation can continue even when it has overflowed or divided by zero and still produce a reasonably informative answer (though after you know the standard well, you'll see that relying on the answer is usually a bad idea).

This is far from the only behavior that the Standard provides. Others can be selected. But Ruby does this for you. The source file numeric.c, function Init_Numeric, sets up the host processor so that division by zero propagates infinities. Other languages might make other choices, for example to generate an exception.

like image 117
Gene Avatar answered Dec 03 '22 09:12

Gene


The behavior for floating points reflects the standard in IEEE 754:

  • Invalid operation (e.g., square root of a negative number) (returns qNaN by default).
  • Division by zero (an operation on finite operands gives an exact infinite result, e.g., 1/0 or log(0)) (returns ±infinity by default).

The decision to implement a runtime error for integer division by zero is common across many other languages as well such as Java, C++, Python. Python actually calls the error ZeroDivisionError as well.

See sawa's answer for the reasons for these classifications and behaviors.

like image 20
fny Avatar answered Dec 03 '22 09:12

fny


The point is that a float has a rounding error. A float 0.0 is not necessarily expressing exact zero, or 0.0 in the mathematical sense, but is representative of all numbers that would be rounded to 0.0 given the precision. Division by exact 0 is not mathematically defined, but prohibiting division by 0.0 would have danger of returning an error in case the divisor happened to have a non-zero absolute value small enough to be rounded to 0.0. You don't want a program to suddenly return an error when the absolute value of the divisor is small when it is not zero. In case of floats, it is safer to have the system assign a certain number to division by 0.0 rather than to prohibit it. But that number cannot be expressed in a normal way, so it is assigned NaN or Infinity. What is misleading about this is that Infinity is not infinity in the mathematical sense. It just means "a number larger than any other number that can be expressed in this system." That explains the case of:

1.0/0.0 # => Infinity
0.0/0.0 # => NaN

When one argument to / is a float, Ruby type-casts the other to float, so

1/0.0
1.0/0

would be the same as 1.0/0.0.

On the other hand, the integer 0 does not include an error, and is exact zero, so there is no such danger. It makes more sense to raise a zero division error. That explains

1/0 # => Error
0/0 # => Error
like image 21
sawa Avatar answered Dec 03 '22 07:12

sawa