4

I'm trying to implement the Regula-Falsi Algorithm to solve the equation of 2(x^3)-x-2 but the problem is that the variable c value is staying constant and it is not changing, even that my code should change it .

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


float fonc(float x)
{
    int result;
    result=2*(pow(x,3))-x-2;
    return result;
}

int main(void)
{
    float eps=pow(10,-4);
    int i=0;
    float a,b,c;
    a=1;
    b=2;
    do
    {
        c=((a*fonc(b))-(b*fonc(a)))/((fonc(b)-fonc(a)));
        if(fonc(c)*fonc(a)<0)
        {
            b=c;
        }
        else
        {
            a=c;
        }
        i++;    
        printf("\n%f",c);
    }
    while(fabs(b-c)>eps);

    printf("le nombre d'itération %d",i);
}
Filburt
  • 17,626
  • 12
  • 64
  • 115
  • Prefer `double` to `float`. – pmg Mar 14 '14 at 22:11
  • even with the double we go to some place where it is no longer possible to get the precison correct –  Mar 14 '14 at 22:19
  • I meant generally, not specifically for this program. If you need a floating-point number your first reaction should be to use a `double` – pmg Mar 14 '14 at 22:21
  • `pow(10,-4)` no don't do that, use `1e-4` or `1e-4f` instead – phuclv Jul 30 '22 at 15:39

3 Answers3

3

Okay, just for the sake of correcting the algorithm to actually perform what it was meant to perform:

Along with changing the type of result from int to float, you also need to change the loop condition. Currently it is:

    while ( fabs( b - c ) > eps );

Which means that the loop will continue happening until the distance between the values b and c become lower than 0.0001, and under this condition, currently, at least on my end, the code runs forever.

We aren't after reducing the difference between b and c anyway. What we really are after is that the fonc( c ) = 2*c*c*c - c - 2 to be less than our eps. In the end, we want it to be as close as possible to zero, so that c becomes approximately a root of the function. So simply:

    while ( fabs( fonc( c ) ) > eps );

is what our condition should be. This way, along with the int --> float change, it doesn't fall into an infinite loop, completing the job in 14 iterations.

Utkan Gezer
  • 3,009
  • 2
  • 16
  • 29
  • Ohhh that's so much better now i really understand the algorithm now ,Thank you so much –  Mar 08 '14 at 19:58
  • @AbdelhadiKhiati I also didn't know about this method, I had to search for and learn about it first. Glad it helped bro. – Utkan Gezer Mar 08 '14 at 20:01
  • Actually, use both conditions, let the while condition stay as it is and make the function value an if with a break. -- The vanilla regula falsi algorithm may get stuck on changing only one side of the interval. Draw a convex, monotonically inreasing function like x^2-3 on paper and try it out. This converges very slowly and the interval length does not converge to zero. That is why variants of the algorithm were introduced that cure that problem, the most simple one is the Illinois variation. See wikipedia page on the false position method. – Lutz Lehmann Mar 09 '14 at 15:43
  • Or more correctly, compare to both ends of the interval, `while ( ( fabs( b - c ) > eps ) && ( fabs( b - c ) > eps ) );`. If the algorithm stalls at one end of the interval, this measures the length of the update. – Lutz Lehmann Mar 17 '14 at 11:13
3

What can go wrong with the algorithm as presented, even if all data types were appropriate?

In contrast to the bisection method, the pure regula falsi will not force the interval length to go to zero. If a monotone and convex function is used, the iteration will stall at changing only one side of the interval with geometric convergence. Any sufficiently smooth function will eventually have these properties over the remaining bracketing interval.

To correctly catch this behavior, the midpoint c should be compared to both interval ends a, b immediately after computation. As bonus point, check if the value at c is small enough and if true, also break the iteration regardless of how far from the ends of the interval this is.


There exist many simple tricks to force the interval length to be zero. The complicated tricks lead to the Brent's method. Of simple tricks one is the Illinois variant. In these variants, the midpoint is considered as a convex sum

    c = |f(b)|/(|f(a)|+|f(b)|) * a + |f(a)|/(|f(a)|+|f(b)|) * b

