R seems pretty comfortable with computing the odd root of a negative number
-0.2^(1/3) # returns a good number
# [1] -0.5848035
but something weird happens if you raise a vector to the 1/3.
c(-0.2, 1)^(1/3) # returns an NA for the first element
# [1] NaN 1
I'm interested in an answer that explains what is happening differently to the vector than to the negative value when provided as a numeric scalar.
I'm not looking for a workaround e.g. function(x){sign(x)*(abs(x))^(1/3)}
. This answer seems to point in a good direction... how does the "^" operator think differently about vectors and scalars?
CodePudding user response:
I'm not looking for a workaround e.g.
function(x) {sign(x) * (abs(x)) ^ (1/3)}
.
I'm interested in an answer that explains what is happening differently to the vector than to the negative value when provided as a numeric scalar.
how does the
^
operator think differently about vectors and scalars?
You seem to believe that c(-0.2, 1)^(1/3)
translates to c(-0.2^(1/3), 1^(1/3))
. This is incorrect. Operator ^
is actually a function, that is, (a) ^ (b)
is as same as "^"(a, b)
. Therefore, the correct interpretation goes as follows:
c(-0.2, 1)^(1/3)
=> "^"(c(-0.2, 1), 1/3)
=> c( "^"(-0.2, 1/3), "^"(1, 1/3) )
=> c( (-0.2)^(1/3), (1)^(1/3) )
=> c( NaN, 1 )
Now, why doesn't -0.2^(1/3)
give NaN
? Because ^
has higher operation precedence than
, -
, *
and /
. So as it is written, it really implies -(0.2^(1/3))
instead of (-0.2)^(1/3)
.
The lesson is that, to avoid buggy code, write your code as (a) ^ (b)
instead of just a ^ b
.
Additional Remark:
I often compare ^
and :
when teaching R to my students, because they have different behaviors. But they all show the importance of protecting operands with brackets.
(-1):2
#[1] -1 0 1 2
-1:2
#[1] -1 0 1 2
-(1:2)
#[1] -1 -2
2*3:10
#[1] 6 8 10 12 14 16 18 20
(2*3):10
#[1] 6 7 8 9 10
2*(3:10)
#[1] 6 8 10 12 14 16 18 20
See ?Syntax
for details of operator precedence.