[英]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 == 0
的log(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.