Because of the opposite signs of f(a) and f(b), this is equivalent to the original formula. If the side b does not change, its importance in this convex sum is increased by decreasing the function value f(b), i.e., multiplying it with additional weight factors. This moves the midpoint c towards b, which will in very few steps find a midpoint that will replace b.


The following is an implementation of the Illinois variant of regula falsi (or false position method). The algorithm finds a solution with function value 2.2e-6 and an enclosing interval of length 6e-7 in 6 iterations.

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


float fonc(float x)
{
   return (2*x*x-1)*x-2;
}

int main(void)
{
    float eps=1e-6;
    int i=0;
    float a=1, fa = fonc(a);
    float  b=2, fb = fonc(b);
    
    printf("\na=%10.7f b=%10.7f  fa=%10.7f  fb=%10.7f\n------\n",a,b, fa,fb);
    
    if(signbit(fb)==signbit(fa)) {
        printf("Attention, les valeurs initiales de 'fonc' n'ont pas de signe opposeés!\n");
        
    }
    do
    {
        float c=(a*fb-b*fa)/(fb-fa), fc = fonc(c);
        
        if( signbit(fc)!=signbit(fa) )
        {
            b=a; fb=fa;
        }
        else
        {
            fb *= 0.5;
        }
        a=c; fa=fc;
        i++;  
        printf("\na=c=%10.7f b=%10.7f  fa=fc=%10.7f  fb=%10.7f",c,b, fc,fb);
        
        if(fabs(fc)<eps) break;
    }
    while(fabs(b-a)>eps);

    printf("\nle nombre d'itération %d\n",i);
    
    return 0;
}

The output is

     a= 1.0000000 b= 2.0000000  fa=-1.0000000  fb=12.0000000
     ------
     
     a=c= 1.0769231 b= 2.0000000  fa=fc=-0.5789710  fb= 6.0000000
     a=c= 1.1581569 b= 2.0000000  fa=fc=-0.0512219  fb= 3.0000000
     a=c= 1.1722891 b= 1.1581569  fa=fc= 0.0497752  fb=-0.0512219
     a=c= 1.1653242 b= 1.1722891  fa=fc=-0.0003491  fb= 0.0497752
     a=c= 1.1653727 b= 1.1722891  fa=fc=-0.0000022  fb= 0.0248876
     a=c= 1.1653733 b= 1.1653727  fa=fc= 0.0000020  fb=-0.0000022
     le nombre d'itération 6
Lutz Lehmann
  • 25,219
  • 2
  • 22
  • 51
2

One problem is that result is int. You almost certainly want to be float or double, as otherwise the result of fonc() is getting truncated to an integer.

NPE
  • 486,780
  • 108
  • 951
  • 1,012
  • Tried to change it ,Stille the same problem –  Mar 08 '14 at 19:12
  • @AbdelhadiKhiati: That's odd; this should fix it. Did you save the file? Did you recompile/link it? Did you run the correct binary? – NPE Mar 08 '14 at 19:15
  • @AbdelhadiKhiati Did it really solve everything? On my end, this change alone still causes the programme to get into an infinite loop. Of course, this change is absolutely necessary, but the code still seems to need more attention. – Utkan Gezer Mar 08 '14 at 19:28
  • @ThoAppelsin yes that changed somethings for me the loop is infinite and sometimes finite i really don't know what is going on with it but the results are being stable no matter how much i change the precision of (eps) :/ –  Mar 08 '14 at 19:52
  • @AbdelhadiKhiati refer the answer I just gave. Also, you might want to change `"\n%f"` inside `printf` into `"%f\n"` for cosmetic purposes. – Utkan Gezer Mar 08 '14 at 19:55
  • You would gain more insight into your implementation if you would write out more values of the iteration. For instance, print all of `a,fonc(a),b,fonc(b)`. To keep the output short, insert as first or last statement in the loop `if(i>40) break;`, along with `if(fabs(fonc(c)) – Lutz Lehmann Mar 09 '14 at 16:28