0

Почему log(∞ + ∞j) равно (∞ + 0.785398j) в C++/Python/NumPy?

17

Я столкнулся с необычным поведением функций логарифма в 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 ответ(ов)

0

Если рассмотреть этот вопрос с точки зрения чистой математики, мы можем анализировать операции в терминах пределов. Например, когда 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 будет полезным.

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь