为什么C++规定复数只能用于float、double或long double实例化?

42
根据C++ ISO规范,§26.2/2:
实例化模板complex的效果对于除float, doublelong double之外的任何类型都是未指定的。
为什么标准作者明确添加此限制?例如,这使得如果您创建complex<int>complex<MyCustomFixedPointType>时会变得不确定,并且似乎是一种人为的限制。
这个限制有理由吗?如果要使用自定义类型实例化complex是否有解决方法?
我主要问这个问题是因为这个早期的问题,其中OP对于complex<int>abs给出了奇怪的输出而感到困惑。话虽如此,考虑到我们还可能使用固定点类型、高精度实数等来创建complex数,这仍然不太合理。

5
看到你之前的回答,我不得不笑了,但这确实是一个很好的问题。 - chris
10
@chris- 我觉得在不能给出高层次的原因解释时回答你的问题让我很不好意思。通常我可以说,“这是C ++中一个奇怪的边缘情况,其原因是X、Y和Z”,但这一次我不知道发生了什么。 - templatetypedef
4
在委员会中,对于标准化复杂的<integral>类型进行了十多年的讨论,并且至少有一个供应商存在支持它的显著阻力。http://lists.cs.uiuc.edu/pipermail/cfe-dev/2012-March/020398.html - user195488
5
"Unspecified"与"Undefined"或"ill formed"不同。在标准术语中,"Unspecified"的意思是“这可能是合法的,但标准不要求,并且您需要检查编译器文档以确定它是否允许在实际实现中使用。”请注意,这里不需要提供解释。 - John Dibling
1
是的,委员会只是逃避了定义T需要支持什么精度,以便允许complex<T>。如果您为您的无限精度或定点算术类型重载超越函数和abs()(在C++11中终于被允许(C++98允许完全特化,但不允许在std命名空间中重载名称)),它将正常工作。我认为在实现中使用__isinf而没有一种方法来专门为您的类型进行特殊化是实现质量问题。即使这样,您仍然可以明确地为您的类型专门化受影响的方法。 - Marc Mutz - mmutz
显示剩余4条评论
2个回答

33

您不能在整数上正确实现许多std::complex操作。例如,

template <class T>
T abs(const complex<T> &z);

对于一个complex<long>,当复数被表示为(实部,虚部)对时,不能有T = long的返回值,因为它返回了sqrt(pow(z.real(), 2) + pow(z.imag(), 2))的值。只有少数操作是有意义的。
更糟糕的是,polar命名构造函数不能在不破坏默认构造函数的情况下变得可靠,反之亦然。标准必须指定“复整数”为高斯整数,才能使它们有任何用处,并且其中一个构造函数是严重错误的。
最后,您希望如何进行“复整数除法”,并需要“复余数”吗? :)
总之,我认为指定一个单独的gaussian_int<T>类型,并具有仅有少数操作,比将支持积分T移植到std::complex中更合理。

1
有趣的是我们选择了完全相同的函数来进行说明。 :) - Luchian Grigore
感谢您为这个决定提供了一个扎实的数学原因。我认为这为这个决定提供了一个优雅的理论依据。我之前没有听说过高斯整数,所以感谢您提出了它们! - templatetypedef
@templatetypedef:感谢您的提问和+1。我从未考虑过在整数类型上模板化“complex”会发生什么。[虽然我不是数学家,但如果有人能证明我错了,请务必告诉我。] - Fred Foo
1
我知道这只是修辞上的意思,但高斯整数是欧几里得域(甚至是范数欧几里得),因此带余除法的行为基本上与普通整数相同;你只需要更多的舍入模式选择。 - user1084944

13

可能是为了与辅助函数兼容。例如:

template<class T> T abs (const complex<T>& x);

如果 T == intabs 将返回 int,这将导致精度巨大的损失。

我们已经接受了整数除法中的大量精度损失。5/3 = 1。我认为我们可以同样接受 abs(std::complex<int>(5, 3)) 返回 56。这可能是一个小众需求,但我大部分职业生涯都在处理复数整数。对于像我这样的人来说,它们不被支持是一件很遗憾的事情。 - Harry

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