Creating a sin formula in C - c

The program compiles but when running it I am not getting the correct values back from my inputs. I have looked for a way to make the sine formula and have found this one but I don't believe it was right.
Is my formula correct? I think just running the sin function in C is giving me the wrong value as well.
Update: I'm still getting the wrong values with these changes if I input 1.5 and 4. I'm getting 0.000 and a random integer
/*
* Function mySin is using a sin formula to get the sin of x
* the function then returns the sin value computed
* Parameters -for function mySin are "x" is the value for sin
* -"n"is the number of series to run
*
*The program also uses the sin(x) function to get the real sin
*
*/
#include <stdio.h>
#include <math.h>
int mySin(double x, int n){
int i=0;
double sinx=0;
for(i=1; i<=n; i+=2){
sinx=(pow(x,i)+sinx); //
}
return sinx;
}
int main(double sinx){
double realSin=0;
double x=0;
int n=0;
printf("Please input x and n:");
scanf("%lf",&x);
scanf("%d",&n);
mySin(x,n);
realSin=sin(x);
printf("mySin= %f\n sin=%d\n",sinx,realSin);
}

Your mySin function is wrong in at least 5 separate ways. Using ** to represent exponentiation (to avoid confusion with xor), the correct formula is
sin(x) = x - x**3/3! + x**5/5! - x**7/7! + x**9/9! ...
Your implementation fails because
It discards the previous terms on every iteration of the loop.
It doesn't alternate signs.
It includes even-exponent terms.
It doesn't compute a factorial in the divisor.
The return type is int, discarding the fractional component of the computed result.
Furthermore, main is wrong in several more ways. The return value of mySin is completely ignored. Instead, sinx is the first argument to main, which is the number of command-line arguments the program received (including the name it was run as). Also, %d is used for all numbers in format strings, regardless of type, when it's only meant for int.
To fix mySin, have i only go over odd values, and have every iteration of the loop compute x**i/i! and add it into the current value of sinx.
To fix main, declare a local sinx variable in main and assign sinx = mySin(x, n) instead of declaring sinx as an argument. Also, use %lf for reading doubles with scanf and %f for writing doubles with printf.

x is double so you have to use the %lf in scanf and %f in the printf
double x;
scanf("%lf", &x);
printf ("%f", x);

One more incorrect point in your code is that you're calculating power by **
There's no power operator in C. The compiler is treating x**i as x * (*i). But since i is not a pointer, it returns the error you saw. You must use pow() instead

mySin should return double. You are returning int.
sin values can be calculated with the Fourier series.

Related

Infinite series approximation of pi in C not terminating

Here is my code, when using print statements it appeared to be an infinite loop:
some potential issues i can troubleshoot are integer division, and perhaps figuring out if the algorithm terminates, and if it always has the correct output, perhaps there is some idiosyncrasy of the C language that I do not understand causing this issue?
From my understanding as the sum tends to negative infinity it will cause the break statement to be triggered ending the algorithm once it reaches an approximation of epsilon precision.
#include <stdio.h>
int main()
{
double pi, sum, epsilon;
long long i=1;
long long max = 2147483647;
printf("Pleas enter the desired accuracy epsilon : ");
scanf("%f", &epsilon);
while (i<max){
if (i%2 == 0){
sum = -4.0/(2.0*i-1);
}else if (i%2 ==1){
sum = (4.0/(2.0*i-1));
}
if (sum < epsilon){
break;
}
pi += sum;
}
printf("The value of pi approximated to epsion : %f is %f\n", epsilon, pi);
return 0;
}
You are not increment the value of i in your while loop. As a result its value always remains 1.
Increment i after your processing is done before the closing } of the while loop.
Initialize the values of pi, sum, epsilon so that you do not run into undefined behavior when you try to read their values for the first time.
Also, with proper options enabled (-Wall with GCC) the compiler will warn you, that you are trying to read a float into a double.
warning: format '%f' expects argument of type 'float *', but argument 2 has type 'double *' [-Wformat=]
scanf("%f", &epsilon);
~^ ~~~~~~~~
So you have to use the correct conversion specifier: %lf instead of %f in your scanf statement.
If you are not very particular about the number 2147483647 and just want a large value, you can also use ULLONG_MAX (from limits.h) to initialize max instead of hard-coding the value.
You need to increment i value in while loop.
Your looping condition while(i < max) is always satisfied (infinite loop). So the value of i or max should be changed inside the loop to ever end the loop.
Your code has undefined behavior:
scanf("%f", &epsilon);
scanf %f takes a float *, not double *. The correct format for double * is %lf.
Your loop condition while (i<max) is equivalent to while (1) as neither i nor max change their value inside the loop.
This also means sum is always 4:
sum = (4.0/(2.0*i-1));
// 4 / (2 * 1 - 1) = 4 / (2 - 1) = 4 / 1 = 4
pi += sum;
also has undefined behavior: pi is uninitialized.

From a float to an integer

