67

Prompted by a spot of earlier code golfing why would:

>NaN^0
[1] 1

It makes perfect sense for NA^0 to be 1 because NA is missing data, and any number raised to 0 will give 1, including -Inf and Inf. However NaN is supposed to represent not-a-number, so why would this be so? This is even more confusing/worrying when the help page for ?NaN states:

In R, basically all mathematical functions (including basic Arithmetic), are supposed to work properly with +/- Inf and NaN as input or output.

The basic rule should be that calls and relations with Infs really are statements with a proper mathematical limit.

Computations involving NaN will return NaN or perhaps NA: which of those two is not guaranteed and may depend on the R platform (since compilers may re-order computations).

Is there a philosophical reason behind this, or is it just to do with how R represents these constants?

Henrik
  • 65,555
  • 14
  • 143
  • 159
Simon O'Hanlon
  • 58,647
  • 14
  • 142
  • 184
  • I don't know for R but the same is happening in Python on my machine together with the similarly wrong: 1**nan returning 1.0 – hivert Jul 25 '13 at 22:40
  • 6
    @hivert at least in the case of R `^` is a function that doesn't just call the `C` function `pow`, it checks for the case where the base is 1 or the exponent is 0 and if either is `TRUE` it returns `1.` before ever calling `pow`: `if((x1 = INTEGER(s1)[i1]) == 1 || (x2 = INTEGER(s2)[i2]) == 0); REAL(ans)[i] = 1.;` – Simon O'Hanlon Jul 25 '13 at 22:44
  • 3
    I'm not convinced ``NA^0 == 1`` makes much sense either because ``Inf^0`` is an indeterminate form. That is, when viewed as a limit we cannot determine from this form alone what the value of the original limit was. For example, as n approach infinity, ``exp(n)^*(1/n)`` approaches e, but ``n^(1/n)`` approaches 1 even though both look like ``Inf^0``. – orizon Jul 26 '13 at 00:34
  • Just a comment about this: "any number raised to 0 will give 1, including -Inf and Inf": for -Inf and +Inf, the value should be NaN, as these are undeterminate limits. Think of (1 + 1/x)^x when x approaches 0. –  Jul 31 '13 at 05:50

6 Answers6

28

This is referenced in the help page referenced by ?'NaN'

"The IEC 60559 standard, also known as the ANSI/IEEE 754 Floating-Point Standard.

http://en.wikipedia.org/wiki/NaN."

And there you find this statement regarding what should create a NaN:

 "There are three kinds of operations that can return NaN:[5]
       Operations with a NaN as at least one operand.

It is probably is from the particular C compiler, as signified by the Note you referenced. This is what the GNU C documentation says:

http://www.gnu.org/software/libc/manual/html_node/Infinity-and-NaN.html

" NaN, on the other hand, infects any calculation that involves it. Unless the calculation would produce the same result no matter what real value replaced NaN, the result is NaN."

So it seems that the GNU-C people have a different standard in mind when writing their code. And the 2008 version of ANSI/IEEE 754 Floating-Point Standard is reported to make that suggestion:

http://en.wikipedia.org/wiki/NaN#Function_definition

The published standard is not free. So if you are have access rights or money you can look here:

http://ieeexplore.ieee.org/xpl/mostRecentIssue.jsp?punumber=4610933

