为什么C为此算法赋予Python不同的值?

时间:2016-09-12 21:56:40

标签: c math linear-interpolation

我在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

2 个答案:

答案 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之间的差异不是一小部分。您需要查看收敛标准。它可能应该将bfofc进行比较,并在给定的小数位数内 - 或者沿着这些行进行比较。

答案 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