Wrong Output while finding the root of the equation in C - c

The following is the C code for calculating the roots of an equation using the Newton-Raphson Algorithm:
#include<stdio.h>
#include<math.h>
double function(double x);
double derivative(double x);
int main(){
double guess=3;
for(int i=0;i<100;i++){
double val=function(guess);
double d=derivative(guess);
guess=guess-val/d;
if(abs(function(guess))<0.00005){
printf("%lf",guess);
break;
}
}
return 0;
}
double function(double x){
return pow(x,5)+2; //f(x)=x^5+2
}
double derivative(double x){
double h=0.00001;
return (function(x+h)-function(x))/h;
}
But the output after compilation is -1.208869, which actually does not satisfy the condition that abs(f(x))<0.00005. What am I doing wrong here?

Your abs(function(guess)) call returns an integer value (cppreference), which will be truncated to zero if the value is less than 1 (as it is when your program stops).
What you need is the fabs() function, to return the absolute value of its given argument as a double.
Changing your if block to use this will work:
if (fabs(function(guess)) < 0.00005) { // Use "fabs" ... not "abs"
printf("%lf", guess);
break;
}

Related

Solution to heat equation

When trying to plot the solution of the heat PDE I've found some troubles. The solution that I've found is:
Here is the code:
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#define N 10000
double f(double x);
double X[N];
double Y[N];
int main(){
int i;
double b=43351/94400;
double dx=0.0001;
X[0]=0;
Y[0]=b;
for (i=1; i<N; i++){
X[i]=X[i-1]+dx;
Y[i]=f(X[i]);
}
FILE* output;
output = fopen("dades.txt", "w");
fprintf(output, "x PosiciĆ³ Temperatura\n");
for (i = 0; i < N; i++){
fprintf(output, "%lf %lf %lf\n", i*dx, X[i], Y[i]);
}
fclose(output);
return 0;
}
double f(double x){
int n;
double b=43351/94400;
for (n=1; n<N; n+=2){
double pi=3.14159265358979323846;
double t0=0.025;
double result=b;
result+=2*(1-pow((-1),n))/(pi*n)*(1-exp(-pow(n,2)*pow(pi,2)*pow(t0,2)))/(pow(n,2)*pow(pi,2))*sin(n*pi*x);
}
return result;
}
What I'm trying to do is to declare a function that calculates the infinite sum for n odd, and then looping it for every x between 0 and 1. The problem is that I don't know how to declare "result" in order to be the sum of all the terms, because if I declare it outside the for loop it doesn't satisfy the boundary conditions.
(Note that I fixed t=0.025).
According to the equation, you can implement f as:
#define M_PI 3.14159265358979323846;
double f(double x)
{
int n;
double result=43351.0/94400.0;
double t0=0.025;
for (n=1; n<N; n+=2){
result+=2*(1-pow((-1),n))/(M_PI*n)*(1-exp(-pow(n,2)*pow(M_PI,2)*pow(t0,2)))/(pow(n,2)*pow(M_PI,2))*sin(n*M_PI*x);
}
return result;
}
Since you are using double, so you have to explicitly add a .0 otherwise it may be considered as integer.
The declarations of variable are moved outside the loop in order both to clarify the code and ensure the variable result gets update instead of being overwritten.
EDIT:
You could improve the function f to take the value of t as an input. This also aligns with the equation provided. It would then implements this way:
double f(double x, double t)
{
int n;
double result=43351.0/94400.0;
for (n=1; n<N; n+=2){
result+=2*(1-pow((-1),n))/(M_PI*n)*(1-exp(-pow(n,2)*pow(M_PI,2)*pow(t,2)))/(pow(n,2)*pow(M_PI,2))*sin(n*M_PI*x);
}
return result;
}
EDIT:
The implementation of the math of the equation could be further simplified:
a^2 b^2 is same as (ab)^2.
(-1)^n with n odd is always -1.
2*(1-pow((-1),n)) is a replacement for 4.
Plus, from a performance perspective you can avoid recalculation of repeated terms by putting them in a variable and the use it as you need (for instance the n^2 pi^2).

can't implement any series that uses power or factorial

