Need help programming with Mclauren series and Taylor series? - c

Ok so here's what i have so far:
#include <stdio.h>
#include <math.h>
//#define PI 3.14159
int factorial(int n){
if(n <= 1)
return(1);
else
return(n * factorial(n-1));
}
void McLaurin(float pi){
int factorial(int);
float x = 42*pi/180;
int i, val=0, sign;
for(i=1, sign=-1; i<11; i+=2){
sign *= -1; // alternate sign of cos(0) which is 1
val += (sign*(pow(x, i)) / factorial(i));
}
printf("\nMcLaurin of 42 = %d\n", val);
}
void Taylor(float pi){
int factorial(int);
float x;
int i;
float val=0.00, sign;
float a = pi/3;
printf("Enter x in degrees:\n");
scanf("%f", &x);
x=x*pi/180.0;
printf("%f",x);
for(i=0, sign=-1.0; i<2; i++){
if(i%2==1)
sign *= -1.0; // alternate sign of cos(0) which is 1
printf("%f",sign);
if(i%2==1)
val += (sign*sin(a)*(pow(x-a, i)) / factorial(i));
else
val += (sign*cos(a)*(pow(x-a, i)) / factorial(i));
printf("%d",factorial(i));
}
printf("\nTaylor of sin(%g degrees) = %d\n", (x*180.0)/pi, val);
}
main(){
float pi=3.14159;
void McLaurin(float);
void Taylor(float);
McLaurin(pi);
Taylor(pi);
}
and here's the output:
McLaurin of 42 = 0
Enter x in degrees:
42
0.733038-1.00000011.0000001
Taylor of sin(42 degrees) = -1073741824
I suspect the reason for these outrageous numbers goes with the fact that I mixed up my floats and ints? But i just cant figure it out...!! Maybe its a math thing, but its never been a strength of mine let alone program with calculus. Also the Mclaurin fails, how does it equal zero? WTF! Please help correct my noobish code. I am still a beginner...
----Update----
#include <stdio.h>
#include <math.h>
//#define PI 3.14159
int factorial(int n){
if(n <= 1)
return(1);
else
return(n * factorial(n-1));
}
void McLaurin(float pi){
int factorial(int);
float x = 42*pi/180, val=0;
int i, sign;
for(i=1, sign=-1; i<11; i+=2){
sign *= -1; // alternate sign of cos(0) which is 1
val += (sign*(pow(x, i)) / factorial(i));
}
printf("\nMcLaurin of of sin(%f degrees) = %f\n", (x*180.0)/pi, val);
}
void Taylor(float pi){
int factorial(int);
float x;
int i;
float val=0, sign;
float a = pi/3;
printf("Enter x in degrees:\n");
scanf("%f", &x);
x=x*pi/180.0;
printf("%f",x);
for(i=0, sign=-1.0; i<2; i++){
if(i%2==0)
sign *= -1; // alternate sign of cos(0) which is 1
printf("%f",sign);
if(i%2==0)
val += (sign*sin(a)*(pow(x-a, i)) / factorial(i));
else
val += (sign*cos(a)*(pow(x-a, i)) / factorial(i));
printf("%d",factorial(i));
}
printf("\nTaylor of sin(%f degrees) = %f\n", (x*180.0)/pi, val);
}
main(){
float pi=3.14159;
void McLaurin(float);
void Taylor(float);
McLaurin(pi);
Taylor(pi);
}
Gives me weird error.
/usr/lib/gcc/i686-pc-cygwin/3.4.4/../../../../i686-pc-cygwin/bin/ld: cannot open output file a.exe: Device or resource busy
collect2: ld returned 1 exit status
Can anyone explain what's wrong now?

Some potential sources of error:
your value of pi doesn't have sufficient digits for even float accuracy;
in your function Maclaurin you have val as an integer, on which you perform division;
in Taylor you only use 2 terms in the series
I think ?

