在C++/Python/NumPy中,为什么log(inf + inf j)等于(inf + 0.785398 j)?

5tmbdcev  于 2022-12-17  发布在  Python
关注(0)|答案(3)|浏览(133)

我发现了Clog函数的一个奇怪行为,并且对log函数处理复数无穷数的行为感到困惑。具体来说,当我期望(inf + nan * 1j)时,log(inf + inf * 1j)等于(inf + 0.785398j)
取复数的对数时,真实的部是输入绝对值的对数,虚部是输入的相位。返回0.785398作为log(inf + inf * 1j)的虚部意味着它假设实部和虚部中的inf具有相同的长度。这个假设似乎与其他计算不一致,例如,inf - inf == naninf / inf == nan(假设2 × 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))
lhcgjxsq

lhcgjxsq1#

free final draft of the C99 specification在第491页上说
clog(+∞,+i∞)返回+∞ + iπ/4。
currently仍然是这种情况。C++ specification使用注解解释了相同的规则
此函数的语义旨在与C函数clog保持一致。
我同意这种行为从数学的Angular 看是令人困惑的,并且可以说与其他inf语义不一致,正如你指出的,但是实际上,它是C标准的一部分,这使得它成为C++标准的一部分,并且由于NumPy通常依赖于C行为(即使在令人困惑的情况下),这在Python示例中是继承的。
标准库cmath.log()函数具有相同的行为(if you test it right...):

>>> import cmath

>>> cmath.log(complex(float('inf'), float('inf')))
(inf+0.7853981633974483j)

我没有办法研究C标准的基本原理,我假设这里有实用的选择,可能是在考虑这些复杂的函数如何相互作用时。

9vw9lbht

9vw9lbht2#

值0.785398(实际上是pi/4)至少与 * 一些 * 其他函数一致:正如你所说,复数的对数的虚部等于该数的相角。2这可以转化为一个问题:inf + j * inf的相位角是多少?
我们可以通过atan2(Im(z), Re(z))计算复数z的相位角,对于给定的数字,这可以归结为计算atan2(inf, inf),对于Numpy和C/C++,atan2(inf, inf)也是0.785398(或pi/4),所以现在可以问一个类似的问题:为什么是atan2(inf, inf) == 0.785398
对于后者,我没有答案(除了“C/C++规范是这么说的”,其他人已经回答了),我只有一个猜测:如atan2(y, x) == atan(y / x)x > 0,可能有人在此上下文中决定不将inf / inf解释为“未定义”,而是解释为“一个非常大的数除以同一个非常大的数”。此比率的结果将是1,并且根据atan的数学定义,atan(1) == pi/4atan
也许这不是一个令人满意的答案,但至少我可以有希望地表明,给定边缘情况下的log定义与相关函数定义的类似边缘情况并非完全不一致。

编辑:正如我所说,与 * 一些 * 其他函数一致:例如,它也与np.angle(complex(np.inf, np.inf)) == 0.785398一致。
编辑2:查看source code of an actual atan2 implementation时出现以下代码注解:

注意,不明显的情况是y和x都是无穷大或都是零。有关详细信息,请参阅 * 复初等函数的分支切割,或W. Kahan著的关于无符号位的许多Ado *
我翻查了参考文档,你可以找到一个here的副本。在本参考的第8章,称为“复数零和无穷大”,William Kahan(他既是数学家又是计算机科学家,根据维基百科,“浮点之父”)涵盖了复数的零和无穷大边缘情况,并得出了pi/4用于将inf + j * inf输入arg函数(X1 M15 N1 X是计算复数的相位角的函数,就像上面的np.angle一样)。你可以在第17页的链接PDF中找到这个结果。我不是一个足够的数学家,无法总结Kahan的理论基础(也就是说:我真的不明白),但也许别人可以。

anauzrmj

anauzrmj3#

如果我们从纯数学的Angular 来考虑这个问题,那么我们可以从极限的Angular 来看待运算,例如当x趋于无穷大时,1/x趋于0(表示为lim(x =〉inf)1/x = 0),这就是我们在浮点数中观察到的。
对于2个无穷大的运算,我们分别考虑每个无穷大,因此:

lim(x => inf) x/1 = inf
lim(x => inf) 1/x = 0

一般来说,我们说inf/x = inf,x/inf = 0。

lim(x => inf) inf/x = inf
lim(x => inf) x/inf = 0

我们应该选择哪一个呢?floats的规范通过声明它是NaN来回避。
然而,对于复杂日志,我们观察到:

lim(x=>inf) log(x + 0j) = inf + 0j
lim(x=>inf) log(0 + xj) = inf + pi/2j
lim(x=>inf) log(inf + xj) = inf + 0j
lim(x=>inf) log(x + infj) = inf + pi/2j

仍然有一个矛盾,但它不是在0和inf之间,而是在0和pi/2之间,所以规范的作者选择了折中的方法。我不知道他们为什么做出这个选择,但浮点无穷不是数学上的无穷。而是表示“这个数字太大了,无法表示”。(复数)可能比减法和除法更纯粹的数学,作者可能觉得保留身份im(log(x+xj))== pi/4是有用的。

相关问题