Почему log(∞ + ∞j) равно (∞ + 0.785398j) в C++/Python/NumPy?
Я столкнулся с необычным поведением функций логарифма в C++ и numpy при работе с комплексными бесконечными числами. В частности, результат выражения log(inf + inf * 1j)
равен (inf + 0.785398j)
, тогда как я ожидаю получить (inf + nan * 1j)
.
При вычислении логарифма комплексного числа реальная часть представляет собой логарифм абсолютного значения входного параметра, а мнимая часть соответствует фазе этого числа. Возвращение 0.785398 в качестве мнимой части результата log(inf + inf * 1j)
подразумевает, что оба значения inf
в реальной и мнимой части имеют одинаковую длину. Это предположение, по-видимому, не согласуется с другими вычислениями, например, inf - inf == nan
и inf / inf == nan
, что подразумевает, что два inf
не обязательно имеют одинаковые значения.
Почему это предположение для log(inf + inf * 1j)
отличается?
Вот код на C++ для воспроизведения проблемы:
#include <complex>
#include <limits>
#include <iostream>
int main() {
double inf = std::numeric_limits<double>::infinity();
std::complex<double> b(inf, inf);
std::complex<double> c = std::log(b);
std::cout << c << "\n";
}
Вот код на Python (numpy) для воспроизведения проблемы:
import numpy as np
a = complex(float('inf'), float('inf'))
print(np.log(a))
ПРАВКА: Спасибо всем, кто принял участие в обсуждении исторических и математических причин. Все ваши ответы обогатили этот наивный вопрос действительно интересной дискуссией. Предоставленные ответы высокого качества, и мне бы хотелось принять больше, чем один ответ. Тем не менее, я решил принять ответ @simon, так как он подробнее объясняет математическую причину и предоставляет ссылку на документ с объяснением логики (хоть я и не могу полностью это понять).
1 ответ(ов)
Если рассмотреть этот вопрос с точки зрения чистой математики, мы можем анализировать операции в терминах пределов. Например, когда x стремится к бесконечности, 1/x стремится к 0 (обозначается как lim(x → ∞) 1/x = 0), что мы также наблюдаем и в плавающей точке.
Для операций с двумя бесконечностями мы рассматриваем каждую бесконечность отдельно. Таким образом:
lim(x → ∞) x/1 = ∞
lim(x → ∞) 1/x = 0
И в общем случае мы говорим, что ∞/x = ∞, а x/∞ = 0. Следовательно:
lim(x → ∞) ∞/x = ∞
lim(x → ∞) x/∞ = 0
Что из этих двух случаев мы должны предпочесть? Спецификация для чисел с плавающей запятой избегает этого вопроса, объявляя результат NaN.
Что касается комплексных логарифмов, то мы наблюдаем следующее:
lim(x → ∞) log(x + 0j) = ∞ + 0j
lim(x → ∞) log(0 + xj) = ∞ + π/2j
lim(x → ∞) log(∞ + xj) = ∞ + 0j
lim(x → ∞) log(x + ∞j) = ∞ + π/2j
Здесь все еще присутствует противоречие, но вместо того чтобы находиться между 0 и ∞, оно колеблется между 0 и π/2, поэтому авторы спецификации решили "разделить разницу". Почему они сделали такой выбор, я не могу сказать, но бесконечности в плавающей точке — это не математические бесконечности, а что-то вроде «это число слишком велико для представления». Учитывая, что использование log(complex) скорее всего будет более математическим, чем вычитание и деление, авторы могли решить, что сохранение равенства im(log(x + xj)) == π/4 будет полезным.
Почему чтение строк из stdin в C++ гораздо медленнее, чем в Python?
Как извлечь частоту, связанную с FFT значениями в Python?
Расширение setuptools для использования CMake в setup.py?
Цветовой график 2D массива в matplotlib
Преобразование байтового массива обратно в массив numpy