为什么(inf + 0j)* 1计算为inf + nanj?

2020/12/06 21:52 · python ·  · 0评论
>>> (float('inf')+0j)*1
(inf+nanj)

为什么?这在我的代码中造成了一个讨厌的错误。

为什么不1赋予乘法身份(inf + 0j)

首先1将转换为复数1 + 0j,然后再进行inf * 0乘法运算,结果为nan

(inf + 0j) * 1
(inf + 0j) * (1 + 0j)
inf * 1  + inf * 0j  + 0j * 1 + 0j * 0j
#          ^ this is where it comes from
inf  + nan j  + 0j - 0
inf  + nan j

从机械上讲,公认的答案当然是正确的,但我认为可以给出更深的答案。

首先,像@PeterCordes在评论中一样澄清问题是很有用的:“复数是否存在可用于inf + 0j的复数形式?” 或者换句话说就是OP认为计算机实现复杂乘法的弱点,或者在概念上不符合inf+0j

简短答案:

使用极坐标,我们可以将复数乘法视为缩放和旋转。即使将无限个“手臂”旋转0度(如乘以1的情况),我们也无法期望将其尖端以有限的精度放置。因此,确实存在一些根本不正确的东西inf+0j,即,一旦我们达到无穷大,有限的偏移就变得毫无意义。

长答案:

