首页 > 解决方案 > 功能用途不明,它有什么作用?

问题描述

如果输入是复数a+bi并且有人可以帮我理解这个函数在做什么real = a, imag = b

我不知道它可能在计算什么,但也许我遗漏了一些明显的东西?

double function(double real, double imag)
{
  double y;
  double a;
  double b;
  a = fabs(real);
  b = fabs(imag);
  if (a < b) 
  {
    a /= b;
    y = b * sqrt(a * a + 1.0);
  } 
  else if (a > b) 
  {
    b /= a;
    y = a * sqrt(b * b + 1.0);
  } 
  else if (b == NAN) 
  {
    y = b;
  } 
  else 
  {
    y = a * sqrt(2);
  }

  return y;
}

标签: c++cfunctionmathcomplex-numbers

解决方案


该代码是计算传递给它的复数的大小(绝对值)而不引起不必要的溢出的有缺陷的尝试。

考虑复数a + b i,其中ab是分配给函数前几行的值ab它的大小是√( a 2 + b 2 )。但是,如果ab很大,则浮点计算a*a可能会溢出浮点格式的有限范围并产生无穷大 (∞),即使幅度在该范围内。举个简单的例子,设a为 2 1000b为 0。那么大小为 √(2 2000 +0) = 2 1000,但计算sqrt(a*a + b*b)产生无穷大。(由于a*a溢出并产生了∞,其余的计算也产生了∞。)

该代码试图通过将ab中较小的一个除以较大的一个并使用数学上等效但不会溢出的计算来解决这个问题。例如,如果a < b为真,则执行:

a /= b;
y = b * sqrt(a * a + 1.0);

然后a /= b产生一个小于 1 的值,因此最后一个之前的所有计算都安全地在浮点有限范围内:a * a小于 1、a * a + 1.0小于 2 和sqrt(a * a + 1.0)小于 1.42。当我们乘以 时b,最终结果可能会溢出到 ∞。发生这种情况的原因有两个:a + b i 的大小可能超出浮点有限范围,因此溢出是正确的。或者先前计算中的舍入可能导致sqrt(a * a + 1.0)比数学结果略大,并且b * sqrt(a * a + 1.0)当幅度的实际值在范围内时足以导致溢出。由于这不是我们的重点,我不会在这个答案中进一步分析这个案例。

除了那个四舍五入的问题,前两种情况都很好。但是,此代码不正确:

else if (b == NAN)

根据 IEEE-754 2008 5.11 和 IEEE-754 1985 5.7,NaN 不小于、等于或大于任何操作数,包括它自己。它是无序的。这意味着b == NAN如果使用 IEEE-754,则必须返回 false。C 2018 不要求使用 IEEE-754,但脚注 22(在 5.2.4.2.2 4)表示,如果不支持 IEC 60559:1989(实际上是 IEEE-754),则术语“安静 NaN”和“信号C 标准中的 NaN”旨在应用于具有类似行为的编码。并且 7.12 5 告诉我们NAN扩展为float代表安静的 NaN。因此, inb == NAN应该NAN表现为 IEEE-754 NaN,因此b == NAN应该产生 0,表示 false。

因此,这个由 控制的代码else if (b == NAN)永远不会被执行:

y = b;

相反,执行落到else,它执行:

y = a * sqrt(2);

如果a是 NaN,则根据需要,结果是 NaN。但是,如果a是一个数字并且b是一个 NaN,那么当期望的结果是一个 NaN 时,这会产生一个数字作为结果。因此,代码被破坏了。


推荐阅读