I have to create a function that does successive substitution.
For example,
I have a function F(X,Y) = (sqrt ((X-Y)/(X-1))) / tanh(sqrt((X-Y)/(X-1))) .
(X is a constant)
I have to enter and check values of Y (smaller than X) like this:
Value 1: SET Y=0
E1 = F(X,Y)
then E2 = F(X,E1)
THEN E3 = F(X,E2)
.
.
.
.
E(n) = F(X,E(n-1))
and stop when (fabs(E(n)-E(n-1))<= 0.001);
I tried to use a do-while loop but I didn't manage to make it work.
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#define F(Ei,E) (sqrt (M*(Ei-E)/(Ei-1))) / tanh(sqrt(M*(Ei-E)/(Ei-1)))
#define Ei 1 + ((Db*CBoo)/(b*Da*CAi))
#define M (Da*k2*CBoo)/(kl*kl)
int main(){
double k2,Da,Db,b,h,CAi,CBoo,kl,E,i;
double E1 ,E2 ;
kl =1;
k2 = 3;
Da = 0.4;
Db = 0.3;
CAi = 3;
CBoo = 5;
b = 2;
E1=0;
E2=0;
E=0;
i=0;
do
{
E1 = E2;
E2 = F(Ei,E1);
printf("dd");
}while(fabs(E2-E1)<= 0.0001);
printf("\nanswer is %lf",E1);
system("PAUSE");
}
The loop only does 1 round and the answer is always 0
Any ideas how to do this??
Thank you!
You should use while(fabs(E2-E1) > 0.001) instead of while(fabs(E2-E1) <= 0.001)
First, you need to change while(fabs(E2-E1) <= 0.001) to while(fabs(E2-E1) > 0.001) as was pointed out by MicroAlex.
The reason it still doesn't work is that the term sqrt(X-Y) restricts the domain of your function F(X,Y) to the interval [0, X] unless you are prepared to deal with complex numbers (which you are not, obviously). With your starting point Y0=0, you immediately get a new Y1=F(X,Y0) outside the domain of your function. This is why it breaks after one iteration. As a matter of fact you're lucky it breaks since the behaviour of the loop condition is essentially undefined.
So the real problem lies in your numerical approach. The problem doesn't seem to yield to fixed-point iteration. What are you trying to do, actually?
edit
The reason why fixed-point iteration doesn't work is probably that the function is not Lipschitz-continuous (due to the sqrt term, but I haven't checked). You might be better off with trying a different root solver, like bisection with a start interval [0, X]
Related
Problem statement: I am working on a code that calculates big numbers. Hence, I am easily get beyond the maximum length of "long double". Here is an example below, where part of the code is given that generates big numbers:
int n;
long double summ;
a[1]=1;
b[1]=1;
c[1] = 1; //a, b, c are 1D variables of long double types
summ=1+c[1];
for(n=2; n <=1760; n++){
a[n]=n*n;
b[n]=n;
c[n] = c[n-1]*a[n-1]/b[n]; //Let us assume we have this kind of operation
summ= summ+c[n]; //So basically, summ = 1+c[1]+c[2]+c[3]+...+c[1760]
}
The intermediates values of summ and c[n] are then used to evaluate the ratio c[n]/summ for every integer n. Then, just after the above loop, I do:
for(n=1;n<=1760;n++){
c2[n]=c[n]/summ; //summ is thus here equals to 1+c[1]+c[2]+c[3]+...+c[1760]
}
Output: If we print n, c[n] and summ, we obtain inf after n=1755 because we exceed the length of long double:
n c[n] summ
1752 2.097121e+4917 2.098320e+4917
1753 3.672061e+4920 3.674159e+4920
1754 6.433452e+4923 6.437126e+4923
1755 1.127785e+4927 1.128428e+4927
1756 inf inf
1757 inf inf
1758 inf inf
1759 inf inf
1760 inf inf
Of course, if there is an overflow for c[n] and summ, I cannot evaluate the quantity of interest, which is c2[n].
Questions: Does someone see any solution for this ? How do I need to change the code so that to have finite numerical values (for arbitrary n) ?
I will indeed most likely need to go to very big numbers (n can be much larger than 1760).
Proposition: I know that GNU Multiple Precision Arithmetic (GMP) might be useful but honestly found too many difficulties trying to use this (outside the field), so if there an easier way to solve this, I would be glad to read it. Otherwise, I will be forever grateful if someone could apply GMP or any other method to solve the above-mentioned problem.
NOTE: This does not exactly what OP wants. I'll leave this answer here in case someone has a similar problem.
As long as your final result and all initial values are not out of range, you can very often re-arrange your terms to avoid any overflow. In your case if you actually just want to know c2[n] = c[n]/sum[n] you can re-write this as follows:
c2[n] = c[n]/sum[n]
= c[n]/(sum[n-1] + c[n]) // def. of sum[n]
= 1.0/(sum[n-1]/c[n] + 1.0)
= 1.0/(sum[n-1]/(c[n-1] * a[n-1] / b[n]) + 1.0) // def. of c[n]
= 1.0/(sum[n-1]/c[n-1] * b[n] / a[n-1] + 1.0)
= a[n-1]/(1/c2[n-1] * b[n] + a[n-1]) // def. of c2[n-1]
= (a[n-1]*c2[n-1]) / (b[n] + a[n-1]*c2[n-1])
Now in the final expression neither argument grows out of range, and in fact c2 slowly converges towards 1. If the values in your question are the actual values of a[n] and b[n] you may even find a closed form expression for c2[n] (I did not check it).
To check that the re-arrangement works, you can compare it with your original formula (godbolt-link, only printing the last values): https://godbolt.org/z/oW8KsdKK6
Btw: Unless you later need all values of c2 again, there is actually no need to store any intermediate value inside an array.
I ain't no mathematician. This is what I wrote with the results below. Looks to me that the exponent, at least, is keeping up with your long double results using my feeble only double only...
#include <stdio.h>
#include <math.h>
int main() {
int n;
double la[1800], lb[1800], lc[1800];
for( n = 2; n <= 1760; n++ ) {
lb[n] = log10(n);
la[n] = lb[n] + lb[n];
lc[n] = lc[n-1] + la[n-1] - lb[n];
printf( "%4d: %.16lf\n", n, lc[n] );
}
return 0;
}
/* omitted for brevity */
1750: 4910.8357954121602000
1751: 4914.0785853634488000
1752: 4917.3216235537839000
1753: 4920.5649098413542000
1754: 4923.8084440845114000
1755: 4927.0522261417700000 <<=== Take note, please.
1756: 4930.2962558718036000
1757: 4933.5405331334487000
1758: 4936.7850577857016000
1759: 4940.0298296877190000
1760: 4943.2748486988194000
EDIT (Butterfly edition)
Below is a pretty simple iterative function involving one single and one double precision float values. The purpose is to demonstrate that iterative calculations are exceedingly sensitive to initial conditions. While it seems obvious that the extra bits of the double will "hold-on", remaining closer to the results one would get with infinite precision, the compounding discrepancy between these two versions demonstrate that "demons lurking in small places" will likely remain hidden in the fantastically tiny gaps between finite representations of what is infinite.
Just a bit of fun for a rainy day.
int main() {
float fpi = 3.1415926535897932384626433832;
double dpi = 3.1415926535897932384626433832;
double thresh = 10e-8;
for( int i = 0; i < 1000; i++ ) {
fpi = fpi * 1.03f;
dpi = dpi * 1.03f;
double diff = fabs( dpi - fpi );
if( diff > thresh) {
printf( "%3d: %25.16lf\n", i, diff );
thresh *= 10.0;
}
}
return 0;
}
8: 0.0000001229991486
35: 0.0000010704333473
90: 0.0000100210180918
192: 0.0001092634900033
229: 0.0010121794607585
312: 0.0100316228017618
367: 0.1002719746902585
453: 1.0056506423279643
520: 10.2658853083848950
609: 103.8011477291584000
667: 1073.9984381198883000
736: 10288.9632129669190000
807: 101081.5514678955100000
886: 1001512.2135009766000000
966: 10473883.3271484370000000
This is my homework:
I haven't tried to write the part of Natural Logarithm because I can't solve the part of Exponential.
This is the the approximations of Exponential in C using Taylor Series expansion I wrote.
However, it returns inf. What did I do wrong?
#include <stdio.h>
// Returns approximate value of e^x
// using sum of first n terms of Taylor Series
float exponential(int n, float x)
{
float sum = 1.0f; // initialize sum of series
for (int a = n; a >= 0; ++a ) {
while (x * sum / a < 0.00001) {
break;
}
sum = 1 + x * sum / a;
return sum;
}
}
int main()
{
int n = 0;
float x = 1.0f;
printf("e^x = %.5f", exponential(n, x));
return 0;
}
With How do I ask and answer homework questions? in mind, I will give you a few things to have a careful look at.
From comment by Spektre:
from a quick look you are dividing by zero in while (x * sum / a < 0.00001) during first iteration of for loop as a=n and you called the function with n=0 ... also your code does not match the expansion for e^x at all
Have a look at the for loop:
for (int a = n; a >= 0; ++a )
What is the first value of a? The second? The third?
Keep in mind that the values are determined by ++a.
When will that loop end? It is determined by a >= 0. When is that false?
What is this loop doing?
while (x * sum / a < 0.00001) {
break;
}
I suspect that you programmed "English to C", as "do the outer loop while ...", which is practically from the assignment.
But the loop does something else. Apart from risking the division by 0 mentioned above, if the condition is true it will stay true and cause an endless loop, which then however is immediatly canceled in the first iteration.
The head of your function float exponential(int n, float x) expects n as a parameter. In main you init it with 0. I suspect you are unclear about where that value n is supposed to come from. In fact it is unknown. It is more a result of the calculation than an input.
You are supposed to add up until something happens.
You do not actually ever need the value of n. This means that your for loop is meaningless. The inner loop (though currently pointless) is much closer to your goal.
I will leave it at this for now. Try to use this input.
Feel free to edit the code in your question with improvements.
(Normally that is not appreciated, but in case of homework dialog questions I am fine with it.)
Your current implementation attempt is quite a bit off. Therefore I will describe how you should approach calculating such a series as given in your quesiton.
Let's look at your first formula:
You need to sum up terms e(n) = x^n / n!
To check with your series: 1 == x^0 / 0! - x == x^1 / 1! - ...
To calculate these terms, you need a simple rule how to get from e(n) to e(n+1). Looking at the formula above we see that you can use this rule:
e(n+1) = e(n) * x / (n+1)
Then you need to create a loop around that and sum up all the bits & pieces.
You are clearly not supposed to calculate x^n/n! from scratch in each iteration.
Your condition to stop the loop is when you reach the limit of 1e-5. The limit is for the new e(n+1), not for the sum.
For the other formulas you can use the same approach to find a rule how to calculate the single terms.
You might need to multiply the value by -1 in each step or do something like *x*n/(n+1) instead of *x/(n+1) etc.
Maybe you need to add some check if the formula is supposed to converge. Then maybe print some error message. This part is not clear in your question.
As this is homework, I only point into the direction and leave the implementation work to you.
If you have problems with implementation, I suggest to create a new question.
#include <stdio.h>
int main() {
float power;
printf("Enter the power of e\n");
scanf("%f", &power);
float ans = 1;
float temp = 1;
int i = 1;
while ((temp * power) / i >= 0.00001) {
temp = (temp * power) / i;
ans = ans + temp;
i++;
}
printf("%.5f", ans);
return 0;
}
I think I solved the problem
But the part about Natural Log is not solved, I will try.
I am having a problem finding a good approximation to the integral between 0 and infinity of sin(x)/sqrt(x) in C programming. I am trying to use the trapezium rule. In my code I also want the user to input a precision value such as 0.001 where the output value will be accurate to that amount of decimal places. What is going wrong with this code?
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
int main(void)
{
int i, N; // integers to interate on in loops //
double h, x, y, precision, lowerLim = 0.0001, upperLim = 10000, f0, fN;
printf("accuracy:");
scanf("%lf", &precision);
N = 10;
double areastored, newarea;
do {
newarea = 0.0;
areastored = newarea; // areastored is the area that I want to compare to the new area calulated as the N (number of partitions) to check the precision of the new value to see if it a better approximation //
h = (upperLim - lowerLim)/(N-1);
fN = sin(upperLim)/sqrt(upperLim);
f0 = sin(lowerLim)/sqrt(lowerLim); // end points evaluated in function //
newarea = newarea + 0.5*h*(f0 + fN);
for (int i = 1; i < N; i++) {
x = lowerLim + h*i;
y = sin(x)/sqrt(x);
newarea = newarea + y*h; // this loop adds all the middle trapezia areas //
}
printf("at N %d integral %f\n", N, newarea);
N = N*5; // iterate the N so next round of the loop it will approximate an area with more and smaller trapezia //
} while ( fabs ( newarea - areastored ) > precision ); // if this is false then should have an area to the desired precision //
printf("The integral evaluates to: %lf\n", newarea);
}
The problem is that if I input an accuracy 0.01, the area is calculated for N = 10, 50, 250 but isn't able to continue and the last area = 8.53 which is off the value of 1.253... I'm expecting
EDIT: I have now made suggested changes to the above code as can be seen now thanks to the comments from several users below. Thank you very much for your help! I have now got an issue with my output, see the attached image of my terminal. It should have stopped by the 9th iteration of N for this input and so the printed vale is rather baffling. Why has this occured? Thanks again for any help in advance!
There are at least two errors in your code
// ...
newarea = 0.0; // <-- It's initialized here
do {
// ...
h = (upperLim - lowerLim)/N-1; // <-- This doesn't do what you think
// ...
// It's updated, but never reset
newarea = newarea + 0.5*h*(f0 + fN);
// ...
} while ( ... );
You should move the newarea = 0.0; line inside the loop and modify the formula that calculates h.
Also note that you have a fixed upper limit (1000), while for this type of integrals you should consider an increasing upper limit and maybe a non uniform grid spacing.
If you debug your program you will see that
h = (upperLim - lowerLim)/N-1;
leads to a negative value of h for N=1250.
This leads to an endless loop
for (x=lowerLim+h; x < upperLim; x+=h) {
because when x gets to a large enough absolute value it will no longer change when you add h.
You probably mean
h = (upperLim - lowerLim) / (N-1);
I am more than likely doing this whole code wrong, but when attempting the find the range of:
4.0*rand()/RAND_MAX + 1
I end up only getting the number 0 as a result, and I'm pretty sure there's more to it than that.
Code (in C):
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main()
{
srand(time(NULL));
int r;
4.0*rand()/RAND_MAX+1;
printf("%i",r);
return 0;
}
double rr = 4.0*rand()/RAND_MAX+1; You need to use a double and more importantly assign the result (rr) to some variable.
printf("%lf",rr); For printing the result.
As far as it is seen there is no range calculation here.
You are simply printing an uninitialized variable(r). (which seems to comtain the value 0 when you printed).
Two things:
First, you are never assigning r any value. You need to change 4.0*rand()/RAND_MAX+1; to r = 4.0*rand()/RAND_MAX+1;
Second, the compiler will likely complain about that since you're degrading from double to int. You should change 4.0 to 4.
The final code should look roughly like r = 4*rand()/RAND_MAX+1;. Then, the range will be {1, 2, 3, 4, 5} (note: depends on whether rand can return RAND_MAX or only less than RAND_MAX. If only less, then exclude 5.) If you wanted {0, 1, 2, 3} you needed to enclose RAND_MAX+1 in parentheses.
Note: as pointed out in the comments, there may be some concerns with the above. You can use something like this to get exactly the same distribution:
r = rand()
if (r == RAND_MAX) return 5;
else return r % 4 + 1;
If you don't ever want to return 5, you can use rejection sampling:
r = RAND_MAX;
while (r == RAND_MAX) r = rand();
return r % 4 + 1;
I need to perform the Taylor Series for arctangent 50 times. Meaning 50 numbers between the domain of the arctan Taylor Series which is [-1,1]. I've tested it out with manual user input and it works fine, but the for loop for the 50 different inputs which I increment in the code by 0.01 and their corresponding results has been unsuccessful. I've tried everything I could think of so far, I'm out of ideas. Any help would be appreciated. Is there an issue with my brackets surrounding the Taylor Series that's conflicting with the other for loop? I've suspected it was the brackets but nothings worked when I attempted to fix it.
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
main (void) {
double n;
double x;
double tSeries=0.0;
double t2;
double t1;
for(n=0;n<=50;++n) {
for(x=-1;x<=1;x=x+0.01) {
t1=(pow(x,2*n+1))*pow(-1,n);
t2=t1/(2*n+1);
tSeries+=t2;
printf("arctan(%lf)=%lf\n",x,tSeries);
}
}
return 0;
}
In the code you've posted the inner loop is over the variable x, and the outer loop is over the power n.
I think you want to sum over values of n for each value of x, so the loop over n should be the inner loop.
I think you also need to zero your sum, tSeries for each value of x.
Finally, I expect you want to print the answer after calculating the sum, so printf should be outside the n loop.
There are a few tricks to the evaluation of power series. I like Numerical Recipes for this sort of thing. Try chapter 5 on the evaluation of functions. (Numerical Recipes in C, Press et al., 2nd Ed., 1992, CUP.)
One thing to note right away is that with the upper limit of the power series fixed, you are evaluating a polynomial. Section 5.3 of my copy of NR recommends strongly against using a sum of calls to pow(). They are quite firm about it!
Let me know if you want me to post correct code.
You got the loops mixed, the inner one goes out and vice versa.
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
int main(void)
{
double n;
double x;
double tSeries = 0.0;
double t2;
double t1;
for (x = -1; x <= 1; x += 0.01) {
for (n = 0; n <= 50; n++) {
t1 = (pow(x, 2 * n + 1)) * pow(-1, n);
t2 = t1 / (2 * n + 1);
tSeries += t2;
}
printf("arctan(%lf)=%lf (%lf)\n", x, tSeries, atan(x));
tSeries = 0.0;
}
return 0;
}