I wrote a program to calculate the value of e^x by series and by library function.See the following:
#include<stdio.h>
#include<math.h>
long long fact(int x)
{
long prod=1;
int i=1;
if(x==0)
return 1;
else{
while(i<=x)
{
prod=prod*i;
i++;
}
return prod;
}
}
int main()
{
int i;
float x;
double sum=1;
for(x=1;x<20;x++)
{
for(i=1;i<=10;i++)
{
if(fact(i)!=0);
sum=sum+pow(x,i)/fact(i);
}
printf("by code e=%.15lf\t\t",sum);
printf("by libfnc e=%.15f\t",exp(x));
printf("quotient =%.15f\n",sum/exp(x));
}
}
The code works for smaller values like 1,2 but with the increase of the value of x the difference (here quotient) increases.That is my code no longer gives correct answer for higher values of x.
You need function prototype before calling it.
Add some ifs to check if you do not divide by zero.
scanf returns number of successfully scanned elements. Check for 1 in this case.
int fct = fact(2*i);
if(fct)
sum=sum+y/(double)fct;
else
{printf("DIVISION BY ZERO!!!!\n"); return 1;}
You will discover that int is to small for factorial function. Change it to double. Also, use double in all floating point operations.
double fact(int x);
int main()
{
double sum,y;
int x,i=0;
double fct;
while(scanf("%d",&x) == 1)
{ sum=0;
for(i=0;i<=N;i++)
{
y=pow(-1,i)*pow(x,2*i);
fct = fact(2*i);
if(fct != 0.0)
sum=sum+y/fct;
else
{printf("DIVISION BY ZERO!!!!\n"); return 1;}
}
printf("using Maclaurin's series %.10f and original cosx=%.10f",sum,cos(x));
}
}
double fact(int x)
{
double prod=1.0;
int i=1;
for(i=1;i<=x;i++)
prod=prod*i;
return prod;
}
https://godbolt.org/z/qsh4qh3d1

numerical integration using a pointer to a function always return 0

I am trying to use the function that I was given by my professor to calculate the integral of a polynomial function (polynomial such as: ax^2+bx+c). the function is:
double numbericalIntegration(double a ,double b ,double(*func)(double)){
double delta = (b - a)/32;
double sum=0, x;
for(x= a+0.5*delta; x<b ; x+=delta)
{
sum+=(*func)(x);
}
return sum*delta;
}
I changed a lot in order to integrate a polynomial function. but I was get the answer 0. why is that? and I'd appreciate if anybody tried to correct my work. my code is:
double integralPoly(double x, double a, double b, double c){
return (a*pow(x,3))/3 +(b*pow(x,2))/2 + (c*x);
}
double numbericalIntegration(double a ,double b ,double(*func)(double,double,double,double), double firstNum, double secondNum, double thirdNum){
double delta = (b - a)/32;
double sum=0, x;
for(x= a+0.5*delta; x<b ; x+=delta)
{
sum+=(*func)(x, firstNum, secondNum, thirdNum);
}
return sum*delta;
}
int main()
{
double (*func)(double,double,double,double);
func = integralPoly;
double sum = numbericalIntegration(2,4,func,1,1,4);
printf("sum = %d",sum);
return 0;
}
You need to change two things. First your polynomial function doesn't make any sense. You said it needs to be in the form of ax^2+bx+c but in your code polynomial is (ax^3)/3+(bx^2)/2+c*x. Your function should be:
double integralPoly(double x, double a, double b, double c){
return (a*pow(x,2)) +(b*x) + c;
}
Also you need to change your printf. %d is integer type specifier and you need double, so you need to use %f for example:
printf("sum = %f",sum);
Now the output of your program is:
sum = 32.666016
which is correct for your parameters.

EQUATION SOLVER absurd result despite correct algorithm