背景:这个问题所围绕的“大事情”是扩展数字系统(考虑实数或复数)的问题。可能要这样做的原因之一是添加了无穷大的概念,或者如果恰好是数学家,则使“紧凑”。还有其他原因,太(https://en.wikipedia.org/wiki/Galois_theoryhttps://en.wikipedia.org/wiki/Non-standard_analysis),但我们不会在这里的那些兴趣。

一点压实

当然,关于这种扩展的技巧是,我们希望这些新数字适合现有的算法。最简单的方法是在无穷大处添加一个元素(https://en.wikipedia.org/wiki/Alexandroff_extension),并使它等于零除以零。这适用于实数(https://en.wikipedia.org/wiki/Projectively_extended_real_line)和复数(https://en.wikipedia.org/wiki/Riemann_sphere)。

其他扩展...

尽管单点压缩是简单的并且在数学上是合理的,但是已经寻求了包括多个定律的“更丰富”的扩展。实际浮点数的IEEE 754标准具有+ inf和-inf(https://en.wikipedia.org/wiki/Extended_real_number_line)。看起来自然而直接,但是已经迫使我们跳了圈,发明了https://en.wikipedia.org/wiki/Signed_zero之类的东西-0

...复杂平面的

复杂平面的扩展超过一英寸呢?

在计算机中,复数通常是通过将两个fp实数粘贴在一起来实现的,一个实数粘贴,一个虚数部分粘贴。只要一切都是有限的,那是完全可以的。但是,一旦考虑到无限性,事情就会变得棘手。

复平面具有自然的旋转对称性,这与复数算法很好地联系在一起,因为将整个平面乘以e ^ phij与绕φ的旋转相同0

那附件G的东西

现在,为了简单起见,复杂的fp仅使用基础实数实现的扩展名(+/- inf,nan等)。这种选择似乎很自然,甚至没有被认为是一种选择,但让我们仔细研究一下它的含义。复杂平面的此扩展的简单可视化效果类似于(I =无限,f =有限,0 = 0)

I IIIIIIIII I
             
I fffffffff I
I fffffffff I
I fffffffff I
I fffffffff I
I ffff0ffff I
I fffffffff I
I fffffffff I
I fffffffff I
I fffffffff I
             
I IIIIIIIII I

但是,由于真正的复数平面是尊重复数乘法的平面,因此可以提供更多信息

     III    
 I         I  
    fffff    
   fffffff   
  fffffffff  
I fffffffff I
I ffff0ffff I
I fffffffff I
  fffffffff  
   fffffff   
    fffff    
 I         I 
     III    

在此投影中,我们看到无限大的“不均匀分布”不仅丑陋,而且还遭受了OP类问题的根源:大多数无限大(((+/- inf,有限)形式和(有限,+ / -inf)集中在四个主要方向上,所有其他方向仅由四个无穷大(+/- inf,+ -inf)表示。将复数乘法扩展到此几何体是一场噩梦,这不足为奇。

在C99规范的附录G会尽可能使其工作,包括弯曲如何在规则infnan相互作用(主要是inf胜过nan)。OP的问题是通过不将实数和拟议的纯虚数类型提升为复数来避免的,但是让实数1与复数1的行为不同并不能解决我的问题。可以说,附件G没有充分说明两个无限性的乘积应该是什么。

我们可以做得更好吗?

试图通过选择更好的无限性几何来尝试解决这些问题。与扩展实线类似,我们可以为每个方向添加一个无穷大。此构造类似于投影平面,但不会将相反的方向聚集在一起。无穷将用极坐标inxe ^ {2 omega pi i}表示,定义乘积将很简单。特别是,OP的问题将很自然地解决。

但这是好消息结束的地方。在某种程度上,我们可以不拘一格地(而不是不合理地)要求我们重新设计,要求我们的新型无限性支持提取其实部或虚部的函数。加法是另一个问题。添加两个非对映的无穷大,我们必须将角度设置为不确定nan(可以说该角度必须位于两个输入角度之间,但是没有简单的方式来表示“部分南度”))

黎曼来营救

鉴于所有这些,也许最好的做法是进行旧的一点压实。也许附件G的作者在强制要求将cproj所有无穷大集合在一起的函数时有相同的感觉


这是一个相关问题,比我本人更有能力回答。

这是在CPython中如何实现复杂乘法的实现细节。与其他语言(例如C或C ++)不同,CPython采用了一种较为简单的方法:

  1. 整数/浮点数被乘以复数
  2. 使用简单的学校公式,一旦涉及到无限数,它就不会提供预期的/预期的结果:
Py_complex
_Py_c_prod(Py_complex a, Py_complex b)
{
    Py_complex r;
    r.real = a.real*b.real - a.imag*b.imag;
    r.imag = a.real*b.imag + a.imag*b.real;
    return r;
}

上述代码的一种有问题的情况是:

(0.0+1.0*j)*(inf+inf*j) = (0.0*inf-1*inf)+(0.0*inf+1.0*inf)j
                        =  nan + nan*j

但是,人们希望得到这样的-inf + inf*j结果。

在这方面,其他语言不是遥不可及的:很长一段时间以来,复数乘法都不是C标准的一部分,仅作为附录G包含在C99中,该附录G描述了应如何执行复数乘法-它并不像上面的学校公式!C ++标准没有指定复杂乘法的工作方式,因此大多数编译器实现都回落到C实现上,这可能符合C99(gcc,clang)或不符合(MSVC)。

对于上述“问题”示例,符合C99的实现(比学校公式更复杂)将提供(请参见live)预期结果:

(0.0+1.0*j)*(inf+inf*j) = -inf + inf*j 

即使使用C99标准,也没有为所有输入定义明确的结果,即使对于符合C99的版本也可能有所不同。

在C99float未被提升为另一个副作用complexinf+0.0j1.0相乘1.0+0.0j会导致不同的结果(请参见此处实时显示):

  • (inf+0.0j)*1.0 = inf+0.0j
  • (inf+0.0j)*(1.0+0.0j) = inf-nanj,虚部是-nan和不是nan(作为CPython的)不会在这里发挥作用,因为所有的安静NaN是相等的(见),甚至有的还具有符号位组(因此打印为“ - ”,看到),有些则没有。

这至少是违反直觉的。


我的主要收获是:“简单”的复数乘法(或除法)并不简单,当在语言或什至是编译器之间切换时,人们必须为微妙的错误/差异做好准备。

Python的有趣定义。如果我们用笔和纸解决此问题,我会说预期的结果将expected: (inf + 0j)如您所指出的那样,因为我们知道我们的意思是1这样(float('inf')+0j)*1 =should= ('inf'+0j)

但是事实并非如此,当您运行它时,我们得到:

>>> Complex( float('inf') , 0j ) * 1
result: (inf + nanj)

Python的理解这*1是一个复杂的数量和不规范的做法1,因此解释为*(1+0j),当我们尝试做错误出现inf * 0j = nanjinf*0不能得到解决。

您实际上想做什么(假设1是1的范数):

回想一下,如果z = x + iy是具有实部x和虚部y的复数,则将的复共轭z定义为z* = x − iy,将绝对值(也称为norm of z)定义为:

在此处输入图片说明

假设这11我们的常识,我们应该做类似的事情:

>>> c_num = complex(float('inf'),0)
>>> value = 1
>>> realPart=(c_num.real)*value
>>> imagPart=(c_num.imag)*value
>>> complex(realPart,imagPart)
result: (inf+0j)

我知道的不是很直观...但是有时编码语言的定义方式与我们日常使用的方式不同。

本文地址:http://python.askforanswer.com/weishenmeinf-0j-1jisuanweiinf-nanj.html
文章标签: ,   ,  
版权声明:本文为原创文章,版权归 admin 所有,欢迎分享本文,转载请保留出处!

文件下载

老薛主机终身7折优惠码boke112

上一篇:
下一篇:

评论已关闭!