我在C中写了一个简短的程序来执行线性插值,它迭代给出一个函数的根到给定的小数点数。到目前为止,对于函数f(x):
<% if crf.where(subject_id: sub.subject_id).first.send(crf_status(crf)) == 1 %>
<td bgcolor="#98FB98" >
<% else %>
程序无法收敛到1dp值。程序更新变量a和b,f(x)的根位于变量a和b之间,直到a和b都以给定的精度舍入到相同的数字。使用long double和上面的函数,调试器显示前两次迭代:
long double f(long double x) {
return (pow(x, 3) + 2 * x - 8);
}
虽然应该是:
a = 1.5555555555555556
a = 1.6444444444444444
此后程序无法更新值。线性插值方程I使用的是给定here的数学方法的重新排列版本,而使用的代码I是我编写的python程序的C版本。尽管算法相同,为什么C实现会得到不同的值,我该如何解决?
好的我仍然掌握这一点,但希望下面我有一个最小的,完整的,可验证的例子:
a = 1.5555555555555556
a = 1.653104925053533
答案 0 :(得分:7)
函数abs()
(来自<stdlib.h>
)具有签名int abs(int);
- 您将从计算中获得整数。
您应该使用long double fabsl(long double);
中的<math.h>
。
您还应该使用powl()
代替pow()
(long double
vs double
)和roundl()
代替roundf()
({{ 1}} vs long double
)。
确保您使用的是正确的类型,换句话说。
修复类型问题后,仍然存在收敛问题。如果你制作了一个MCVE(Minimal, Complete, Verifiable Example)会有所帮助。但是,这是我可以从您的问题中推断出的MCVE:
float
我得到的输出是:
#include <math.h>
#include <stdio.h>
static inline long double f(long double x)
{
return(powl(x, 3) + 2 * x - 8);
}
int main(void)
{
long double a = 1.0L;
long double b = 2.0L;
int dp = 6;
while (roundl(a * powl(10, dp)) / powl(10, dp) != roundl(b * powl(10, dp)) / powl(10, dp))
{
long double fofa = f(a);
long double fofb = f(b);
long double c = (b * fabsl(fofa) + a * fabsl(fofb)) / (fabsl(fofb) + fabsl(fofa));
long double fofc = f(c);
printf("a = %+.10Lf, f(a) = %+.10Lf\n", a, fofa);
printf("b = %+.10Lf, f(b) = %+.10Lf\n", b, fofb);
printf("c = %+.10Lf, f(c) = %+.10Lf\n", c, fofc);
putchar('\n');
if (fofc < 0.0L)
{
a = c;
}
else if (fofc == 0.0L)
{
a = c;
break;
}
else
{
b = c;
}
}
printf("Result: a = %Lg\n", a);
return 0;
}
无限循环的原因很明显; a = +1.0000000000, f(a) = -5.0000000000
b = +2.0000000000, f(b) = +4.0000000000
c = +1.5555555556, f(c) = -1.1248285322
a = +1.5555555556, f(a) = -1.1248285322
b = +2.0000000000, f(b) = +4.0000000000
c = +1.6531049251, f(c) = -0.1762579238
a = +1.6531049251, f(a) = -0.1762579238
b = +2.0000000000, f(b) = +4.0000000000
c = +1.6677455452, f(c) = -0.0258828049
a = +1.6677455452, f(a) = -0.0258828049
b = +2.0000000000, f(b) = +4.0000000000
c = +1.6698816424, f(c) = -0.0037639074
a = +1.6698816424, f(a) = -0.0037639074
b = +2.0000000000, f(b) = +4.0000000000
c = +1.6701919841, f(c) = -0.0005465735
a = +1.6701919841, f(a) = -0.0005465735
b = +2.0000000000, f(b) = +4.0000000000
c = +1.6702370440, f(c) = -0.0000793539
a = +1.6702370440, f(a) = -0.0000793539
b = +2.0000000000, f(b) = +4.0000000000
c = +1.6702435859, f(c) = -0.0000115206
a = +1.6702435859, f(a) = -0.0000115206
b = +2.0000000000, f(b) = +4.0000000000
c = +1.6702445357, f(c) = -0.0000016726
a = +1.6702445357, f(a) = -0.0000016726
b = +2.0000000000, f(b) = +4.0000000000
c = +1.6702446735, f(c) = -0.0000002428
a = +1.6702446735, f(a) = -0.0000002428
b = +2.0000000000, f(b) = +4.0000000000
c = +1.6702446936, f(c) = -0.0000000353
a = +1.6702446936, f(a) = -0.0000000353
b = +2.0000000000, f(b) = +4.0000000000
c = +1.6702446965, f(c) = -0.0000000051
a = +1.6702446965, f(a) = -0.0000000051
b = +2.0000000000, f(b) = +4.0000000000
c = +1.6702446969, f(c) = -0.0000000007
a = +1.6702446969, f(a) = -0.0000000007
b = +2.0000000000, f(b) = +4.0000000000
c = +1.6702446970, f(c) = -0.0000000001
a = +1.6702446970, f(a) = -0.0000000001
b = +2.0000000000, f(b) = +4.0000000000
c = +1.6702446970, f(c) = -0.0000000000
a = +1.6702446970, f(a) = -0.0000000000
b = +2.0000000000, f(b) = +4.0000000000
c = +1.6702446970, f(c) = -0.0000000000
a = +1.6702446970, f(a) = -0.0000000000
b = +2.0000000000, f(b) = +4.0000000000
c = +1.6702446970, f(c) = -0.0000000000
a = +1.6702446970, f(a) = -0.0000000000
b = +2.0000000000, f(b) = +4.0000000000
c = +1.6702446970, f(c) = -0.0000000000
和a
之间的差异不是一小部分。您需要查看收敛标准。它可能应该将b
与fofc
进行比较,并在给定的小数位数内 - 或者沿着这些行进行比较。
答案 1 :(得分:3)
您正在实施的内容称为 regular falsi 或 false position method 。
只要保持相反的符号条件,实际上没有必要使用绝对值。
有一个众所周知的拖延问题,普通的香草调节法,因为当函数在剩余的时间间隔内凸出时,一个终点将不再向根移动。可以轻松修改以避免这种情况,例如插入二分步骤。更容易实现但更难理解的是 Illinois修改。有关详细信息,请参阅Wikipedia关于规范falsi的文章。
或者这个问题和答案:Regula-Falsi Algorithm?
改编自链接中的答案:
#include<math.h>
#include<stdio.h>
long double f(long double x) {
return powl(x, 3) + 2 * x - 8;
}
int main(void) {
const int dp = 18;
long double eps=0.5*powl(10,-dp);
int i=0;
long double a=1, fofa = f(a);
long double b=2, fofb = f(b);
printf("\na=%.21Lf b=%.21Lf fofa=%.21Lf fofb=%.21Lf\n------\n",a,b, fofa,fofb);
if(signbit(fofb)==signbit(fofa)) {
printf("Warning, initial values do not have opposite sign!\n");
}
do {
long double c=(a*fofb-b*fofa)/(fofb-fofa), fofc = f(c);
if( signbit(fofc)!=signbit(fofa) ) {
b=a; fofb=fofa;
a=c; fofa=fofc;
} else {
a=c; fofa=fofc;
fofb *= 0.5;
}
i++;
printf("\na=c=%.21Lf b=%.21Lf fofa=fofc=%.21Lf fofb=%.21Lf",c,b, fofc,fofb);
} while(fabsl(b-a)>eps);
printf("\ngoal reached after %d iterations\n",i);
return 0;
}
结果
a=1.000000000000000000000 b=2.000000000000000000000 fofa=-5.000000000000000000000 fofb=4.000000000000000000000
------
a=c=1.555555555555555555507 b=2.000000000000000000000 fofa=fofc=-1.124828532235939643549 fofb=2.000000000000000000000
a=c=1.715539947322212467064 b=1.555555555555555555507 fofa=fofc=0.480046589479470829469 fofb=-1.124828532235939643549
a=c=1.667685780603345490963 b=1.715539947322212467064 fofa=fofc=-0.026500999000164700194 fofb=0.480046589479470829469
a=c=1.670189362207942139265 b=1.715539947322212467064 fofa=fofc=-0.000573759143326624515 fofb=0.240023294739735414734
a=c=1.670297511133477909220 b=1.670189362207942139265 fofa=fofc=0.000547652143260468627 fofb=-0.000573759143326624515
a=c=1.670244695550498326532 b=1.670297511133477909220 fofa=fofc=-0.000000014643676336194 fofb=0.000547652143260468627
a=c=1.670244696962696986627 b=1.670297511133477909220 fofa=fofc=-0.000000000000373724489 fofb=0.000273826071630234313
a=c=1.670244696962769068724 b=1.670244696962696986627 fofa=fofc=0.000000000000373706274 fofb=-0.000000000000373724489
a=c=1.670244696962733028543 b=1.670244696962769068724 fofa=fofc=-0.000000000000000000434 fofb=0.000000000000373706274
a=c=1.670244696962733028651 b=1.670244696962733028543 fofa=fofc=0.000000000000000000867 fofb=-0.000000000000000000434
goal reached after 10 iterations