Logical error in bisection algorithm code - c

I am writing a program to demonstrate the bisection algorithm(from numerical methods).
What I am doing is this:
defined a function F(int), which takes the integer and returns the value of the polynomial at that integer.
In the bisection() function:
a) a,b are the initial approximations.
b) the for() construct finds the value of a after which the sign(magnitude) of F(a) changes.
c) the printfs are for troubleshooting purposes(except for the last one).
d) int prec is for the precision required for the solution (no. of iterations), where no. of iterations, N=log((b-a)/E), E=10^(-prec).
What I'm getting is this:
Output:
a=1 F(a)=-0.207936
a=1, b=2
Approximation 0: x = 0 a=1072693248 b=1
Approximation 1: x = 0 a=1072693248 b=1
Approximation 2: x = 0 a=1072693248 b=1
Approximation 3: x = 0 a=1072693248 b=1
Approximation 4: x = 0 a=1072693248 b=1
The solution is: x = 1.000000
I have tried commenting the N=... statement and assigning constant integer to N, but to no effect.
Interestingly, commenting out all statements with variable x in the for() construct does not alter values of a and b.
Oddly, if the statement x=(a+b)/2; is commented out, then the value of a is affected by the value with which x is initialized:
i) a=1072693248, when x=1,
ii)when x=0, a=0,b=0
iii)when x=-1, a=-1074790400, b=1
I am using Microsoft Visual C++ 2010 Express for compilation.
Please help me out.
Here is the code:
#include<stdio.h>
#include<math.h>
#define MIN -10
double F(int x)
{
double y=(x*x)-(2*x)+0.792064;
// printf("\nx=%d y=%d",x,y);
return y;
}
void bisection(int prec)
{
int a,b=0;
int c,N=10,i;
double x=0;
for(a=MIN;(F(a)*F(a-1))>0;a++);
printf("\na=%d F(a)=%f",a,F(a));
b=a+1;
printf("\n\na=%d, b=%d",a,b);
N=(log((float)(b-a))+5);
for(i=0;i<N;i++)
{
x=(a+b)/2;
printf("\nApproximation %d: x = %d\ta=%d b=%d",i,x,a,b);
if((F(a)*F(x)>0))
a=x;
else
b=x;
}
printf("\n\nThe solution is: x = %f",x);
getchar();
}
int main()
{
bisection(4);
return 0;
}

It's because a and b are declared as ints. When you write x = (a + b) / 2;, all the elements on the right side are integers, so they will be evaluated to an integer. Moreover, as the difference of a and b is 1, the value would be equal to the smaller one of them, which is a. That's why the value of x becomes 1.0. To fix it, the upper and lower limits should be declared as doubles, not ints. When a and b are integers, their values cannot converge to the actual value of x.
Also, you're using %d in printf to write a double value. It should be %lf.

Related

Why is my method for this question wrong: Write a function power (int a, int b), to calculate the value of a raised to b using while loop in c

Note: I am a total beginner at c and this question was given in my university assignment.
Question: Write a function power (int a, int b), to calculate the value of a raised to b using while loop in C.
I used the following code for the hackerrank question given above:
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
int power(int a, int b);
int main() {
/* Enter your code here. Read input from STDIN. Print output to STDOUT */
int a, b, result;
scanf("%d %d", &a, &b);
result = power(a, b);
printf("%d", result);
return 0;
}
int power(int x, int y) {
int z = x;
while (y > 1) {
x *= z;
y--;
}
return x;
}
But this problem gave me errors in some of the test cases. This was easily fixed by just changing z=x to z=1, x*=z to z*=x and return (x) to return (z).
But I do not understand why my initial code was wrong.
Using z=1 instead of z=x fixes the result for y=0.[1]
The other two changes just serve to make the code clearer, but provide no function difference.
The results are still wrong for y<0 even with this fix. However, the function is not very useful for y<0 since the best it could do is to round to 0 or 1, usually 0.
Your code:
int power(int x,int y)
{
int z=x;
while (y>1)
{
x*=z;
y--;
}
return(x);
}
Will start multiplying already with x, when none of the y was yet used for multiplication. On the other hand, using 1 would result in 1 without any multiplication and requires the first decrement of y to become x. This matches the required result of 1 for x to the power of 0.
Using z*=x repeatedly multiplies with x, which results as expected in x to the power of y (when starting with 1).
Doing x*=z results in repeated multiplication with z (which was x in your code), which seems right. But because of the need to start with 1 (see above) AND to keep the original value of x, a second variable is needed. Keeping the original value of x and storing the changing result in the new variable makes more sense than the other way round.
Returning the variable which contains the result is obvious, it just is the other variable after the change above.
Negative values of y seem to be irrelevant four your assignment. If they also need to be covered think of the result of e.g. x to the power of 2, then "undo" that, by subtracting 2 again from the exponent by dividing twice by x again. You are back at x to the power of 0. Then "undo" the same way again, i.e. divide twice again by x. The result is then x to the power of -2, i.e. 1/(x*x).