Given this code that my professor gave us in an exam which means we cannot modify the code nor use function from other libraries (except stdio.h):
float x;
(suppose x NOT having an integer part)
while (CONDITION){
x = x*10
}
I have to find the condition that makes sure that x has no valid number to the right of decimal point not giving attention to the problems of precision of a float number (After the decimal point we have to have only zeros). I tried this condition:
while ((fmod((x*10),10))){
X = X*10
}
printf(" %f ",x);
example:
INPUT x=0.456; --------> OUTPUT: 456.000
INPUT X=0.4567;--------> OUTPUT; 4567.000
It is important to be sure that after the decimal point we don't have any
significant number
But I had to include math.h library BUT my professor doesn't allow us to use it in this specific case (I'm not even allowed to use (long) since we never seen it in class).
So what is the condition that solve the problem properly without this library?
As pointed out here previously:Due to the accuracy of floats this is not really possible but I think your Prof wants to get something like
while (x - (int)x != 0 )
or
while (x - (int)x >= 0.00000001 )
You can get rid of the zeroes by using the g modifier instead of f:
printf(" %g \n",x);
There is fuzziness ("not giving attention to the problems of precision of a float number") in the question, yet I think a sought answer is below, assign x to an integer type until x no longer has a fractional part.
Success of this method depends on INT_MIN <= x <= INT_MAX. This is expected when the number of bits in the significant of float does not exceed the value bits of int. Although this is common, it is not specified by C. As an alternative, code could with a wider integer type like long long with a far less chance of the range restriction issue.
Given the rounding introduced with *10, this method is not a good foundation of float to text conversion.
float Dipok(float x) {
int i;
while ((i=x) != x) {
x = x*10;
}
return x;
}
#include <assert.h>
#include <stdio.h>
#include <float.h>
void Dipok_test(float x) {
// suppose x NOT having an integer part
assert(x > -1.0 && x < 1.0);
float y = Dipok(x);
printf("x:%.*f y:%.f\n", FLT_DECIMAL_DIG, x, y);
}
int main(void) {
Dipok_test(0.456);
Dipok_test(0.4567);
return 0;
}
Output
x:0.456000000 y:456
x:0.456699997 y:4567
As already pointed out by 2501, this is just not possible.
Floats are not accurate. Depending on your platform, the float value for 0.001 is represented as something like 0.0010000001 in fact.
What would you expect the code to calculate: 10000001 or 1?
Any solution will work for some values only.
I try to answer to my exam question please if I say something wrong correct me!
It is not possible to find a proper condition that makes sure that there are no valid number after the decimal point. For example : We want to know the result of 0.4*20 which is 8.000 BUT due to imprecision problems the output will be different:
f=0.4;
for(i=1;i<20;i++)
f=f+0.4;
printf("The number f=0.4*20 is ");
if(f!=8.0) {printf(" not ");}
printf(" %f ",8.0);
printf("The real answer is f=0.4*20= %f",f);
Our OUTPUT will be:
The number f=0.4*20 is not 8.000000
The real answer is f=0.4*20= 8.000001

To print the answer from the series -> x^3 - x^5 + x^7 - x^9 +

#include<stdio.h>
#include<conio.h>
#include<math.h>
int main()
{
int x,n;
float sum=0;
printf("Length and Value");
scanf("%d%d",&n,&x);
for(int i=1;i<=n;i++)
{
sum+=(pow(x,2*i+1) * pow(-1,i+1));
}
printf("%f",sum);
return 0;
}
I'm trying to solve this series in C language. Am I doing something wrong in the above code?
Yes, you're a bit wrong. In your code
printf("%f",sum);
sum is an int and using %f to print the value of an int is undefined behaviour.
The function pow() returns a double. You may want to change your sum to type double.
If you don't mind using your own version, a better looking implementation, without using pow() will be
Store the existing value.
Multiply by x * x on each iteration
Take care of -ve sign for even numbered iteration.
First things first, your printf has the wrong format specifier for an int: use %d instead. But for non-integral x, you'll want to refactor to a double anyway, so %f will probably be retained.
Secondly, don't use pow: it will not be precise (probably implemented as exp(log)) and you don't need to evaluate the power from scratch for each term.
Keep a running power: i.e. compute x * x * x initially, then successively multiply that by x * x for subsequent terms. Don't forget to alternate the signs: you can do that by multiplying by -1.
you are trying to find x^3,x^5 that is power in odd. so do a little change in your for loop. write this instead of your code. and if you give a large x or n value then it is preferable to declare sum as a long data type
#include<stdio.h>
#include<conio.h>
#include<math.h>
int main()
{
int x,n;
long sum=0;
printf("Length and Value");
scanf("%d%d",&n,&x);
for(int i=2;i<=n;i+=2)
{
sum+=(pow(x,i+1) * pow(-1,i));
}
printf("%l",sum);
return 0;
}
First of all, you are trying to evaluate a series that diverges for all points outside and on the circle of radius one (as a complex series). If you use an int for x, you will get each time values bigger and bigger, oscillating around 0. Try it with numbers of ||x|| < 1 (this means double or float for x)
All the other answers posted are also usefull to get sooner to the expected value.

Number of decimal digits in C