#include<stdio.h>
#include<math.h>
#include<stdlib.h>
void bisect(float *p,int n,int a);
float value(float *p,int n,int a);
int main()
{
int a,i;
float *p;
printf("enter the degree of the polynomial\n");
scanf("%d",&a);
p=(float *) malloc(a*sizeof(float));
for(i=0;i<=a;i++)
{
printf("enter the coefficient of x^%d\n",i);
scanf("%f",p+i);
}
printf("%f\n",value(p,-2,a));
printf("%f\n",value(p,1,a));
printf("%f\n",value(p,0,a));
for(i=-100;i<100;i++)
{
if(value(p,i,a)*value(p,i+1,a)==0.000)
{
printf("%d\n",value(p,i+1,a));
if(value(p,i,a)==0&&value(p,i+1,a)==0.00)
{
printf("the roots are %d,%d\n",i,i+1);
}
if(value(p,i+1,a)==0.0)
{
printf("the real root is %d\n",i+1);
i++;
continue;
}
}
if(value(p,i,a)*value(p,i+1,a)<0)
{
bisect(p,i,a);
}
}
return 0;
}
float value(float *p,int n,int a)
{
float sum=0.0;
int i;
for(i=0;i<=a;i++)
{
sum=sum+*(p+i)*pow(n,i);
}
return sum;
}
void bisect(float *p,int n,int a)
{
float j,k,l;
int i;
j=n;k=n+1;l=(j+k)/2;
for(i=0;i<50;i++)
{
if(value(p,j,a)*value(p,l,a)==0){break;}
if(value(p,j,a)*value(p,l,a)<0)
{
j=j;k=l;l=(j+k)/2;
}
else if(value(p,l,a)*value(p,k,a)<0)
{
l=(l+k)/2;j=l;
}
}
printf("the root of the equation is %f\n",l);
}
I tried inserting print statements in the main function, and found that the value function is giving absurd results for simple polynomials, but the roots are correct for some polynomials but wrong for many. Why would the roots be correct for some if the algorithm was wrong?
There are so many problems in your code:
In main method,
printf("%d\n",value(p,-2,a));
Compiler should give you warning:
warning: format '%d' expects argument of type 'int', but argument 2 has type 'double'
Use %f instead of %d as value() returns float.
You are not allocating enough space and you are casting the return value of malloc. Casting the return value of malloc should be avoided since malloc returns a void * (which means that it needs no cast) and casting the return value can conceal errors. You can read more about this issue here.
p = (float *) malloc(a*sizeof(float));
to
p=malloc((a+1) * sizeof *p);
You are comparing floating ponit number here:
if(value(p,i,a)==0&&value(p,i+1,a)==0.00)
Don't do this, read What Every Computer Scientist Should Know About Floating-Point Arithmetic for the reason. You can use one of this (e.g nearlyEqual()) functions for your purpose.
In method bisect():
j=j;k=l;l=(j+k)/2; // j = j, kidding?
The biggest conceptual or mathematical error (apart from the programming errors explained in the other answer) is that you use integers for the arguments in the value function. It is rarely the case that random polynomials have integer roots. Rename n to x for intuitive readability and set the type of x to float.
Check again your assignment, if the prototype is really value(p,n,a), then maybe the intention is that n is the degree and a the evalution point, thus the signature should be (*float,int,float).
Using this signature, you should really use the Horner scheme to evaluate densely coded polynomials
float value(float *p, int deg, float a) {
int i;
float val = p[deg];
for(i=deg; i-- > 0; ) val = val*a+p[i];
return val;
}
and use descriptive names for variables in the bisection method (instead of j,k,l usually associated to integers) to avoid mixing them up
float left=a, right = a+1, mid =(left+right)/2;
etc.

-1.#IND00 output for certain input values

I'm trying to write a code that will take x as input and give cos(x) as output, using maclaurin's series.I'm using a while loop until the difference of two consecutive results is less then 0.001. I'm using double type to accomodate larger values.
the code works when x is in range [-2,2], but if x is greater or less than this range the ouput is -1.#IND00. Why is it happening? is the output value out of range ? how can i fix this ??
my code is :
#include <stdio.h>
double abs(double a);
double power(double p, int q);
int fact(int a);
int main()
{
int i=1,j=2*i;
double x,s=1.0,p,l=0.001;
printf("Enter x: ");
scanf("%lf", &x);
p = s+ power(-1,i) * power(x,j) / fact(j);
while (abs(p-s)>l){
i++; j=2*i;
s=p;
p = s+ power(-1,i) * power(x,j) / fact(j);
}
printf("cos(%f) = %f", x,p);
return 0;
}
double abs(double a)
{
if (a>=0) return a;
else return (-a);
}
double power(double p, int q)
{
int i;
double a=1.0;
for (i=0; i<q; i++){
a=a*p;
}
return a;
}
int fact(int a)
{
int i,p=1;
if (a==0 || a==1) return 1;
else
while (a!=1){
p=p*a;
a--;
}
return p;
}
update your scanf function to
scanf("%lf", &x);
Also you need to check pow and fact, these functions could overflow. Especially, fact which only use int.
As a larger |x| is use, more terms are needed and fact() overflows and strange results follow. Use double.
// int fact(int a)
double myfact(double p, int q) {
int i;
double a = 1.0;
for (i=0; i<q; i++){
a=a*p;
}
return a;
}
Eventually with values somewhere larger |x| > 30, other limitations kick in using this method. The limitation is due to precision and not range. For large values a significantly different algorithm should be used.
Potential conflict between int abs(int j) in <stdlib.h>. The prototyped may be found via stdio.h and conflicts with OP double abs(double a). In any case, abs() is a standard library function and OP should avoid that function name. Also recommend renaming power().
// double abs(double a)
double myabs(double a)

Resources