复杂的无穷大和NaN的乘除运算

3

在实际的浮点数算法中,我们有额外的符号INF(无穷大),NAN和带符号的零。对于复数算法,情况更加复杂。如果使用“天真”的乘除规则

(a + ib)(c + id) = (ac - db) + i(ac+bd)
(a + ib)/(c + id) = ( (ac + db) + i(ac-bd) ) / (c*c + d*d)

在a、b、c、d变量中,当其中一个变量为INF或NAN时,几乎所有情况都会得到错误的(*)结果。

例如

  • (1 + i0)*(INF + i0) = INF + iNAN。与实数算术1*INF = INF相比
  • (0 + i1)* (NAN + i0) = NAN + iNAN。然而,人们期望i*NAN = (0+iNAN)
  • 1 / (0+0i) = NAN + iNAN。这会破坏例如z = 1/(1/z)的运算,在实数算术中可以完美地运行。

这个列表可以轻松继续下去。

问题是如何正确实现复数除法和乘法,以便在所有情况下,包括其中一个实部或虚部为INF和NAN时,都能给出有意义的结果?还有哪些编程语言保证了具有INF和NAN的复杂算术的正确行为?

编辑:我想知道哪种编程语言标准(版本)要求正确处理具有INF和NAN的复杂算术。我最感兴趣的语言是C、C++和FORTRAN系列。

(*) 错误意味着在数学上没有意义,或者在IEEE-754的意义上是反直觉的。


1
在什么情况下?使用什么语言?这里是clang的C++ <complex>实现。如果您查看operator *实现,它展示了如何处理INF/NaN。您对此有什么异议吗? - Brett Hale
他们似乎做得很对。谢谢提供链接。我的问题是哪种编程语言能够保证这一点,也就是在哪种语言的规范中明确要求正确的INF和NAN行为。据我所知,C++并没有这样的规定(但我可能错了)。FORTRAN似乎也不需要。我希望在这里能够得到明确的答案。 - Andreas H.
问题在于,如果您想编写依赖于处理INF和NAN的可移植代码,那么如果某些编译器正确处理而其他编译器不正确处理,则这是毫无意义的。 - Andreas H.
1个回答

3
对于 C 语言,请查看 C99 或 C11 的附录 G。至少 GCC 遵循此规范,如果 clang 没有遵循,我会感到惊讶。
对于 C++,我IRC,C++ 标准选择不包含 C99/C11 附录 G,并且复杂乘除的算法由实现决定。
Fortran 标准没有指定如何实现复数乘法或除法。对于除法,GFortran 使用常见的 Smith(1962)方法,除非指定了 -ffast-math,然后使用朴素算法。
有关计算复杂除法的不同算法的比较,请参见 http://arxiv.org/abs/1210.4539

1
这也可能会引起兴趣:Claude-Pierre Jeannerod,Nicolas Louvet和Jean-Michel Muller,“关于带有FMA的复浮点除法的分量精度”。在第21届IEEE计算机算术研讨会(ARITH 21)论文集中,2013年4月7日,第83-90页(在线),以及:Douglas M. Priest,“用于复数除法的高效缩放。” ACM Transactions on Mathematical Software (TOMS) 30.4(2004):389-401。 (在线,付费墙 - njuffa
谢谢,这正是我在寻找的。所以C语言是科学计算的语言!即使Annex G是可选的,至少它规定了如何正确地进行复杂算术运算。C++和Fortran实际上令人失望... - Andreas H.
Smith 1962方法是一种用于复杂除法的策略,可在此处获取:https://dl.acm.org/citation.cfm?id=368661 - mppf

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接