【问题标题】:How does C++ compute the absolute value of a complex number, preventing overflow?C++如何计算复数的绝对值,防止溢出?
【发布时间】:2016-12-09 16:12:08
【问题描述】:

C++ 标头<complex> 提供abs(z)norm(z)

复数z=x+iy的范数是norm(z):=x^2+y^2。

z 的绝对值是abs(z):=sqrt(norm(z))。

但是,下面的示例显示abs(z) 必须以不同的方式实现,因为尽管norm(z) 会溢出,但它不会溢出。至少在g++ 6.2.1下不会溢出。

标准是否保证了这种不溢出?它是如何实现的?

#include <iostream>
#include <complex>
typedef std::complex<double> complex_t;

int main()
{
    complex_t z = { 3e200, 4e200 };
    double a = abs(z);
    double n = norm(z);

    std::cout << a << " -> " << std::isinf(a) << "\n";
    std::cout << n << " -> " << std::isinf(n) << "\n";

    return 0;
}

输出:

5e+200 -> 0
inf -> 1

【问题讨论】:

  • 看头文件中的实现。至少在我的系统上,abs(real part), abs(imag part) 的最大值用于先除,然后乘。这可能是避免溢出的原因。
  • 看起来 libstdc++ 是反过来的:abs 的计算是直接的 (source),范数的计算是绝对值的平方 (source)。 Abs 还将实部和虚部都除以最大值,可能是为了防止溢出。

标签: c++ numeric floating-accuracy complex-numbers


【解决方案1】:

std::complex::abs 等价于std::hypot 函数,确实可以保证在计算的中间阶段避免上溢和下溢。

Wikipedia page on Hypot function 提供了一些关于实现的见解。

我将引用伪代码以防万一:

  // hypot for (x, y) != (0, 0)
double hypot(double x,double y)
{
    double t;
    x = abs(x);
    y = abs(y);
    t = min(x,y);
    x = max(x,y);
    t = t/x;
    return x*sqrt(1+t*t);
}

【讨论】:

  • 请注意,这并不是 libm 会做的事情。此实现不会给出 1ULP 错误界限
  • @YanZhou 哦,是的,从精度上讲,这个伪代码根本不会发生;但是它解释了溢出情况。 “真实代码”类似于this
猜你喜欢
  • 2022-06-22
  • 1970-01-01
  • 1970-01-01
  • 2022-07-22
  • 1970-01-01
  • 1970-01-01
  • 2011-10-22
  • 2012-04-13
  • 1970-01-01
相关资源
最近更新 更多