Skip to content

Possible inconsistency between `as.complex(NA_real_)` and the docs

2 messages · Davis Vaughan, Martin Maechler

#
Hi all,

Surprisingly (at least to me), `as.complex(NA_real_)` results in
`complex(real = NA_real_, imaginary = 0)` rather than `NA_complex_`.

It seems to me that this goes against the docs of `as.complex()`,
which say this in the Details section:

"Up to R versions 3.2.x, all forms of NA and NaN were coerced to a
complex NA, i.e., the NA_complex_ constant, for which both the real
and imaginary parts are NA. Since R 3.3.0, typically only objects
which are NA in parts are coerced to complex NA, but others with NaN
parts, are not. As a consequence, complex arithmetic where only NaN's
(but no NA's) are involved typically will not give complex NA but
complex numbers with real or imaginary parts of NaN."

To me this suggests that `NA_real_`, which is "NA in parts", should
have been coerced to "complex NA".

`NA_integer_` is actually coerced to `NA_complex_`, which to me is
further evidence that `NA_real_` should have been as well.

Here is the original commit where this behavior was changed in R 3.3.0:
https://github.com/wch/r-source/commit/4a4c2052e5a541981a249d4fcf92b54ca7f0a2df

```
# This is expected, based on the docs
x <- as.complex(NaN)
Re(x)
#> [1] NaN
Im(x)
#> [1] 0

# This is not expected. The docs say:
# "Since R 3.3.0, typically only objects which are NA in parts are
coerced to complex NA"
# but that doesn't seem true for `NA_real_`.
x <- as.complex(NA_real_)
Re(x)
#> [1] NA
Im(x)
#> [1] 0

# It does seem to be the case for `NA_integer_`
x <- as.complex(NA_integer_)
Re(x)
#> [1] NA
Im(x)
#> [1] NA
```

Thanks,
Davis Vaughan
8 days later
#
Well, the logic here is really the mathematical equivalence:
if you turn a real number x  in to a complex one, say z,
then  z =  x + i * 0 , i.e., real part x  and imaginary part 0.
The above was written in  svn commit 69410  (the github mirror
of which you mention below)
------------------------------------------------------------------------
r69410 | maechler | 2015-09-22 10:11:34 +0200 (Tue, 22 Sep 2015) | 1 line

more consistent behavior of complex number NaN / NA - not back-compatible
------------------------------------------------------------------------

which I had to amend a day later in
------------------------------------------------------------------------
r69423 | maechler | 2015-09-23 19:23:57 +0200 (Wed, 23 Sep 2015) | 1 line

even NaN + NA_complex_ is platform dependent
------------------------------------------------------------------------

just with adding the following at the end of
example(as.complex)  :

showC <- function(z) noquote(sprintf("(R = \%g, I = \%g)", Re(z), Im(z)))

## The exact result of this *depends* on the platform, compiler, math-library:
(NpNA <- NaN + NA_complex_) ; str(NpNA) # *behaves* as 'cplx NA' ..
stopifnot(is.na(NpNA), is.na(NA_complex_), is.na(Re(NA_complex_)), is.na(Im(NA_complex_)))
showC(NpNA)# but not always is {shows  '(R = NaN, I = NA)' on some platforms}
## and this is not TRUE everywhere:
identical(NpNA, NA_complex_)
showC(NA_complex_) # always == (R = NA, I = NA)

And that was a while ago.  In the mean time I've become more
aware of the fact that --- to my large chagrin --- our
distinction of NA and NaN  unfortunately   has more problems in
quite platform-dependent arithmetic than I had still hoped at
the time.
Yeah.. I agree that  as.complex(.) should return the same for integer
and double NA.

I see where and how the change would need to happen.
.. we'll see if it is feasible (I guess "yes" with 0.98 subjective probability)