簡體   English   中英

需要計算雙精度浮點數的復數對數

[英]Need to calculate the complex log of a double precision float

我嘗試使用以下方法計算 clog(a + i*b) 的實部

將“x”視為復數。 x = a + i*b 令 z 為 x 的復數對數。

實數(x) = 0.5 * log(a^2 + b^2)

對於 0.5 到 1.0 之間的值,這種方法在 ULP 方面會產生巨大的誤差。

我嘗試了其他方法來避免實部和虛部的平方,例如

令 t = b / a; 實數(x) = log(a) + 0.5 * log1p(t*t)

這種方法也繼續存在錯誤。 我知道錯誤可能來自 a 和 b 的平方,因此我嘗試使用fma()操作來獲取由於“a”和“b”的平方而導致的錯誤

設 a2 = a * a b2 = b * b

err_a2 = fma(a,a,-a2)

err_b2 = fma(b,b,-b2)

然后我嘗試0.5 * log(((err_a1 + err_b2) + a2) + b2)來獲得 x 的復數對數的實際值。

但結果仍然不准確。

如何准確計算log(sqrt(a^2 + b^2)) (2 ULP 內的錯誤)。 我想我需要以更高的精度以更高的精度計算a^2 + b^2的平方根,但我不知道如何從這里開始。

sqrt(a^2 + b^2)只是std::hypot(a,b) 運氣好的話,這已經很精確了。

...計算雙精度的復數對數...

代碼可以使用double real_part = (double) clog(x)


|x| == 1.0附近不使用clog(x)計算復數對數的實部 |x| == 1.0 ,考慮使用log1p() *1來形成更好的精度結果。

核心問題是|x| - 1.0 |x| - 1.0可能會嚴重損失精度,這是確定log()的第一步。

0.5 * log(a^2 + b^2)在數學上類似於0.5 * logp1(a^2 + b^2 - 1) |x| 接近 1.0 並且|a| > |b| |a| > |b| ,使用0.5 * logp1((a-1)*(a+1) + b^2) 這從|a|中減去 1.0 完全正確,因此在(a-1)*(a+1) + b^2中保持精度。

#include <complex.h>
#include <math.h>
#include <stdio.h>

#define root2 1.4142135623730950488016887242097

double clog_real(double a, double b) {
  double real_x;
  double h = hypot(a, b);
  // |x| near 1.0?
  if (h >= root2 / 2 && h < root2) {
    // Subtract 1 from the larger part
    if (fabs(a) > fabs(b)) {
      real_x = 0.5 * log1p((a - 1) * (a + 1) + b * b);
    } else {
      real_x = 0.5 * log1p((b - 1) * (b + 1) + a * a);
      // or (here and like-wise above)
      real_x = 0.5 * log1p(fma(a, a, (b - 1) * (b + 1)));
    }
  } else {
    real_x = log(h);
  }
  return real_x;
}

int main() {
  double a = 0x1.fffffe0000010p-12 * 2;
  double b = 0x1.fffffc0000040p-1;
  printf("%g %g\n", a, b);
  complex double c = a + csqrt(-1) * b;
  printf("%g\n", (double) clog(c));
  printf("%g\n", clog_real(a, b));
}

Output

0.000976562 1
3.57628e-07
3.57628e-07

回復:“我嘗試使用fma() ...”-> 一些fma()質量低


*1 log1p函數計算 1 加上參數的以 e 為底的(自然)對數。

你試過log(sqrt(a*a + b*b))嗎? 通常,平方根具有與平方相反的效果,所以如果你嘗試計算它,你可能會得到一個更合適的數字的對log

無論如何,要計算接近 1.0 的數字的對數,您可能可以計算z == 0log(z + 1)的導數,您會得到更好的方法,因為 function 在半徑 < 0.5 的圓中是 analitic 並且所以,你會得到一個很好的泰勒近似值。 這個近似值寫在下面(感謝 Wolfram alpha)

log(1+x) ~= x - x^2/2 + x^3/3 - x^4/4 + ... (-1)^(n)*x^(n+1)/(n+1) + O(x^(n+2))

這是一個絕對收斂於半徑為 1 的開放圓上的序列,因此計算接近 1 或對數的值非常適合(實際上,它在許多地方都使用)。

當然,如果你想在復平面上解決這個問題,你需要將計算作為復數來操作。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM