I've created a function to compute cosine based on taylor serie ,
only to encounter a precision problem when comparing it with the standard library cosine.
for example,computing 23 my cos gives:
-0.532834
and the standard library gives:
-0.532833
I've been searching the web,and trying to figure it myself but just couldn't figure what the problem is!
when increasing the treashould to be 1.0e-7,the problem is solved.
but it should work well for 1.0e-6 as well(as it worked for my friends)
would appreciate any insight,thanks ahead.
#define PI 3.14159265358979323846264338327950288419716
double my_cos(double rad){
int i = 0;
double numer = 1, denom = 1;
double x2, cos = 0;
rad = fmod(fabs(rad),2*PI);
x2 = pow(rad,2);
do{
cos += pow(-1,i)*(numer/denom);
i++;
numer *= x2;
denom *= (2*i)*(2*i-1);
} while (numer/denom>1.0e-6);
return cos ;
}
The rounding happens when you call printf
This
printf("%f\n", my_cos(23));
printf("%f\n", cos(23));
will print
-0.532834
-0.532833
which seems "wrong".
But
if you increase the number of digits print like
printf("%0.12f\n", my_cos(23));
printf("%0.12f\n", cos(23));
it will print
-0.532833931872
-0.532833020333
So you have the precision you want. It's just the printing that makes it look as if something is wrong.
Related
Im trying to calculate the sin(x) using Taylor Series for sin x by formula with the accuracy of 0.00001 (meaning until the sum goes lower than precision of 0.00001).
(x is given by radians).
The problem is that my function to calculate sin (using Taylor series formula) is printing out the same value as given (for example if 7 is given it will print out 7.00000 instead of 0.656987).
tried to debug my code using gdb and couldnt figure out why it stops after first iteration.
Here`s my C code in order to calculate sin (x ) using Taylor series.
double my_sin(double x) {
int i=3,sign=1; // sign variable is meant to be used for - and + operator inside loop.
// i variable will be used for power and factorial division
double sum=x, accuracy=0.000001; // sum is set for first x.
for(i=3;fabs(sum) < accuracy ;i+=2){ // starting from power of 3.
sign*=-1; // sign will change each iteration from - to +.
sum+=sign*(pow(x,i)/factorial(i)); // the formula itself (factorial simple function for division)
}
return (sum);
}
Any help would be appreciated.
Thanks
tried to debug my code using gdb and couldnt figure out why it stops after first iteration.
Well, let's do it again, step by step.
sum = x (input is 7.0, so sum == 7.0).
for(i=3; fabs(sum) < accuracy; i+=2) { ...
Since sum is 7.0, it is not less than accuracy, so the loop body never executes.
return sum; -- sum is still 7.0, so that's what your function returns.
Your program does exactly what you asked it to do.
P.S. Here the code you probably intended to write:
double my_sin(double x) {
double sum = x, accuracy = 0.000001;
double delta = DBL_MAX;
for(int i = 3, sign = -1; accuracy < fabs(delta); i += 2, sign = -sign) {
delta = sign * pow(x, i) / factorial(i);
sum += delta;
}
return sum;
}
I am a real beginner here and I'm really not sure about this. It is a homework assignment.
We have to find 10 (x,y) coordinates of an arc using the radius, a starting angle and an end angle. The program works, but the results it gives differ very slightly from the 'correct' results as required by the automatic checking system. Here's the code and both mine and the systems results based on r=100, angle1=1, anglef=30!
Thanks in advance!
FILE *pf1;
int n=0;
double angulo1, angulof, angulo, radio, x, y;
printf ("\nIntroduce radio : ");
scanf ("%lf", &radio);
printf ("\nIntroduce angulo inicial : ");
scanf ("%lf", &angulo1);
printf ("\nIntroduce angulo final : ");
scanf ("%lf", &angulof);
angulo = ((angulof-angulo1)/9);
pf1 = fopen("salida.txt", "w");
for (n=0; n<=9; n++)
{
x=radio*cos(angulo1+(angulo*n));
y=radio*sin(angulo1+(angulo*n));
fprintf (pf1, "%lf,%lf\n", x,y);
}
return 0;
.
ERROR
■■■ MY FILE:
54.030231,84.147098
-41.614684,90.929743
-98.999250,14.112001
-65.364362,-75.680250
28.366219,-95.892427
96.017029,-27.941550
75.390225,65.698660
-14.550003,98.935825
-91.113026,41.211849
-83.907153,-54.402111
■■■ CORRECT FILE:
54.030231,84.147095
-41.614685,90.929741
-98.999252,14.112000
-65.364365,-75.680252
28.366219,-95.892426
96.017029,-27.941549
75.390228,65.698662
-14.550003,98.935822
-91.113029,41.211849
-83.907150,-54.402111
The post is very confusing:
Calculating angles from 1 to 30 radians in 10 steps doesn't make much sense. Sensible values for radians are from -2π to +2π, outside that range trigonomic functions quickly lose precision. Also, making steps that are much larger than a few degrees is very unusual. To get from 1 to 30 radians in 10 steps, steps of almost 180° are taken.
Some testing of the output reveals that the steps are smaller: from 1 to 10 radians in 10 steps. This is still 57° per step, and goes almost 2 times around the circle.
Reverse engineering the output with atan2(y,x) reveals that the desired output is less precise than the calculation with doubles. So, probably the calculations used 32 bit floats. To test this, one has to be very careful. Internally, floats can get passed as doubles, and the processor works with 80 bits of precision for arithmetic calculations. (Note that on most machines long double has the same precision as double.)
Now, if you call sin on a float, the compiler often calls the double version of sin. To force the float version, one can try to explicitly call them, they have an f appended to the function name: sinf and cosf.
Testing the following with MicroSoft Visual C, 2017 community edition:
#include <math.h>
void test_sinf()
{
float radio = 100;
float angulo1 = 1;
float angulof = 10;
float angulo = (angulof - angulo1) / 9;
float x, y;
int n;
for (n = 0; n < 10; ++n) {
x = radio * cosf(angulo1 + (angulo*n));
y = radio * sinf(angulo1 + (angulo*n));
printf("%.6lf,%.6lf\n", x, y);
}
}
outputs:
54.030228, 84.147095
-41.614685, 90.929741
-98.999252, 14.112000
-65.364365, -75.680252
28.366220, -95.892426
96.017029, -27.941549
75.390228, 65.698662
-14.550003, 98.935822
-91.113022, 41.211849
-83.907150, -54.402115
This leaves the last digit of only 4 of the numbers with a difference. Which suggests a slightly different library/compiler has been used. As the angles and the radius are all integer numbers which can be represented exact with floats, they are an unprobable cause of the differences.
edit: Testing out the suggestion of #gnasher729 is seems he's right. Running the code with the double precision sin and cos, and convering the result to float before printing, gives exactly the "desired" numbers. This probably gives the same results on most compilers for this test case. (32 bit floats are an IEEE standard, and 64 bit trigonomic functions have enough precision to make implementation details disappear after rounding.)
#include <math.h>
void test_sin_converted_to_float()
{
float radio = 100;
float angulo1 = 1;
float angulof = 10;
float angulo = (angulof - angulo1) / 9;
float x, y;
for (int n = 0; n <= 9; ++n) {
x = radio * cos(angulo1 + (angulo*n));
y = radio * sin(angulo1 + (angulo*n));
printf("%.6lf, %.6lf\n", x, y);
}
}
Checking your data with a spreadsheet, it contains exactly what it ought to contain. The data in the second file however look like sine and cosine where calculated with single precision (float).
Which would mean that whoever created this "automatic checking" should be very, very, ashamed of themselves.
As the name suggested, I'd like to compute cubic roots of a complex number in C. cbrt doesn't work.
#include <stdio.h>
#include <stdlib.h>
#include <complex.h>
#include <cmath.h>
int main(){
double complex x, z = 1+2*I;
x = cbrt(z);
printf("z is %f + %fi \n", creal(z), cimag(z));
printf("x is %f + %fi \n", creal(x), cimag(x));
return(0);
}
The output is as follows.
z is 1.000000 + 2.000000i
x is 1.000000 + 0.000000i
cbrt doesn't work.
That function works on real values. #squeamish ossifrage
x is 1.000000 + 0.000000i is a reasonable result.
double cbrt(double x);
The cbrt functions compute the real cube root of x. C11dr §7.12.7.1 2
A good compiler with warnings fully enabled with report on the following. Save time, enable all compiler warnings.
// warning expected such as:
// warning: conversion to 'long double' from 'complex double' discards imaginary component [-Wconversion]
x = cbrt(z);
How to compute a cubic root of a complex number in C?
<cmath.h> is not part of the C standard library. Its role here is unclear.
Code can use double complex cpow(double complex, double complex);
x = cpow(z, 1.0/3.0);
...
// Ouptut
// x is 1.219617 + 0.471711i
I do not find a double complex ccbrt(double complex); in the standard library nor access to one via type-generic math <tgmath.h>.
... to compute cubic roots ...
Emphasis on plural "roots" here: to compute all 'n' roots:
int n = 3;
const double complex two_pi_i = 2.0 * asin(-1.0) * I;
double complex rotate = cexp(two_pi_i / n);
x = cpow(z, 1.0 / 3.0);
for (int k = 0; k < n; k++) {
printf("x[%d] is % f + % fi \n", k, creal(x), cimag(x));
x *= rotate;
}
Output
x[0] is 1.219617 + 0.471711i
x[1] is 1.018322 + -0.820363i
x[2] is -0.201294 + -1.292075i
I would look at this answer from the Mathematics Stack Exchange.
Essentially you want to compute the radius and angle of the Eurler formula. Then divide both the radius and angle by three (see link). So first you need to convert your complex number to Euler format. I don't have time now to figure that out, but maybe this gave you an idea at where to look.
Hope this helps!
Addition: #squeamish probably has a better idea with cpow, but as he mentioned this will only return one of the roots.
I am trying to get multiplay decimal part of a double number about 500 times. This number starts to lose precision as time goes on. Is there any trick to be able to make the continued multiplication accurate?
double x = 0.3;
double binary = 2.0;
for (i=0; i<500; i++){
x = x * binary;
printf("x equals to : %f",x);
if(x>=1.0)
x = x - 1;
}
Ok after i read some of the things u posted i am thinking how could i remove this unwanted stuff from my number to keep multiplication stable. For instance in my example. My decimal parts will be chaning in such manner: 0.3,0.6,0.2,0.4,0.8... Can we cut the rest to keep this numbers ??
With typical FP is binary64, double x = 0.3; results in x with the value more like 0.29999999999999998890... so code has an difference from the beginning.
Scale x by 10 to stay with exact math - or use a decimal64 double
int main(void) {
double x = 3.0;
double binary = 2.0;
printf("x equals to : %.20f\n",x);
for (int i=0; i<500; i++){
x = x * binary;
printf("x equals to : %.20f\n",x/10);
if(x>=10.0)
x = x - 10;
}
return 0;
}
In general, floating point math is not completely precise, as shown in the other answers and in many online resources. The problem is that certain numbers can not be represented exactly in binary. 0.3 is such a number, but all natural numbers aren't. So you could change your program to this:
double x = 3.0;
double binary = 2.0;
for (i=0; i<500; i++){
x = x * binary;
printf("x equals to : %f",x/10.0);
if(x>=10.0)
x = x - 10.0;
}
Although your program is doing some very unusual things, the main answer to your question is that that is how floating point numbers work. They are imprecise.
http://floating-point-gui.de/basic/
So, I'm trying to create a program that calculates cos(x) by using a Taylor approximation.
The program is really simple: The user inputs a parameter x (x being an angle in radians) and a float ε, which is the precision of the value of cos(x).
Basically, the only thing the program has to do is to calculate this sum:
x^0/0! - x^2/2! + x^4/4! - x^6! + x^8/8! - ..., until the terms are smaller than ε, that is, the value for cos(x) it'll be within our range of precision.
So, here's the code:
#include <stdio.h>
/* Calculates cos(x) by using a Taylor approximation:
cos(x) = x^0/(0!) - x^2/(2!) + x^4/(4!) - x^6/(6!) + x^8/(8!) - ... */
int main(void)
{
int k; // dummy variable k
float x, // parameter of cos(x), in radians
epsilon; // precision of cos(x) (cos = sum ± epsilon)
sum, // sum of the terms of the polynomial series
term; // variable that stores each term of the summation
scanf("%f %f", &x, &epsilon);
sum = term = 1, k = 0;
while (term >= epsilon && -term <= epsilon)
// while abs(term) is smaller than epsilon
{
k += 2;
term *= -(x*x)/(k*(k-1));
sum += term;
}
printf("cos(%f) = %f\n", x, sum);
return 0;
}
At first, I tried to solve it by calculating the factorials on a separate variable "fact", though that caused an overflow even with reasonable large values for ε.
To solve this, I noticed that I could just multiply the previous term by -x² / (k(k - 1)), increasing k by 2 in every iteration, to get the next term. I thought that would solve my problem, but then again, it is not working.
The program compiles fine, but for example, if I input:
3.141593 0.001
The output is:
cos(3.141593) = -3.934803
...and that is obviously wrong. Can someone help me?
The bug lies in the condition of your while loop:
while (term >= epsilon && -term <= epsilon)
It's not the correct condition. While it could be fixed by fixing the logic:
while (term >= epsilon || -term >= epsilon)
You should just use the standard floating point abs function, fabs, as it makes the function of your code more obvious:
while (fabs(term) >= epsilon)
After applying that change and compiling your program I used it to compute cos(3.141593) = -1.000004, which is correct.
Just adding to Charliehorse55's answer.
Usually one does an argument reduction using simple trigonometry
cos(x + y) = cos(x)cos(y) - sin(x)sin(y)
sin(x + y) = cos(x)sin(y) + sin(x)cos(y)
to reduce the argument to [0..SmallAngle] range and only then calculate the Taylor expansion.