I like to change the number of decimal digits showed whenever I use a float number in C. Does it have something to do with the FLT_DIG value defined in float.h? If so, how could I change that from 6 to 10?
I'm getting a number like 0.000000 while the actual value is 0.0000003455.
There are two separate issues here: The precision of the floating point number stored, which is determined by using float vs double and then there's the precision of the number being printed as such:
float foo = 0.0123456789;
printf("%.4f\n", foo); // This will print 0.0123 (4 digits).
double bar = 0.012345678912345;
printf("%.10lf\n", bar); // This will print 0.0123456789
I experimented this problem and I found out that you cannot have great precision with float they are really bad .But if you use double it would give you the right answer. just mention %.10lf for precision upto 10 decimal points
You're running out of precision. Floats don't have great precision, if you want more decimal places, use the double data type.
Also, it seems that you're using printf() & co. to display the numbers - if you ever decide to use doubles instead of floats, don't forget to change the format specifiers from %f to %lf - that's for a double.
#kosmoplan - thank you for a good question!
#epsalon - thank you for a good response. My first thought, too, was "float" vs. "double". I was mistaken. You hit it on the head by realizing it was actually a "printf/format" issue. Good job!
Finally, to put to rest some lingering peripheral controversy:
/*
SAMPLE OUTPUT:
a=0.000000, x=0.012346, y=0.012346
a=0.0000003455, x=0.0123456791, y=0.0123456789
*/
#include <stdio.h>
int
main (int argc, char *argv[])
{
float x = 0.0123456789, a = 0.0000003455;
double y = 0.0123456789;
printf ("a=%f, x=%f, y=%lf\n", a, x, y);
printf ("a=%.10f, x=%.10f, y=%.10lf\n", a, x, y);
return 0;
}

Sine function using Taylor expansion (C Programming)

Here is the question..
This is what I've done so far,
#include <stdio.h>
#include <math.h>
long int factorial(int m)
{
if (m==0 || m==1) return (1);
else return (m*factorial(m-1));
}
double power(double x,int n)
{
double val=1;
int i;
for (i=1;i<=n;i++)
{
val*=x;
}
return val;
}
double sine(double x)
{
int n;
double val=0;
for (n=0;n<8;n++)
{
double p = power(-1,n);
double px = power(x,2*n+1);
long fac = factorial(2*n+1);
val += p * px / fac;
}
return val;
}
int main()
{
double x;
printf("Enter angles in degrees: ");
scanf("%lf",&x);
printf("\nValue of sine of %.2f is %.2lf\n",x,sine(x * M_PI / 180));
printf("\nValue of sine of %.2f from library function is %.2lf\n",x,sin(x * M_PI / 180));
return 0;
}
The problem is that the program works perfectly fine from 0 to 180 degrees, but beyond that it gives error.. Also when I increase the value of n in for (n=0;n<8;n++) beyond 8, i get significant error.. There is nothing wrong with the algorithm, I've tested it in my calculator, and the program seems to be fine as well.. I think the problem is due to the range of the data type.. what should i correct to get rid of this error?
Thanks..
You are correct that the error is due to the range of the data type. In sine(), you are calculating the factorial of 15, which is a huge number and does not fit in 32 bits (which is presumably what long int is implemented as on your system). To fix this, you could either:
Redefine factorial to return a double.
Rework your code to combine power and factorial into one loop, which alternately multiplies by x, and divides by i. This will be messier-looking but will avoid the possibility of overflowing a double (granted, I don't think that's a problem for your use case).
15! is indeed beyond range that a 32bit integer can hold. I'd use doubles throughout if I were you.
The taylor series for sin(x) converges more slowly for large values of x. For x outside -π,π. I'd add/subtract multiples of 2*π to get as small an x as possible.
You need range reduction. Note that a Taylor series is best near zero and that in the negative range it is the (negative) mirror image of it's positive range. So, in short: reduce the range (by the modula of 2 PI) to wrap it it the range where you have the highest accuracy. The range beyond 1/2 PI is getting less accurate, so you also want to use the formula: sin(1/2 PI + x) = sin(1/2 PI - x). For negative vales use the formula: sin(-x) = -sin(x). Now you only need to evaluate the interval 0 - 1/2 PI while spanning the whole range. Of course for VERY large values accuracy of the modula of 2 PI will suffer.
You may be having a problem with 15!.
I would print out the values for p, px, fac, and the value for the term for each iteration, and check them out.
You're only including 8 terms in an infinite series. If you think about it for a second in terms of a polynomial, you should see that you don't have a good enough fit for the entire curve.
The fact is that you only need to write the function for 0 <= x <=\pi; all other values will follow using these relationships:
sin(-x) = -sin(x)
and
sin(x+\pi;) = -sin(x)
and
sin(x+2n\pi) = sin(x)
I'd recommend that you normalize your input angle using these to make your function work for all angles as written.
There's a lot of inefficiency built into your code (e.g. you keep recalculating factorials that would easily fit in a table lookup; you use power() to oscillate between -1 and +1). But first make it work correctly, then make it faster.

Resources