Подтвердить что ты не робот

Numpy - квадратный корень из -1 оставляет небольшую реальную часть

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

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

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

(6.1230317691118863e-17+1j)

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

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

4b9b3361

Ответ 1

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

>>> numpy.power(-1+0j, 0.5)
(6.123233995736766e-17+1j)
>>> cmath.exp(cmath.log(-1)/2)
(6.123233995736766e-17+1j)

Ответ 2

Что происходит, так это то, что квадратный корень из -1 вычисляется как exp (i phase/2), где фаза (-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 (module) + я phase). С другой стороны, cmath.sqrt(-1) дает ровно 1j, потому что он использует другой метод и не страдает от проблемы аппроксимации с плавающей запятой (-1+0j)**0.5 (как было предложено TonyK).