taylor series with error at most 10^-3

I'm trying to calculate the the taylor series of cos(x) with error at most 10^-3 and for all x ∈ [-pi/4, pi/4], that means my error needs to be less than 0.001. I can modify the x +=in the for loop to have different result. I tried several numbers but it never turns to an error less than 0.001.
#include <stdio.h>
#include <math.h>
float cosine(float x, int j)
{
float val = 1;
for (int k = j - 1; k >= 0; --k)
val = 1 - x*x/(2*k+2)/(2*k+1)*val;
return val;
}
int main( void )
{
for( double x = 0; x <= PI/4; x += 0.9999 )
{
if(cosine(x, 2) <= 0.001)
{
printf("cos(x) : %10g %10g %10g\n", x, cos(x), cosine(x, 2));
}
printf("cos(x) : %10g %10g %10g\n", x, cos(x), cosine(x, 2));
}
return 0;
}
I'm also doing this for e^x too. For this part, x must in [-2,2] .
float exponential(int n, float x)
{
float sum = 1.0f; // initialize sum of series
for (int i = n - 1; i > 0; --i )
sum = 1 + x * sum / i;
return sum;
}
int main( void )
{
// change the number of x in for loop so you can have different range
for( float x = -2.0f; x <= 2.0f; x += 1.587 )
{
// change the frist parameter to have different n value
if(exponential(5, x) <= 0.001)
{
printf("e^x = %f\n", exponential(5, x));
}
printf("e^x = %f\n", exponential(5, x));
}
return 0;
}
But whenever I changed the number of terms in the for loop, it always have an error that is greater than 1. How am I suppose to change it to have errors less than 10^-3?
Thanks!
My understanding is that to increase precision, you would need to consider more terms in the Taylor series. For example, consider what happens when
you attempt to calculate e(1) by a Taylor series.
$e(x) = \sum\limits_{n=0}^{\infty} frac{x^n}{n!}$
we can consider the first few terms in the expansion of e(1):
n value of nth term sum
0 x^0/0! = 1 1
1 x^1/1! = 1 2
2 x^2/2! = 0.5 2.5
3 x^3/3! = 0.16667 2.66667
4 x^4/4! = 0.04167 2.70834
You should notice two things, first that as we add more terms we are getting closer to the exact value of e(1), also that the difference between consecutive sums are getting smaller.
So, an implementation of e(x) could be written as:
#include <stdbool.h>
#include <stdio.h>
#include <math.h>
typedef float (*term)(int, int);
float evalSum(int, int, int, term);
float expTerm(int, int);
int fact(int);
int mypow(int, int);
bool sgn(float);
const int maxTerm = 10; // number of terms to evaluate in series
const float epsilon = 0.001; // the accepted error
int main(void)
{
// change these values to modify the range and increment
float start = -2;
float end = 2;
float inc = 1;
for(int x = start; x <= end; x += inc)
{
float value = 0;
float prev = 0;
for(int ndx = 0; ndx < maxTerm; ndx++)
{
value = evalSum(0, ndx, x, expTerm);
float diff = fabs(value-prev);
if((sgn(value) && sgn(prev)) && (diff < epsilon))
break;
else
prev = value;
}
printf("the approximate value of exp(%d) is %f\n", x, value);
}
return 0;
}
I've used as a guess that we will not need to use more then ten terms in the expansion to get to the desired precision, thus the inner for loop is where we loop over values of n in the range [0,10].
Also, we have several lines dedicated to checking if we reach the required precision. First I calculate the absolute value of the difference between the current evaluation and the previous evaluation, and take the absolute difference. Checking if the difference is less than our epsilon value (1E-3) is on of the criteria to exit the loop early. I also needed to check that the sign of of the current and the previous values were the same due to some fluctuation in calculating the value of e(-1), that is what the first clause in the conditional is doing.
float evalSum(int start, int end, int val, term fnct)
{
float sum = 0;
for(int n = start; n <= end; n++)
{
sum += fnct(n, val);
}
return sum;
}
This is a utility function that I wrote to evaluate the first n-terms of a series. start is the starting value (which is this code always 0), and end is the ending value. The final parameter is a pointer to a function that represents how to calculate a given term. In this code, fnct can be a pointer to any function that takes to integer parameters and returns a float.
float expTerm(int n, int x)
{
return (float)mypow(x,n)/(float)fact(n);
}
Buried down in this one-line function is where most of the work happens. This function represents the closed form of a Taylor expansion for e(n). Looking carefully at the above, you should be able to see that we are calculating $\fract{x^n}{n!}$ for a given value of x and n. As a hint, for doing the cosine part you would need to create a function to evaluate the closed for a term in the Taylor expansion of cos. This is given by $(-1)^n\fact{x^{2n}}{(2n)!}$.
int fact(int n)
{
if(0 == n)
return 1; // by defination
else if(1 == n)
return 1;
else
return n*fact(n-1);
}
This is just a standard implementation of the factorial function. Nothing special to see here.
int mypow(int base, int exp)
{
int result = 1;
while(exp)
{
if(exp&1) // b&1 quick check for odd power
{
result *= base;
}
exp >>=1; // exp >>= 1 quick division by 2
base *= base;
}
return result;
}
A custom function for doing exponentiation. We certainly could have used the version from <math.h>, but because I knew we would only be doing integer powers we could write an optimized version. Hint: in doing cosine you probably will need to use the version from <math.h> to work with floating point bases.
bool sgn(float x)
{
if(x < 0) return false;
else return true;
}
An incredibly simple function to determine the sign of a floating point value, returning true is positive and false otherwise.
This code was compiled on my Ubuntu-14.04 using gcc version 4.8.4:
******#crossbow:~/personal/projects$ gcc -std=c99 -pedantic -Wall series.c -o series
******#crossbow:~/personal/projects$ ./series
the approximate value of exp(-2) is 0.135097
the approximate value of exp(-1) is 0.367857
the approximate value of exp(0) is 1.000000
the approximate value of exp(1) is 2.718254
the approximate value of exp(2) is 7.388713
The expected values, as given by using bc are:
******#crossbow:~$ bc -l
bc 1.06.95
Copyright 1991-1994, 1997, 1998, 2000, 2004, 2006 Free Software Foundation, Inc.
This is free software with ABSOLUTELY NO WARRANTY.
For details type `warranty'.
e(-2)
.13533528323661269189
e(-1)
.36787944117144232159
e(0)
1.00000000000000000000
e(1)
2.71828182845904523536
e(2)
7.38905609893065022723
As you can see, the values are well within the tolerances that you requests. I leave it as an exercise to do the cosine part.
Hope this helps,
-T
exp and cos have power series that converge everywhere on the real line. For any bounded interval, e.g. [-pi/4, pi/4] or [-2, 2], the power series converge not just pointwise, but uniformly to exp and cos.
Pointwise convergence means that for any x in the region, and any epsilon > 0, you can pick a large enough N so that the approximation you get from the first N terms of the taylor series is within epsilon of the true value. However, with pointwise convergence, the N may be small for some x's and large for others, and since there are infinitely many x's there may be no finite N that accommodates them all. For some functions that really is what happens sometimes.
Uniform convergence means that for any epsilon > 0, you can pick a large enough N so that the approximation is within epsilon for EVERY x in the region. That's the kind of approximation that you are looking for, and you are guaranteed that that's the kind of convergence that you have.
In principle you could look at one of the proofs that exp, cos are uniformly convergent on any finite domain, sit down and say "what if we take epsilon = .001, and the regions to be ...", and compute some finite bound on N using a pen and paper. However most of these proofs will use at some steps some estimates that aren't sharp, so the value of N that you compute will be larger than necessary -- maybe a lot larger. It would be simpler to just implement it for N being a variable, then check the values using a for-loop like you did in your code, and see how large you have to make it so that the error is less than .001 everywhere.
So, I can't tell what the right value of N you need to pick is, but the math guarantees that if you keep trying larger values eventually you will find one that works.

Finding multiplicative inverse of x in Z(n), extended Euclides algorithm

I'm trying to find multiplicative inverse of x using GMP library; I know there is a built-in function, but I want to write my own.
This is my extended Euclides algorithm implementation:
void extended_euclides(mpz_t r,mpz_t x,mpz_t y,mpz_t a, mpz_t b){
mpz_t r_2,r_1,x_2,x_1,y_2,y_1,q,tmp;
mpz_inits(r,x,y,NULL);
mpz_init_set(r_2,a);
mpz_init_set(r_1,b);
mpz_init_set_ui(x_2,1);
mpz_init_set_ui(y_2,0);
mpz_init_set_ui(x_1,0);
mpz_init_set_ui(y_1,1);
mpz_init_set_ui(q,0);
mpz_init_set_ui(tmp,0);
do{
mpz_fdiv_qr(q,r,r_2,r_1);
//x
mpz_mul(tmp,q,x_1);
mpz_sub(x,x_2,tmp);
//y
mpz_mul(tmp,q,y_1);
mpz_sub(y,y_2,tmp);
mpz_set(x_2,x_1);
mpz_set(x_1,x);
mpz_set(y_2,y_1);
mpz_set(y_1,y);
mpz_set(r_2,r_1);
mpz_set(r_1,r);
}while(mpz_cmp_ui(r,0)!=0);
mpz_set(r,r_1);
mpz_set(x,x_2);
mpz_set(y,y_2);
mpz_clears(r_2,r_1,x_2,y_2,x_1,y_1,q,tmp,NULL);
}
It works fine for all small numbers and for some big numbers but not for all, and I don't known why. Example numbers for which it doesn't work:
a=99493485436357509294299436068793093643611893389896126764674829386592836165461754466092785338067969036756243799506670417432259164622123562781847156006846186608672621538507317131150760491084706497192710261706218845591564505899259562270249156644155861984060987885202877640033289062925176647874893491223532714128
b=202287573793610924311033969010234326099
if I change b to:
b=202287573793610924311033969010234326199
it works fine (I changed first 0 from right side to 1); the result I get is:
-26280231501456618600907242915048902345641123248519760433640466576442417888637174268721528225514196371138187569270563190841794774411834326405888357503240710494456394764379952360665884114850067939183395690214208147924280567331029828334399167395301049535292042342359035346464834873473183771024039179653285711685
The correct result, calculated by GMP function and checked by me in equation b*b^-1 ≡ 1 mod (a), is:
73213253934900890693392193153744191297970770141376366331034362810150418276824580197371257112553772665618056230236107226590464390210289236375958798503605476114216226774127364770484876376234638558009314571492010697667283938568229733935849989248854812448768945542843842293568454189451992876850854311570247002443
If a and b are co-prime, extended Euclid algorithm finds x and y such that
x a + y b == 1
but either x or y may be negative. For y = inverse of b modulo a,
if y < 0 then y = y + a,
which will convert y to a proper value modulo a (note my prior comment).
The wiki example finds t = inverse of a modulo n, and has the same check:
if t < 0 then t = t + n
http://en.wikipedia.org/wiki/Extended_Euclidean_algorithm#Modular_integers

0.1 increment in a While Loop (C Programming)

I am in an introductory C programming class. Our latest project has us writing code to tabulate x and sqrt(x) values from 1-10 with a 0.1 step using a while loop. When I try to do the 0.1 increment, however, nothing is added to the starting integer 1 and the program runs in an infinite loop. I'll post the code below. Other than it not doing the step, the program runs fine (and works with other increments like 1, etc.). How do I resolve this?
#include <stdio.h>
#include <math.h>
int main(void)
{
int x=1;
double sq_rt;
printf("Square Root Table: \n");
printf("Value of X Square Root of X\n");
while (x <= 10)
{
sq_rt = sqrt (x);
printf("%6i %20f \n", x, sq_rt);
x += 1e-1;
}
return 0;
}
An int type will only allow you to store whole numbers (i.e. -2, -1, 0, 1, 2 etc). To store numbers with a decimal point, you'll need a double precision (or double) type. Change the first line of main() to:
double x = 1.0;
If you try to add 1e-1 to an int, it will convert it to an int first - the type of x - which when truncated will end up being zero, so you'll never actually add anything to x.
The line in your program which reads
x += 1e-1;
is performing operations equivalent to
x = (int)(((double)x) + 0.1);
In other words, x is first converted to a double, then 0.1 is added to it, resulting in 1.1. This value is then converted to int, resulting in a value of 1, which is assigned to x.
The fix is to change the type of x to a floating point type such as float or double.
Share and enjoy.
the following code is a suggestion on how to perform the desired algorithm.
#include <stdio.h>
#include <math.h>
// define the magic numbers, don't embed them in the code
#define UPPER_LIMIT (10.0)
#define STEP_SIZE (0.1)
int main(void)
{
double x=1.0;
double sq_rt;
printf("Square Root Table: \n");
printf("Value of X Square Root of X\n");
// due to ambiguities in 'real' values,
// this loop will iterate approx. 90 times.
while( x < UPPER_LIMIT )
{
sq_rt = sqrt (x);
// display the two double values
// note: long float conversion values
// because the underlying numbers are double
// note: blanks for alignment with column headers
printf("%9.6lf %16.13lf \n", x, sq_rt);
// increase base value by increment of 0.1
x += STEP_SIZE;
} // end while
return 0;
} // end function: main

Why does this division result in zero?

I was writing this code in C when I encountered the following problem.
#include <stdio.h>
int main()
{
int i=2;
int j=3;
int k,l;
float a,b;
k=i/j*j;
l=j/i*i;
a=i/j*j;
b=j/i*i;
printf("%d %d %f %f\n",k,l,a,b);
return 0;
}
Can anyone tell me why the code is returning zero for the first and third variables (k and a)?
Are you asking why k and a show up as zero? This is because in integer division 2/3 = 0 (the fractional part is truncated).
What I think you are experiencing is integer arithmetic. You correctly suppose l and b to be 2, but incorrectly assume that k and a will be 3 because it's the same operation. But it's not, it's integer arithmetic (rather than floating-point arithmetic). So when you do i / j (please consider using some whitespace), 2 / 3 = 0.33333... which is cast to an int and thus becomes 0. Then we multiply by 3 again, and 0 * 3 = 0.
If you change i and j to be floats (or pepper your math with (float) casts), this will do what you expect.
You haven't said what you're getting or what you expect, but in this case it's probably easy to guess. When you do 'a=i/j*j', you're expecting the result to be roughly .2222 (i.e. 2/9), but instead you're getting 0.0. This is because i and j are both int's, so the multiplication and (crucially) division are done in integer math, yielding 0. You assign the result to a float, so that 0 is then converted to 0.0f.
To fix it, convert at least one operand to floating point BEFORE the division: a = (float)i/j*j);
this is due to how the c compiler treats int in divisions:
#include <stdio.h>
int main()
{
int i=2;
int j=3;
int k,l;
float a,b;
k=i/j*j; // k = (2/3)*3=0*3=0
l=j/i*i; // l = (3/2)*2=1*2=2
a=i/j*j; // same as k
b=j/i*i; // same as b
printf("%d %d %f %f/n",k,l,a,b);
return 0;
}
If you're asking why k and a are 0: i/j*j is the same as (i/j)*j. Since j is larger than i, i/j is 0 (integer division). 0*j is still 0, so the result (k) is 0. The same applies to the value of a.
it doesn’t matter if you’re variable is float or not, as long you’re using
integer / integer , you’ll get 0,
but because you’re using a float output, you get 0.0

Resources