a few things jump out:
in McLauren you define val (your calculated value) as an int. try defining it as a float
in Taylor you are only flipping your sign every other time so it goes -1, 1, -1, -1, 1, 1 .... and so on
i think your formula for the Taylor series is incorrect, after refreshing myself on wikipedia, you shouldn't be calling sin or cos (because that's what you are trying to calculate)
good luck!

This one that have already been mentioned is definitely troublesome:
val should be a float in McLaurin()
In addition, you need to use %f or %g instead of %d when using printf() to print out your vals. That's ultimately why you're getting such crazy numbers: floats being interpreted as ints.
Also, in Taylor(), you need to change your two if statements to be
if(i%2==0)
because you are Taylor expanding sin, not cos.
Doing these things yields 0.669130 and 0.708945 for the MacLaurin and Taylor series answers, respectively, using the same number of terms as in your code. If I add two more terms to the Taylor series answer (use i<4 instead of i<2), I get 0.668793. The true answer (using the same pi as you used) is 0.669130 which the Taylor series answer gets to with 3 more additional terms added in.

Related

Sinus function using Taylor expansion

The teacher asks to remove the pi subtraction cycle in the main function. I don’t know how to write the program so that the correct results will come out for any values.
#include <stdio.h>
#include <math.h>
double sinus(double x);
int main(void) {
double a, x;
scanf("%le", & x);
a = x;
while (fabs(x) > 2 * (M_PI)) {
x = fabs(x) - 2 * (M_PI);
}
if (a > 0)
a = sinus(x);
else a = (-1) * sinus(x);
printf("%le", (double) a);
return 0;
}
double sinus(double x) {
double sum = 0, h, eps = 1.e-16;
int i = 2;
h = x;
do {
sum += h;
h *= -((x * x) / (i * (i + 1)));
i += 2;
}
while (fabs(h) > eps);
return sum;
return 0;
}
#include <stdio.h>
#include <math.h>
double sinus(double x);
int main(void)
{
double a,x;
scanf("%le",&x);
a=x;
x=fmod(fabs(x),2*(M_PI));
if(a>0)
a=sinus(x);
else a=(-1)*sinus(x);
printf("%le",(double)a);
return 0;}
double sinus(double x)
{
double sum=0, h, eps=1.e-16; int i=2;
h=x;
do{
sum+=h;
h*=-((x*x)/(i*(i+1)));
i+=2;}
while( fabs(h)>eps );
return sum;
return 0;
}
… how to write the program so that the correct results will come out for any values.
OP's loop is slow with large x and an infinfite loop with very large x:
while (fabs(x) > 2 * (M_PI)) {
x = fabs(x) - 2 * (M_PI);
}
A simple, though not high quality solution, is to use fmod() in the function itself. #Damien:
#ifndef M_PI
#define M_PI 3.1415926535897932384626433832795
#endif
double sinus(double x) {
x = fmod(x, 2*M_PI); // Reduce to [-2*M_PI ... 2*M_PI]
...
Although function fmod() is not expected to inject any error, the problem is that M_PI (a rational number) is an approximation of π, (an irrational number). Using that value approximation injects error especially x near multiplies of π. This is likely OK for modest quality code.
Good range reduction is a problem as challenging as the trigonometric functions themselves.
See K.C. Ng's "ARGUMENT REDUCTION FOR HUGE ARGUMENTS: Good to the Last Bit" .
OP's sinus() should use additional range reduction and trigonometric properties to get x in range [-M_PI/4 ... M_PI/4] (example) before attempting the power series solution. Otherwise, convergence is slow and errors accumulate.

Logarithm calculator

I'm trying to make a logarithm calculator and got stuck—it doesn't print out a value. The problem may be at lines 15 or 24 or both. How can I make it print the value (all written in C).
Here's the full code:
#include <stdio.h>
#include <stdlib.h>
// Finds base 10 logarithms
int main()
{
float result;
float base = 10.0;
float multiplier = 1.0;
// float counter1 = 0.0;
// float counter2 = 0;
printf("Input result: ");
scanf("%l", result);
// Solves for all results above the base
if(result > base) {
while(result > multiplier) {
multiplier = multiplier * multiplier; // the multiplier has to check non-whole numbers
multiplier += 0.001;
} // division
}
printf("Your exponent is: %l \n", &multiplier);
printf("Hello mathematics!");
return 0;
}
All help appreciated,
Xebiq
you should delete & in printf,and add & in scanf.
printf("Your exponent is: %f \n", multiplier);
scanf("%f", &result);
and use %f in them.
and with base 10 I suggest this function to calculate log:
unsigned int Log2n(unsigned int n)
{
return (n > 1) ? 1 + Log2n(n / 10) : 0;
}
also you should know about Floating-point numbers here:
multiplier += 0.001;
probably exactly 0.001 won't be added to multiplier when I debugged this 0.00100005 was being add to multiplier in my compiler.(which will affect multiplying)
In printf remove '&' and in scanf add '&' before variable.

What should I change so that my arctan(x) approximation can display x=1 and x=-1 properly?

One of my C assignments was it to write an approximation of arctan(x) in the language C. The equation which I should base it on is
arctan(x)=\sum {k=0}^{\infty }(-1)^{k} \tfrac{x^{2k+1}}{2k+1}
In addition x is only defined as -1<=x<=1.
Here is my code.
#include <stdio.h>
#include <math.h>
double main(void) {
double x=1;
double k;
double sum;
double sum_old;
int count;
double pw(double y, double n) {
double i;
double number = 1;
for (i = 0; i < n; i++) {
number *= y;
}
return(number);
}
double fc (double y) {
double i;
double number = 1;
for (i = 1; i <= y; i++){
number *= i;
}
return(number);
}
if(x >= (-1) && x <= 1) {
for(k=0; sum!=sum_old; k++) {
sum_old = sum;
sum += pw((-1), k) * pw(x, (2*k) + 1)/((2*k) + 1);
count++;
printf("%d || %.17lf\n", count, sum);
}
printf("My result is: %.17lf\n",sum);
printf("atan(%f) is: %.17f\n", x, atan(x));
printf("My result minus atan(x) = %.17lf\n", sum - atan(x));
} else {
printf("x is not defined. Please choose an x in the intervall [-1, 1]\n");
}
return 0;
}
It seemingly works fine with every value, except value 1 and -1. If x=1, then the output ends with:
...
7207 || 0.78543285189457468
7208 || 0.78536
Whereas the output should look more like this. In this case x=0.5.
25 || 0.46364760900080587
26 || 0.46364760900080587
My result is: 0.46364760900080587
atan(0.500000) is: 0.46364760900080609
My result minus atan(x) atan(x) = -0.00000000000000022
How can I improve my code so that it can run with x=1 and x=-1.
Thanks in advance.
PS: I use my own created pw() function instead of pow(), because I wanted to bybass the restriction of not using pow() as we didn't had that in our lectures yet.
PPS: I'd appreciate any advice as to how to improve my code.
In each iteration, you add (-1)k • x2k+1 / (2k+1), and you stop when there is no change to the sum.
If this were calculated with ideal arithmetic (exact, infinitely precise arithmetic), it would never stop for non-zero x, since you are always changing the sum. When calculating with fixed-precision arithmetic, it stops when the term is so small it does not change the sum because of the limited precision.
When |x| is less than one by any significant amount, this comes quickly because x2k+1 gets smaller. When |x| is one, the term becomes just 1 / (2k+1), which gets smaller very slowly. Not until k is around 253 would the sum stop changing.
You might consider changing your stopping condition to be when sum has not changed from sum_old very much rather than when it has not changed at all.
if(x >= (-1) && x <= 1) {
for(k=0; sum!=sum_old; k++) {
sum_old = sum;
sum += pw((-1), k) * pw(x, (2*k) + 1)/((2*k) + 1);
count++;
printf("%d || %.17lf\n", count, sum);
}
Comparing doubles can be tricky. The conventional way to compare doubles is to test within epsilon. There should be an epsilon value defined somewhere, but for your purposes how many digits are enough to approximate? If you only need like 3 or 4 digits you can instead have
#define EPSILON 0.0001 //make this however precise you need to approximate.
if(x >= (-1) && x <= 1) {
for(k=0; fabs(sum - sum_old) > EPSILON; k++) {
sum_old = sum;
sum += pw((-1), k) * pw(x, (2*k) + 1)/((2*k) + 1);
count++;
printf("%d || %.17lf\n", count, sum);
}
If the issue is that -1,1 iterate too many times either reduce the precision or increase the step per iteration. I am not sure that is what you're asking though, please clarify.
I think the cause of this is for a mathematical reason rather than a programming one.
Away from the little mistakes and adjustments that you should do to your code, putting x = 1 in the infinite series of arctan, is a boundary condition:
In this series, we add a negative value to a positive value then a negative value. This means the sum will be increasing, decreasing, increasing, ... and this will make some difference each iteration. This difference will be smaller until the preciseness of double won't catch it, so the program will stop and give us the value.
But in the sum equation. When we set z = 1 and n goes from 0 to ∞, this will make this term (-1^n) equal to 1 in one time and -1 in the next iteration. Also,
the value of the z-term will be one and the denominator value when n approaches infinity will = ∞ .
So the sum several iterations will be like +1/∞ -1/∞ +1/∞ -1/∞ ... (where ∞ here represents a big number). That way the series will not reach a specific number. This is because z = 1 is a boundary in this equation. And that is causing infinite iterations in your solution without reaching a number.
If you need to calculate arctan(1) I think you should use this formula:
All formulas are from this Wikipedia article.
Here is some modifications that make your code more compact and has less errors:
#include <stdio.h>
#include <math.h>
#define x 0.5 //here x is much easier to change
double pw(double, double); //declaration of the function should be done
int main() { //the default return type of main is int.
double k;
double sum = 0 ; //you should initiate your variables.
double sum_old = 1 ; //=1 only to pass the for condition first time.
//you don't need to define counter here
if(x < -1 || x > 1){
printf("x is not defined. Please choose an x in the interval [-1, 1]\n");
return 0;
}
for(k=0; sum!=sum_old; k++) {
sum_old = sum;
sum += pw((-1), k) * pw(x, (2*k) + 1)/((2*k) + 1);
printf("%.0f || %.17lf\n", k, sum);
}
printf("My result is: %.17lf\n",sum);
printf("atan(%f) is: %.17f\n", x, atan(x));
printf("My result minus atan(x) = %.17lf\n", sum - atan(x));
return 0;
}
double pw(double y, double n) { //functions should be declared out of the main function
double i;
double number = 1;
for (i = 0; i < n; i++) {
number *= y;
}
return(number);
}
double fc (double y) {
double i;
double number = 1;
for (i = 1; i <= y; i++){
number *= i;
}
return(number);
}

How would you use the while statement to find the square root using the while loop

I have to write a program that will find a square root using the while loop. I was given this new_guess = (old_guess + (n / old_guess)) / 2.0; but I dont fully understand what to do with it, this is what I have:
int main(void)
{
double n, x, new_guess, old_guess, value;
printf("Enter a number:");
scanf("%lf", &n);
x = 1.00000;
while (new_guess >= n) {
new_guess = (old_guess + (n / old_guess)) / 2.0;
printf("%10.5lf\n", fabs(new_guess));
}
return 0;
}
x is the initial guess. Im really lost on how to do it. This is C also. I know its really wrong but I really dont understand how to make it start because when I enter a number it just stop right away.
Your program has undefined behavior because both new_guess and old_guess are uninitialized when you enter the loop.
The condition is also incorrect: you should stop when new_guess == old_guess or after a reasonable maximum number of iterations.
Here is a modified version:
#include <math.h>
#include <stdio.h>
int main(void) {
double n, x;
int i;
printf("Enter numbers:");
while (scanf("%lf", &n) == 1 && n >= 0.0) {
x = 1.0;
/* Using a while loop as per the assignment...
* a for loop would be much less error prone.
*/
i = 0;
while (i < 1024) {
double new_guess = (x + (n / x)) / 2.0;
if (new_guess == x)
break;
x = new_guess;
i++;
}
printf("%g: %.17g, %d iterations, diff=%.17g\n",
n, x, i, sqrt(n) - x);
}
return 0;
}
Given the start value, the number of iterations grows with the size of n, exceeding 500 for very large numbers, but usually less than 10 for small numbers. Note also that this algorithm fails for n = 0.0.
Here is a slightly more elaborate method, using the floating point break up and combine functions double frexp(double value, int *exp); and double ldexp(double x, int exp);. These functions do not perform any calculation but allow for a much better starting point, achieving completion in 4 or 5 iterations for most values:
#include <math.h>
#include <stdio.h>
int main(void) {
double n, x;
int i, exp;
printf("Enter a number:");
while (scanf("%lf", &n) == 1 && n >= 0.0) {
if (n == 0) {
x = 0.0;
i = 0;
} else {
frexp(n, &exp);
x = ldexp(1.0, exp / 2);
for (i = 0; i < 1024; i++) {
double new_guess = (x + (n / x)) / 2.0;
if (new_guess == x)
break;
x = new_guess;
}
}
printf("%g: %.17g, %d iterations, diff=%.17g\n",
n, x, i, sqrt(n) - x);
}
return 0;
}

Why isn't my code accurate when I change the numberOfTerms?

#include <stdio.h>
double pi = 3.141592653589;
int numberOfTerms = 5;
int factorial(int n)
{
if(n > 1)
return n * factorial(n - 1);
else
return 1;
}
double DegreesToRadian( double degrees )
{
return degrees * pi / 180;
}
void cosine(double cos){
int x = 0;
double ans = 1;
int exponent = 2;
int isPlus = 0;
for(x; x < numberOfTerms - 1; x++){
if(isPlus == 0){
ans -= (pow(cos, exponent))/factorial(exponent);
exponent += 2;
isPlus = 1;
}else{
ans += (pow(cos, exponent))/factorial(exponent);
exponent += 2;
isPlus = 0;
}
}
printf ("%.12f \t", ans);
}
void sine(double sin){
int x = 0;
double ans = sin;
int exponent = 3;
int isPlus = 0;
for(x; x < numberOfTerms - 1; x++){
if(isPlus == 0){
ans -= (pow(sin, exponent))/factorial(exponent);
exponent += 2;
isPlus = 1;
}else{
ans += (pow(sin, exponent))/factorial(exponent);
exponent += 2;
isPlus = 0;
}
}
printf ("%.12f \n", ans);
}
int main()
{
double j = -180.00;
printf(" ");
printf("\n\n");
for (j; j <= 180; j += 5){
printf("%.2f \t", j);
printf( "%.12f \t", DegreesToRadian(j));
cosine(DegreesToRadian(j));
sine(DegreesToRadian(j));
}
return 0;
}
I'm using Taylor Series to find the sin and cosine of a number but when I change the numberOfTerms to 10 or 15 it becomes inaccurate(waaaaaaaaayy off), what do I need to change to make it accurate? (Yeah my functions are not optimal lel)
I get a [Warning] incompatible implicit declaration of built-in function 'pow' if that matters.
Let us assume you keep the value of numberOfTerms as 10. Then, in the cosine and sine functions, in the for loop, you are incrementing exponent by 2 every time. And, you are using the factorial of exponent in the denominator.
If the loop runs 9 times, the value for exponent would increase as 2, 4, 6, 8, 10, 12, 14, 16, 18.
We know that 14! = 87178291200. But a signed int (which is used to return the result of the factorial function) can hold a positive value up to 2147483647. There occurs an overflow.
I suggest you use double (or even unsigned long long) for the return type and the parameter of the factorial function. But do not try to compute factorials of large numbers as they would not fit in any data type in C.
Also, since you have not defined pow function yourself, I think you are missing a #include<math.h> at the top.
Another suggestion, define pi as a symbolic constant rather than a global variable.
The implicit declaration of pow returns an int, but the actual definition returns double, the code will interpret the double an an int by bit pattern resulting in an entirely incorrect value - not just the integer part of the double.

Resources