Math.pow с отрицательными числами и нецелыми степенями

Спецификация ECMAScript для Math.pow имеет следующее специфическое правило:

  • Если x ‹0 и x конечно, y конечно и y не является целым числом, результатом будет NaN.

(http://es5.github.com/#x15.8.2.13)

В результате Math.pow(-8, 1 / 3) дает NaN, а не -2

В чем причина этого правила? Есть ли какая-то более широкая информатика или IEEEish причина для этого правила, или это просто выбор TC39 / Eich, сделанный когда-то давно?


Обновлять

Благодаря тому, что Амадан обменялся со мной, я думаю, что теперь понимаю его рассуждения. Я хотел бы расширить нашу дискуссию для потомков.

Возьмем следующий пример: Math.pow(823543, 1 / 7) дает 6.999999999999999, хотя на самом деле должно быть 7. Это неточность, вызванная тем фактом, что 1 / 7 необходимо сначала преобразовать в десятичное представление 0.14285714285714285, которое усекается и теряет точность. Это не такая уж большая проблема, когда мы работаем с положительными числами, потому что мы все равно получаем результат, очень близкий к реальному.

Однако как только мы вступаем в отрицательный мир, у нас возникает проблема. Если бы механизм JavaScript попытался вычислить Math.pow(-823543, 1 / 7), ему сначала нужно было бы преобразовать 1 / 7 в десятичное число, так что он действительно будет вычислять Math.pow(-823543, 0.14285714285714285), на который на самом деле нет реального ответа. В этом случае ему, возможно, придется вернуть NaN, поскольку он не смог найти действительное число, хотя реальный ответ должен быть -7. Более того, поиск комплексных чисел, которые близки к действительным числам, чтобы сделать «наилучшее предположение», может потребовать такого уровня сложности, который они не хотели требовать от JS-движка в математической сфере.

Я предполагаю, что это связано с учетом потери точности в числах с плавающей запятой, что привело их к правилу, согласно которому отрицательные числа в нецелой степени всегда должны быть NaN - в основном потому, что нецелочисленная степень, вероятно, даст комплексное число в результате потери точности, даже если это не так, и может не быть хорошего способа восстановить его.

Я довольно доволен этим, но приветствую дополнительную информацию.


person Nathan Wall    schedule 29.01.2013    source источник
comment
См. Также Math.Pow () не работает (в некоторых комментариях к некоторым ответам обсуждается функция Pow комплексного числа) и поиск кубического корня отрицательного числа с помощью функции pow и др. Многие калькуляторы с радостью вычислят (-x)^q, где -x отрицательно, а q - нецелое число, которое выглядит как рациональное с нечетным знаменателем (когда дробь выражается в наименьшем значении). Итак, IEEE отличается от этого.   -  person Jeppe Stig Nielsen    schedule 30.01.2013
comment
Также: Кубический корень отрицательного числа. Этот вопрос задают очень часто с разными формулировками.   -  person Jeppe Stig Nielsen    schedule 30.01.2013
comment
@Jeppe, Спасибо за ссылки. Они очень полезны.   -  person Nathan Wall    schedule 30.01.2013


Ответы (2)


Я предполагаю, потому что эти обстоятельства приводят к сложным результатам, а ECMAScript не снабжен мнимыми числами. В частности, среди других результатов ваш пример должен привести к чему-то близкому к 1 + 1.732i. (Тот факт, что -2 также является возможным результатом, помимо прочего - это скорее случайность, чем правило.)

person Amadan    schedule 29.01.2013
comment
Хм? Есть реальный ответ. -2. Если нет реального ответа, можно дать NaN. Но если есть реальный ответ, почему бы не дать его мне? - person Nathan Wall; 29.01.2013
comment
Если быть более точным: Math.pow(8, 1 / 3) имеет два сложных ответа и один реальный ответ. В этом случае JavaScript с радостью даст мне настоящий ответ 2, хотя есть и другие ответы. Какая разница? - person Nathan Wall; 29.01.2013
comment
Извините, я отредактировал позже, чтобы учесть вашу точку зрения. Например, (-8) ^ (4.32) не имеет удобного реального решения; и я полагаю, что искоренение (хе-хе) случаев, которые действительно имеют рациональное решение, выходит за рамки спецификации. - person Amadan; 29.01.2013
comment
Хороший контрпример. Ваш ответ помог мне еще раз обдумать это, и теперь я думаю, что понимаю, почему это так. Дроби должны быть преобразованы в числа с плавающей запятой, и из-за ограничений точности чисел с плавающей запятой было бы легко, если бы вычисление было настолько незначительным, что вещественное число стало сложным, и JS должен был вернуть NaN. а не близкий разумный результат. В этом случае угадывание может быть слишком подвержено ошибкам. Спасибо! - person Nathan Wall; 29.01.2013
comment
Спасибо за это. Столкнулся с той же проблемой в SQL Server и был в тупике. - person Kevin Pope; 14.03.2014

Вы можете использовать вспомогательную функцию.

В Swift я столкнулся с похожей ситуацией. Вот предлагаемое вам решение:

function checkSquareRoot(x, y) {
    if (x > 0) {
        return Math.pow(x, y)
    }
    return -1 * Math.pow(-x, y)
}
person Abdulla    schedule 04.10.2015