如何在 C 中用连分数实现自然对数?
How to implement natural logarithm with continued fraction in C?
这里有个小问题。从这个公式创建一些东西:
我有这个,但是没用。弗兰基,我真的不明白它应该如何工作。我试着用一些错误的指令来编写它。 N 是迭代次数和分数部分。我认为它以某种方式导致递归但不知道如何。
感谢您的帮助。
double contFragLog(double z, int n)
{
double cf = 2 * z;
double a, b;
for(int i = n; i >= 1; i--)
{
a = sq(i - 2) * sq(z);
b = i + i - 2;
cf = a / (b - cf);
}
return (1 + cf) / (1 - cf);
}
中央环路一团糟。返工。也不需要递归。只需先计算最深的项,然后再算出来。
double contFragLog(double z, int n) {
double zz = z*z;
double cf = 1.0; // Important this is not 0
for (int i = n; i >= 1; i--) {
cf = (2*i -1) - i*i*zz/cf;
}
return 2*z/cf;
}
void testln(double z) {
double y = log((1+z)/(1-z));
double y2 = contFragLog(z, 8);
printf("%e %e %e\n", z, y, y2);
}
int main() {
testln(0.2);
testln(0.5);
testln(0.8);
return 0;
}
输出
2.000000e-01 4.054651e-01 4.054651e-01
5.000000e-01 1.098612e+00 1.098612e+00
8.000000e-01 2.197225e+00 2.196987e+00
[编辑]
根据@MicroVirus 的提示,我发现 double cf = 1.88*n - 0.95;
比 double cf = 1.0;
更有效。随着使用的术语越多,所使用的值所产生的差异就越小,但是好的初始 cf
需要更少的术语才能得到好的答案,尤其是 |z|
接近 0.5 时。当我学习 0 < z <= 0.5
时,可以在这里做更多的工作。 @MicroVirus 对 2*n+1
的建议可能与我的建议很接近,因为 n
有一个偏差。
这是基于逆向计算并注意到 CF[n]
的值随着 n
的增加而得出的。我很惊讶 "seed" 值似乎不是一个很好的整数方程。
这是使用递归的问题的解决方案(如果有人感兴趣):
#include <math.h>
#include <stdio.h>
/* `i` is the iteration of the recursion and `n` is
just for testing when we should end. 'zz' is z^2 */
double recursion (double zz, int i, int n) {
if (!n)
return 1;
return 2 * i - 1 - i * i * zz / recursion (zz, i + 1, --n);
}
double contFragLog (double z, int n) {
return 2 * z / recursion (z * z, 1, n);
}
void testln(double z) {
double y = log((1+z)/(1-z));
double y2 = contFragLog(z, 8);
printf("%e %e %e\n", z, y, y2);
}
int main() {
testln(0.2);
testln(0.5);
testln(0.8);
return 0;
}
输出与上面的解决方案相同:
2.000000e-01 4.054651e-01 4.054651e-01
5.000000e-01 1.098612e+00 1.098612e+00
8.000000e-01 2.197225e+00 2.196987e+00
这里有个小问题。从这个公式创建一些东西:
我有这个,但是没用。弗兰基,我真的不明白它应该如何工作。我试着用一些错误的指令来编写它。 N 是迭代次数和分数部分。我认为它以某种方式导致递归但不知道如何。
感谢您的帮助。
double contFragLog(double z, int n)
{
double cf = 2 * z;
double a, b;
for(int i = n; i >= 1; i--)
{
a = sq(i - 2) * sq(z);
b = i + i - 2;
cf = a / (b - cf);
}
return (1 + cf) / (1 - cf);
}
中央环路一团糟。返工。也不需要递归。只需先计算最深的项,然后再算出来。
double contFragLog(double z, int n) {
double zz = z*z;
double cf = 1.0; // Important this is not 0
for (int i = n; i >= 1; i--) {
cf = (2*i -1) - i*i*zz/cf;
}
return 2*z/cf;
}
void testln(double z) {
double y = log((1+z)/(1-z));
double y2 = contFragLog(z, 8);
printf("%e %e %e\n", z, y, y2);
}
int main() {
testln(0.2);
testln(0.5);
testln(0.8);
return 0;
}
输出
2.000000e-01 4.054651e-01 4.054651e-01
5.000000e-01 1.098612e+00 1.098612e+00
8.000000e-01 2.197225e+00 2.196987e+00
[编辑]
根据@MicroVirus 的提示,我发现 double cf = 1.88*n - 0.95;
比 double cf = 1.0;
更有效。随着使用的术语越多,所使用的值所产生的差异就越小,但是好的初始 cf
需要更少的术语才能得到好的答案,尤其是 |z|
接近 0.5 时。当我学习 0 < z <= 0.5
时,可以在这里做更多的工作。 @MicroVirus 对 2*n+1
的建议可能与我的建议很接近,因为 n
有一个偏差。
这是基于逆向计算并注意到 CF[n]
的值随着 n
的增加而得出的。我很惊讶 "seed" 值似乎不是一个很好的整数方程。
这是使用递归的问题的解决方案(如果有人感兴趣):
#include <math.h>
#include <stdio.h>
/* `i` is the iteration of the recursion and `n` is
just for testing when we should end. 'zz' is z^2 */
double recursion (double zz, int i, int n) {
if (!n)
return 1;
return 2 * i - 1 - i * i * zz / recursion (zz, i + 1, --n);
}
double contFragLog (double z, int n) {
return 2 * z / recursion (z * z, 1, n);
}
void testln(double z) {
double y = log((1+z)/(1-z));
double y2 = contFragLog(z, 8);
printf("%e %e %e\n", z, y, y2);
}
int main() {
testln(0.2);
testln(0.5);
testln(0.8);
return 0;
}
输出与上面的解决方案相同:
2.000000e-01 4.054651e-01 4.054651e-01
5.000000e-01 1.098612e+00 1.098612e+00
8.000000e-01 2.197225e+00 2.196987e+00