4

IEEE 754 specifies the result of 1 / 0 as ∞ (Infinity).

However, IEEE 754 then specifies the result of 0 × ∞ as NaN.

This feels counter-intuitive: Why is 0 × ∞ not 0?

  1. We can think of 1 / 0 = ∞ as the limit of 1 / z as z tends to zero

  2. We can think of 0 × ∞ = 0 as the limit of 0 × z as z tends to ∞.

Why does the IEEE standard follow intuition 1. but not 2.?

le_m
  • 19,302
  • 9
  • 64
  • 74
  • 1
    Because Infinity isn't a concrete number? – Michael Todd Jun 15 '16 at 16:49
  • 2
    [Infinity * 0 isn't so easily defined.](http://math.stackexchange.com/questions/28940/why-is-infinity-multiplied-by-zero-not-an-easy-zero-answer) – Mike Cluck Jun 15 '16 at 16:51
  • @MichaelTodd If that would be the only explanation, then `Infinity / 0` should be `NaN`, too, but it isn't – le_m Jun 15 '16 at 16:51
  • 1
    But in the case of `Infinity / 0`, doesn't the division by zero take precedence over whatever happens to be in the numerator? (I'm not arguing mathematics rigorously here. I'm just guessing the intent of the language author.) – Michael Todd Jun 15 '16 at 16:52
  • @le_m Because there's different ways of interpreting that and [because of how floating point numbers are calculated.](http://stackoverflow.com/questions/18838301/in-javascript-why-does-zero-divided-by-zero-return-nan-but-any-other-divided-b) – Mike Cluck Jun 15 '16 at 16:54
  • You can read the specification here (if you have an account): http://ieeexplore.ieee.org/xpl/articleDetails.jsp?arnumber=4610935&filter=AND(p_Publication_Number:4610933) – Felix Kling Jun 15 '16 at 16:54
  • 1
    Infinity **is** a number in javascript, at least by type, but it's not really a concrete number, it's not, say, `7` or anything like that, it's more of a concept, *"the largest number there is"* etc. When you multiply infinity with any positive or negative number, you get positive or negative Infinity, as it can't be any larger. When you divide a number by Infinity, you get `0` as it can't be any smaller. When you multiply Infinity with `0` you get "Not A Number", as someone decided that would be the logical thing to do, and put it in the spec. – adeneo Jun 15 '16 at 16:54
  • Infinity is not a concrete number. It is merely a concept. You can only actually tend to infinity, never attain it. `Infinity * 0` is meaningless and undefined (in a mathematical sense). Hence, NaN. – ManoDestra Jun 15 '16 at 16:57
  • @ManoDestra You are right, of course. Depending on the definition of `Infinity * 0` (an infinite sum? indeterminate form?), there are different results for `Infinity * 0`. But those setting the standard *did* make some decisions, e. g. `Infinity / 0 == Infinity`. Why not here, too? – le_m Jun 15 '16 at 17:19
  • Division by zero is defined as infinity. The division by zero takes precedence over the value on the numerator. If you think about any number tending to infinity, division by zero will be undefined, as the denominator approaches zero, any number on top will increase, even "infinitely" large ones. However, multiplying infinity by zero is a very different matter, as you are trying to "zeroise" an infinity quantity (which is merely conceptual to begin with). JavaScript simply makes sensible choices given this and they are quite rightly different results based on the operations involved. – ManoDestra Jun 15 '16 at 17:31
  • I reworded the question to make it more clear. Thanks for your valuable input so far! – le_m Jun 15 '16 at 18:02
  • 3
    Why not think of 0*Infinity as the limit of x*infinity as x tends to zero? It makes as much sense as the other way round. The problem with 0*Infinity, and the reason it should be a NaN, is that it is possible to come up with a case for 0, Infinity, and anything in between. – Patricia Shanahan Jun 15 '16 at 20:02
  • @PatriciaShanahan Why not? Because infinity is clearly not a *real* number but something else, e.g. a limit. But when I write 0, I explicitly mean 0 - not 0 +/- something. However, as your very good answer points out: There is no distinction between a *really 0, I mean it!* and *actually bigger than 0 and only 0 because the actual value cannot be represented*. Your answer helped me get that! – le_m Jun 15 '16 at 20:19

1 Answers1

10

It is easier to understand the behavior of IEEE 754 floating point zeros and infinities if you do not think of them as being literally zero or infinite.

The floating point zeros not only represent the real number zero. They also represent all real numbers that would round to something smaller than the smallest subnormal. That is why zero is signed. Even tiny numbers do have a sign if they are not actually zero.

Similarly, each infinity also represents all numbers with the corresponding sign that would round to something with a magnitude that would not fit in the finite range.

NaN represents either "No real number result", for example sqrt(-1), or "Haven't a clue".

Something very big divided by something very small is very, very big, so `Infinity / 0 == Infinity".

Something very big multiplied by something very small could be anything, depending on the actual magnitudes that we don't know. Since the result could be anything from very small through very big, NaN is the most reasonable answer.

=================================================================

Although I think the above is the best way to understand practical floating point behavior, a similar issue arises in real number limits.

Suppose f(x) tends to infinity and g(x) tends to zero as x tends to infinity. It is easy to prove that f(x)/g(x) tends to infinity as x tends to infinity. On the other hand, it is not possible to prove anything about the limit of f(x)*g(x) without more information about the functions.

Patricia Shanahan
  • 25,849
  • 4
  • 38
  • 75
  • So we should think of 0 more as a very small quantity instead of actual 0, since it is the result of many arithmetic computations for which arithmetic underflow occurs? That seems sensible! – le_m Jun 15 '16 at 18:17
  • I disagree with this answer. Thinking of floating-point numbers as representing small ranges of values is the root of much confusion, and we should not encourage it. Zeroes represent exactly zero (a fact the OP has no trouble with, otherwise they would not accept that 0 times anything should be zero so easily) and infinities represent exceptional values conceptually beyond all reals (this is the point that the OP does not already accept). – Pascal Cuoq Jun 15 '16 at 21:08
  • Both floating-point zeroes and infinities can be obtained as approximations of FP computations that, in the reals, did not result in zero or infinity. That approximation was then. What we have now is a floating-point value that represents exactly zero, and one that represent exactly infinity, respectively. – Pascal Cuoq Jun 15 '16 at 21:09
  • 2
    @PascalCuoq In your model, what is negative zero and why does it exist? – Patricia Shanahan Jun 15 '16 at 21:12
  • "Thinking of floating-point numbers as representing small ranges of values is the root of much confusion, and we should not encourage it". I am not aware of harmful confusion of this nature, are you referring to the never-ending discussions on trig functions of large arguments maybe? I think the mental model of each floating-point number actually representing a small interval (as the consequence of rounding) is often useful, such as in this case; likewise useful is a look at limits (which I think is what Patricia is alluding to with respect to negative zero), e.g. when considering branch cuts. – njuffa Jun 15 '16 at 21:51
  • -0. is another representation of 0 and it exists to avoid complicating the sign-magnitude representation. What is -0. in your interpretation? A small negative interval? The opposite of 0.0 - 0.0. Why is sqrt(-0.) what it is? – Pascal Cuoq Jun 16 '16 at 06:59
  • @njuffa trig functions of large arguments , the idea that on a desktop OS like Windows it's acceptable not to produce digits after the 17th significant one in conversions to decimal, the superstition that `double x = y; int c = x == y;` might not set `c` to 1 for finite or infinite values of `y`, … – Pascal Cuoq Jun 16 '16 at 07:06
  • @njuffa …and perhaps, as if often repeated here, most programmers should not use `==` between floating-point values, but you can observe the same superstition about `double x = y; int c = x > y;` – Pascal Cuoq Jun 16 '16 at 07:51
  • 3
    @PascalCuoq Never comparing floating-point values with "==" is non-sense and this "rule" is repeated mindlessly without justification, not by recourse to a "small interval" model, as far as I have seen. To my knowledge, -0 exists not simply for the convenience of format orthogonality, but by conscious design: see Kahan's paper on branch cuts in complex functions, -0 represents a limit when approaching zero from below; also for smooth interaction with infinities, e.g. 1/x where x is negative and underflows. Not producing digits unnecessary to uniquely identify a `binary64` seems fine to me? – njuffa Jun 16 '16 at 14:23
  • 5
    My view of floating-point numbers is similar to wave/particle dualism in physics: Sometimes it is best to think of an fp number as a point, at other times it is best to think of it as an interval, depending on context. When dealing with large arguments to trig functions, a library writer has no knowledge of which context-dependend view is appropriate, so needs to err on the conservative (point) side. As for sqrt(-0)==0, I don't recall what drove that, it does not make sense under an "approach zero in the negative half-plane (via underflow)" mental model, but needed for consistency with +0==-0? – njuffa Jun 16 '16 at 15:13