Numpy - квадратный корень из -1 оставляет небольшую вещественную часть - PullRequest
13 голосов
/ 09 июня 2011

Возможно, это алгоритмическая проблема, но следующий фрагмент кода

numpy.power((-1+0j),0.5)

производит следующий вывод

(6.1230317691118863e-17+1j)

Аналогичные выражения, например numpy.power(complex(-1),.5) дает тот же результат, однако - numpy.sqrt(complex(-1)) дает ожидаемый результат 1j. Очевидно, что результат не должен иметь реального значения, поэтому я упускаю что-то решающее, или мне нужно сообщить об этом непонятным разработчикам.

В случае, если кто-нибудь спросит, нет, я не могу округлить действительную часть (мне нужна полная точность для этого вычисления), и да, мне нужно использовать функцию мощности.

Ответы [ 3 ]

15 голосов
/ 09 июня 2011

Что происходит, так это то, что квадратный корень из -1 рассчитывается как exp (i phase / 2), где phase (of -1) равен приблизительно π. На самом деле

>>> import cmath, math
>>> z = -1+0j
>>> cmath.phase(z)
3.141592653589793
>>> math.cos(_/2)
6.123233995736766e-17

Это показывает, что фаза -1 равна π только до нескольких 1e-17; фаза, деленная на 2, также составляет только приблизительно π / 2, а ее косинус - только приблизительно 0, следовательно, ваш результат (реальная часть вашего результата - этот косинус).

Проблема в конечном итоге связана с тем фактом, что существует только фиксированное конечное число чисел с плавающей запятой . Число π отсутствует в списке чисел с плавающей запятой и поэтому может быть представлено только приблизительно. π / 2 также нельзя точно представить, так что действительная часть квадратного корня из -1 представляет собой косинус приближения с плавающей запятой для π / 2 (следовательно, косинус, который отличается от 0).

Итак, приблизительное значение Python для numpy.power(complex(-1), .5) в конечном счете связано с ограничением чисел с плавающей запятой и, вероятно, встречается во многих языках.

То, что вы наблюдаете, связано с этим ограничением с плавающей запятой через реализацию степени числа. В вашем примере, квадратный корень вычисляется путем оценки модуля и аргумента вашего комплексного числа (по существу, через функцию log, которая возвращает log (module) + i phase). С другой стороны, cmath.sqrt(-1) дает ровно 1j, поскольку он использует другой метод и не страдает от проблемы аппроксимации с плавающей запятой (-1+0j)**0.5 (как предполагает TonyK).

9 голосов
/ 09 июня 2011

Это побочный эффект от реализации numpy.power() для комплексных чисел. У stdlib та же проблема.

>>> numpy.power(-1+0j, 0.5)
(6.123233995736766e-17+1j)
>>> cmath.exp(cmath.log(-1)/2)
(6.123233995736766e-17+1j)
5 голосов
/ 27 июня 2011

Попробуйте numpy.real_if_close ().

См .: Реальный, если закрыть

...