The ECMAScript specification for Math.pow
has the following peculiar rule:
- If x < 0 and x is finite and y is finite and y is not an integer, the result is NaN.
(http://es5.github.com/#x15.8.2.13)
As a result Math.pow(-8, 1 / 3)
gives NaN
rather than -2
What is the reason for this rule? Is there some sort of broader computer science or IEEEish reason for this rule, or is it just a choice TC39/Eich made once upon a time?
Update
Thanks to Amadan's exchanges with me, I think I understand the reasoning now. I would like to expand upon our discussion for the sake of posterity.
Let's take the following example: Math.pow(823543, 1 / 7)
yields 6.999999999999999
although it really should be 7
. This is an inaccuracy introduced by the fact that 1 / 7
must first be converted to a decimal representation 0.14285714285714285
, which is truncated and loses precision. This isn't such a bad problem when we're working with positive numbers because we still get a result that's extremely close to the real result.
However, once we step into the negative world we have a problem. If a JavaScript engine were to try to compute Math.pow(-823543, 1 / 7)
it would first need to convert 1 / 7
to a decimal, so it would really be computing Math.pow(-823543, 0.14285714285714285)
which actually has no real answer. In this case, it may have to return NaN
since it couldn't find a real number, even though the real answer should be -7
. Futhermore, looking for complex numbers which are close to real numbers to make a "best guess" may involve a level of complexity they didn't want to require a JS engine to have in the math arena.
My guess is it is due to the consideration of the loss of precision in floating point numbers that led them to the rule that negative numbers to a non-integer power should always be NaN
-- basically because a non-integer power is likely to give a complex number as a result of loss of precision, even if it shouldn't, and there may be no good way to recover from it.
With this, I'm fairly satisfied, but I do welcome further information.
I assume because those circumstances lead the result into complex waters, and ECMAScript is not equipped with imaginary numbers. Specifically, your example should result in something close to 1 + 1.732i
, among other results. (The fact that -2 is also a possible result is besides the point - it is an accident rather than a rule.)
You can use a helper function.
In swift I faced a similar situation. Here is a proposed solution for you
func checkSquareRoot(x: Double, y: Double) -> Double {
let result = pow(x, y)
if x > 0 {
return result
} else {
return -1 * pow( -x, y)
}
}
来源:https://stackoverflow.com/questions/14575697/math-pow-with-negative-numbers-and-non-integer-powers