IRTFM
  • 258,963
  • 21
  • 364
  • 487
  • Thanks. I decided to accept this as an answer because I think there is enough linked reading that as you point out answers the design decision. But the R documentation on `NaN` should maybe be tweaked on the `?NaN` page to mention that operations involving NaN always result in Na or NaN except when raising to 0. Thanks – Simon O'Hanlon Jul 25 '13 at 19:01
  • ... except that the R documentation might say "except *possibly* when raising to zero, depending on the platform" (it's not clear to me from the answer whether `NaN^0` is 1 on all possible OSs with all possible compilers ...) – Ben Bolker Jul 25 '13 at 21:27
  • 1
    I added the Note from the help page. (I certainly wasn't intending to cover "all possible compilers".) And I would say that the current behavior with the GNU-C compiler is not agreeing the "Note". – IRTFM Jul 25 '13 at 21:37
  • @BenBolker unfortunately the comments thread under the OP got too long and was nuked in its entirety. But it was previously pointed out that if we believe the documentation for `^` then: 1 ^ y and y ^ 0 are 1, *always*. But that is perhaps due to how R does exponentiation as I pointed to in [R chat](http://chat.stackoverflow.com/transcript/message/10841115#10841115) and not because of compiler standards. – Simon O'Hanlon Jul 25 '13 at 22:36
  • -1, for three reasons. (1) Why are you talking about C? This is a question about R. (2) C doesn't even **have** a *"to the power of"* operator, so what the C-standard says about operations on NaN is irrelevant, even if it was the right language. (3) Everything you've quoted here seems to indicate that `NaN^0` should be `NaN`, not `0`. So even if this was about the correct language, how does this answer the question!? – BlueRaja - Danny Pflughoeft Jul 25 '13 at 22:42
  • 1
    @BlueRaja-DannyPflughoeft the equivalent C function is `pow`. The inbuilt exponentiation function, `^` in R calls `pow` via some checks on the arguments that were passed to it. `NaN^0` is equivalent in R to `\`^\`(NaN,0)`. See my comment below the OP for the R source code (written in C) that is executed *before* `pow` is called. I think DWin is pretty familiar with R. – Simon O'Hanlon Jul 25 '13 at 22:48
  • 1
    @BlueRaja-DannyPflughoeft: I started the search for authoritative descriptions with the help page for 'NaN'. It directed me to the IEEE standard. R is written in C, so it seemed possible that an edge case like this might be determined in practice by the "usual" behavior of NaN with "^" in the GNU-C-compiler. Answers come in many flavors, oftentimes historical, as appears to be the case here. – IRTFM Jul 25 '13 at 22:56
  • @DWin: I imagine that the GNU-C people have the C standard in mind. :-) C99 Annex F (specifically F.9.4.4), explicitly makes this recommendation: "pow(x, ±0) returns 1 for any x, even a NaN.". – Mark Dickinson Jul 26 '13 at 12:25
  • By the way, I do think the 'floating-point' tag makes sense for this question: there are lots of floating-point experts it would attract who can give definitive answers to what's going on at the C and IEEE 754 level (but not necessarily at R level). – Mark Dickinson Jul 26 '13 at 12:27
  • 1
    It also says "In R, basically all mathematical functions (including basic ‘Arithmetic’), are supposed to work properly with ‘+/- Inf’ and ‘NaN’ as input or output." So I think this is a bug in R - in particular, `NA ^ 0 == 1" is definitely wrong. – hadley Jul 26 '13 at 13:38
  • @MarkDickinson: Added back a tag for floating-point exceptions. I take your point, Hadley. Do you want to report the bug? Your standing with R Core is probably a lot higher than mine. – IRTFM Jul 26 '13 at 15:00
  • @hadley I don't believe that `NA^0==1` is wrong, because all elements of a vector in R must be of the same type. I can't `^` a non-numeric `NA` (e.g. an `NA` in a character vector or just `NA_character_^0`), R rightly tells me I'm supplying a non-numeric argument. However conceptually in a numeric vector `NA` should just mean *I don't know what this number is*, but it's still a number therefore `NA^0` should *always* `== 1`. Conceptually I don't know about `NaN` which is why the question arose. – Simon O'Hanlon Jul 26 '13 at 20:34
  • 1
    @SimonO101 I don't see why the class of the element is relevant: `NA_real_ ^ 0` is 1, clearly defying the usual missing value propagation rules: `NA_real_ * 0`, is `NA`, not 0. – hadley Jul 28 '13 at 01:02
  • @hadley `NA_real_ * 0` should be `NA` not `0` because `NA_real_` could represent `Inf` and `Inf * 0` is undefined (or `NaN` in R speak), hence it *might not* be `0`, however *any* number `^` 0 is `1` including `Inf` and `-Inf` so *should always* `== 1`. The only case that is obviously (to my mind) wrong is `NaN ^ 0`. – Simon O'Hanlon Jul 30 '13 at 13:21
  • GNU C quote in answer: `Unless the calculation would produce the same result no matter what real value replaced NaN, the result is NaN.` OP: `any number raised to 0 will give 1, including -Inf and Inf.` Sounds suspiciously like a valid explanation to me. – brichins Jul 30 '13 at 23:38
  • @SimonO101 Ah, that makes sense. I didn't realise the difference in behaviour between `Inf ^ 0` and `Inf * 0`. – hadley Jul 31 '13 at 13:15
  • I don't understand what mathematically coherent path one can take to conclude that `Inf*0` is undefined while `Inf^0` isn't? – eddi Nov 23 '13 at 23:04
20

The answer can be summed up by "for historical reasons".

It seems that IEEE 754 introduced two different power functions - pow and powr, with the latter preserving NaN's in the OP case and also returning NaN for Inf^0, 0^0, 1^Inf, but eventually the latter was dropped as explained briefly here.

Conceptually, I'm in the NaN preserving camp, because I'm coming at the issue from viewpoint of limits, but from convenience point of view I expect current conventions are slightly easier to deal with, even if they don't make a lot of sense in some cases (e.g. sqrt(-1)^0 being equal to 1 while all operations are on real numbers makes little sense if any).

eddi
  • 49,088
  • 6
  • 104
  • 155
  • That link is interesting reading. I would have liked R's `min` and `max` to ignore NaN's, but for NaN^1 to be NaN. Ya' can't always get what you want. – IRTFM Jul 25 '13 at 17:57
  • 1
    I believe the final version of the IEEE754-2008 standard does in fact have both `pow` and `powr`, as well as `pown` for raising an arbitrary float to an integral power. `pow(qNaN, 0)` and `pown(qNaN, 0)` are defined as `1`; `powr(qNaN, 0)` signals the invalid operation exception, and so returns a `qNaN` under default FP exception handling. – Mark Dickinson Jul 26 '13 at 12:19
  • 1
    Very interesting reading on history of IEEE 754. NaN preserving has another advantage (for min/max or for anything else): NaN may have appeared in a previous computation, which, in other circumstances would have given a usable double value, which could have been compared/used/... NaN is then viewed as an exceptional value, and merely an error (for some reason, as overflow, the computation gone bad). Preserving NaN allows to at least see in the end that there was an error somewhere, and won't give silently an incorrect answer. Signaling NaNs are also a way to trap the error when it happens. –  Aug 21 '13 at 13:50
  • The "NaN preserving" concept is practically identical to "NA preserving". So in numerical computations, NA and NaN are always (?, can you find an exeption ?) treated equally / analogously. More in a separate "reply" below. Re `sqrt(-1)^0` : this is *exactly* a good example why NaN^0 should give 1: `sqrt(-1 + 0i)^0` indeed gives 1 (+0i): ``sqrt(-1+0i)^0 == 1`` is indeed `TRUE` – Martin Mächler Nov 23 '13 at 17:20
  • @MartinMächler you're missing the point. Let's say I define my own function which is **only** defined on the set `[0,Inf)` and is not defined otherwise: `f = function(x) {if (x >= 0) x else NaN}`. In no sense would `f(-1)^0` be equal to `1`, yet R would tell you that it is. – eddi Nov 23 '13 at 17:35
  • @eddi: I'm not sure what you mean by "In no sense would `f(-1)^0` be equal to one?" How about in the sense that for integer powers, x^n is defined as "unity if n==0, (x^(n-1))*x if n is positive, or (x^(n+1))/x if n is negative". I've never seen any definition whose n==0 case required that x be defined. – supercat Nov 23 '13 at 19:24
  • @supercat in this example there is no `x` you speak of - I'll make a comment in your answer that might make it more clear to you – eddi Nov 23 '13 at 22:01
18

Yes, I'm late here, but as R Core member who was involved in this design, let me recall what I commented above. NaN preserving and NA preserving work "equivalently" in R, so if you agree that NA^0 should give 1, NaN^0 |-> 1 is a consequence.

Indeed (as others said) you should really read R's help pages and not C or IEEE standards, to answer such questions, and SimonO101 correctly cited

1 ^ y and y ^ 0 are 1, always

and I'm pretty sure that I was heavily involved (if not the author) of that. Note that it is good, not bad, to be able to provide non-NaN answers, also in cases other programming languages do differently. The consequence of such a rule is that more things work automatically correctly; in the other case, the R programmer would have been urged to do more special casing herself.

Or put differently, a simple rule as the above (returning non-NaN in all cases) is a good rule, because it propagates continuity in a mathematical sense: lim_x f(x) = f(lim x). We have had a few cases where it was clearly advantageous (i.e. did not need special casing, I'm repeating..) to adhere to the above "= 1" rule, rather than to propagate NaN. As I said further up, the sqrt(-1)^0 is also such an example, as 1 is the correct result as soon as you extend to the complex plane.

Martin Mächler
  • 4,619
  • 27
  • 27
  • lol, why would anyone agree that `NA^0` should give 1 if they think `NaN^0` should not? `NA` is a superset of `NaN`. You got the if-else direction wrong. – eddi Nov 23 '13 at 17:40
  • Well, the OP did exactly say that! – Martin Mächler Nov 23 '13 at 18:26
  • :) fair enough - *both* of you should know better then – eddi Nov 23 '13 at 18:43
  • and why on earth was my summarizing remarks, from the one person who knew the answer to the question "why?" because I've co-implemented it, be *down*voted. .. heaven gracious! – Martin Mächler Nov 23 '13 at 19:00
  • the -1 is from me and is mainly because you state that this choice is "good" without any argument to support it – eddi Nov 23 '13 at 22:06
  • re your edit: no, you missed the point further up, and are still missing it – eddi Dec 01 '13 at 03:18
  • (Mainly) for others reading this - `NaN` is an abbreviation of "not a number", and is frequently used exactly as such - as **not** a number, but rather a stand-in for something else. A simple example of that is `as.numeric('blah')`, which returns a `NaN`. In that use case of `NaN`, it makes no sense whatsoever to return a 1, irrespective of that weak attempt at using limits to justify this choice. – eddi Dec 01 '13 at 03:32
5

Here's one reasoning. From Goldberg:

In IEEE 754, NaNs are often represented as floating-point numbers with the exponent e_max + 1 and nonzero significands.

So NaN is a floating-point number, though with a special meaning. Raising a number to the power zero sets its exponent to zero, therefore it will no longer be NaN.

Also note:

> 1^NaN
[1] 1

One is a number whose exponent is zero already.

James
  • 65,548
  • 14
  • 155
  • 193
  • So, your claim is that they wanted to avoid having to deal with special cases? But, floating-point computations already have to deal with a number of special cases caused by `NaN` *(as well as`+/- Inf`, `+/- 0`, and denormalized numbers)*, so... – BlueRaja - Danny Pflughoeft Jul 25 '13 at 22:48
  • 1
    And if it so happened that NaN was represented as e.g. 2, by your logic `1+NaN` would be equal to 3. You can't draw conclusions on what some result *should be* from how you choose to represent it. – eddi Nov 23 '13 at 18:30
4

Conceptually, the only problem with NaN^0 == 1 is that zero values can come about at least four different ways, but the IEEE format uses the same representation for three of them. The above formula equality sense for the most common case (which is one of the three), but not for the others.

BTW, the four cases I would recognize would be:

  • A literal zero
  • Unsigned zero: the difference between two numbers that are indistinguishable
  • Positive infinitesimal: The product or quotient of two numbers of matching sign, which is too small to be distinguished from zero.
  • Negative infinitesimal: The product or quotient of two numbers of opposite sign, which is too small to be distinguished from zero.

Some of these may be produced via other means (e.g. literal zero could be produced as the sum of two literal zeros; positive infinitesimal by the division of a very small number by a very large one, etc.).

If a floating-point recognized the above, it could usefully regard raising NaN to a literal zero as yielding one, and raising it to any other kind of zero as yielding NaN; such a rule would allow a constant result to be assumed in many cases where something that might be NaN would be raised to something the compiler could identify as a constant zero, without such assumption altering program semantics. Otherwise, I think the issue is that most code isn't going to care whether x^0 might would NaN if x is NaN, and there's not much point to having a compiler add code for conditions code isn't going to care about. Note that the issue isn't just the code to compute x^0, but for any computations based on that which would be constant if x^0 was.

supercat
  • 77,689
  • 9
  • 166
  • 211
  • NaN is often used to e.g. indicate that the result is not in the real domain e.g. `sqrt(-1)`. In your custom function it could be smth a lot more exotic than a complex number, that wouldn't necessarily even have the `^` operator defined for it, in which case it would be irrelevant what "kind" if a zero you're looking at. – eddi Nov 23 '13 at 18:36
  • @eddi: If the semantic meaning of `x^literalZero` is defined as "ignore x and return 1", then the correct result of `sqrt(-1)^0` should be 1. One may question whether that is the most desirable way to define the exponentiation operator, but I would posit that languages should avoid defining corner cases whose handling would require extra code. Incidentally, does the language you're using distinguish cases where the right-hand operator is an integer from those where it is floating-point? In some languages, (-2.0)^2 is 4.0, but (-2.0)^(2.0) is invalid. If the zero is an integer... – supercat Nov 23 '13 at 19:14
  • ...then I don't think IEEE-754 NaN handling wouldn be relevant (since it doesn't mention exponentiation by integer) and I would not favor requiring a language to code the zero case as `if (exponent==0) return (isNan(base) ? NaN : 1.0);` as opposed to simply `if (exponent==0) return 1;`. – supercat Nov 23 '13 at 19:16
  • Take a function `f = function(x) {if (x > 0) x else "boo"}`. Then `f(-1)^0` would correctly give you an error. Now imagine someone wants to represent this function in the reals-only domain. The way they would do it is: `f_real = function(x) {if (x > 0) x else NaN}`. And R would them proceed to give an incorrect answer when they try to do `f_real(-1)^0`. – eddi Nov 23 '13 at 22:03
  • @eddi: Do you mean f_real(-1)^0, or f_real^0.0? I would posit that mathematically, f(x)^N may be defined as {1 when N=0, (f(x)^(N-1))*f(x) when N > 0, and (f(x)^(N+1)) when N < 0}. As such, it requires that the function be evaluated abs(N) times; since math has no concept of functions with side-effects, evaluating the function abs(N) times is equivalent to evaluating it exactly once, *provided that one only cares what happens if one actually uses the result*. Note that my disagreement only extends to the case where the exponent is "integer" zero. Incidentally, I was wrong about IEEE not... – supercat Nov 25 '13 at 16:07
  • ...defining a power function for integer N. It in fact defines three power functions, one of which assumes an integer N and specified to reports that NaN^0 is 1.0; the others use real N and differ in their behavior for NaN^0.0. Curious they defined two forms of real^real, but not two forms of comparison, given that there are many situations where the most important characteristic for == and != operators would be that they should define an equivalence relation. – supercat Nov 25 '13 at 16:11
  • it's completely irrelevant what power you want to take `f_real(-1)` to, including 0, what you call 0.0 or 10. In all cases the answer should be the same - it should be `NaN`. The operation "power to integer 0" that you wish do define and can feel free to do, is simply *not* defined for strings (and for some other custom class it could well *be* defined, but produce a different result) and *that's* what `NaN` stands for here and what R screws up. To repeat - the operation you're defining is *only* defined for reals and `NaN` encompasses not *just* reals. – eddi Nov 25 '13 at 16:43
-1

If you look at the type of NaN, it is still a number, it's just not a specific number that can be represented by the numeric type.

EDIT:

For example, if you were to take 0/0. What is the result? If you tried to solve this equation on paper, you get stuck at the very first digit, how many zero's fit into another 0? You can put 0, you can put 1, you can put 8, they all fit into 0*x=0 but it's impossible to know which one the correct answer is. However, that does not mean the answer is no longer a number, it's just not a number that can be represented.

Regardless, any number, even a number that you can't represent, to the power of zero is still 1. If you break down some math x^8 * x^0 can be further simplified by x^(8+0) which equates to x^8, where did the x^0 go? It makes sense if x^0 = 1 because then the equation x^8 * 1 explains why x^0 just sort of disappears from existence.

Lochemage
  • 3,974
  • 11
  • 11
  • So are you basically saying that "not a number is a number"? –  Jul 25 '13 at 16:38
  • @H2CO3 According to R, yes because `is.numeric(NaN)` is `TRUE` – dickoa Jul 25 '13 at 16:39
  • @dickoa I think the question is *should it be?*! – Simon O'Hanlon Jul 25 '13 at 16:39
  • @H2CO3 `javascript:alert(typeof(NaN));` ;-) – Daniel Fischer Jul 25 '13 at 16:40
  • @SimonO101 It's a very interesting question and I really don't know what it should be a this level...still thinking and pros and cons – dickoa Jul 25 '13 at 16:40
  • @DanielFischer I know, and `float f = NAN;`... but still... If something is **not a number,** then it's not a number. (And the downvotes are *still* not mine...) –  Jul 25 '13 at 16:41
  • Why the downvotes? I don't see this answer as particularly *not useful* or worse incorrect – Simon O'Hanlon Jul 25 '13 at 16:42
  • 1
    @H2CO3 I know you know. Just having a bit of innocent fun. – Daniel Fischer Jul 25 '13 at 16:42
  • @DanielFischer That's permitted, I'm by no means against it :) –  Jul 25 '13 at 16:43
  • no, I'm saying that NaN is of type numeric, it's just not a specific value that can be represented by a specific number value. Usually you get this value after performing a math operation on some numbers that is impossible to solve with a specific number result. The answer is still a number, it's just not a number that can be represented – Lochemage Jul 25 '13 at 16:45
  • For example, if you were to take 0/0. What is the result? If you tried to solve this equation on paper, you get stuck at the very first digit, how many zero's fit into another 0? You can put 0, you can put 1, you can put 8, they all fit into 0 but it's impossible to know which one the correct answer is. The answer is still a number, just not a specific one anyone can represent. – Lochemage Jul 25 '13 at 16:57
  • 1
    this answer (especially the edit) is complete nonsense that has nothing to do with math – eddi Jul 25 '13 at 17:10
  • 3
    @eddi I really wish someone would just write an answer that says "because R is following X standard and that's what the standard says" so we can all upvote that and done with this. – joran Jul 25 '13 at 17:11
  • @joran agreed in the sense of answering OP, but not necessarily for answering the conceptual issues underlying it – eddi Jul 25 '13 at 17:13
  • 3
    @joran: Well, I'm not sure what guarantees R makes about following any standards, but the overwhelmingly dominant standard in this area is IEEE 754, and that says (in section 9.2.1): "pow (x, ±0) is 1 for any x (even a zero, quiet NaN, or infinity)". It's not 100% clear to me from the wording of the standard whether this is a recommendation or a requirement. – Mark Dickinson Jul 25 '13 at 17:22
  • There is a difference between an *unknown* number and an error, i.e., an expression such as 0/0 that does not represent a real number. `NaN` is meant for the second case. – Ferdinand.kraft Jul 25 '13 at 17:32