Calculate the value of 𝜋 from the infinite series in c - c

I am trying to make a C program that calculates the value of Pi from the infinite series, aka Leibniz series, and display it to the user. My problem is that I need to display a special message that appears when the program hits the first 3.14, and the first 3.141. That special message should include in which iteration of the loop did the the number become 3.14 and 3.141. I am not lazy so a found a way to make the infinite series but the second part I couldn't figure out, so what should I add to my code to make it display the special message?
#include <stdio.h>
int main(void) {
int i, den; // denominator and counter
double pi = 4;
for (i = 0; i < 10000; i++) {
den = i * 2 + 3;
// (4 - 4/3 + 4/5 -4/7 + 4/9 -......)
if (i % 2 == 0) {
pi = pi - (4.0 / den);
}
else {
pi = pi + (4.0 / den);
}
printf("pi = %lf\n", pi);
}
}

Here's a possible solution:
#include<stdio.h>
#include <math.h>
int
main (void)
{
int i, den; //denominator and counter
int prec = 0;
double pi = 4;
for (i = 0; i < 10000; i++)
{
den = i * 2 + 3;
//(4 - 4/3 + 4/5 -4/7 + 4/9 -......)
if (i % 2 == 0)
pi -= 4.0 / den;
else
pi += 4.0 / den;
//printf ("pi = %lf\n", pi);
if (prec < 1 && trunc (100 * pi) == 314)
{
printf ("Found 3.14 at iteration %d\n", i);
prec++;
}
if (prec < 2 && (int)trunc (1000 * pi) == 3141)
{
printf ("Found 3.141 at iteration %d\n", i);
prec++;
}
}
}
The output is:
pi = 2.666667
pi = 3.466667
pi = 2.895238
...
pi = 3.150140
pi = 3.133118
pi = 3.149996
Found 3.14 at iteration 117
...
pi = 3.141000
pi = 3.142185
pi = 3.141000
Found 3.141 at iteration 1686
...

Here is a version that compares the first n digits of a double cmp_n(). Variables use minimal scope. The variable oracle holds the truncated pi to n decimals. The values of oracle must be stored in ascending order. I tweaked the pi formula to be a bit more compact format.
#include <math.h>
#include <stdio.h>
int cmp_n(double d1, double d2, size_t n) {
return fabs(trunc(pow(10, n) * d1) - trunc(pow(10, n) * d2)) < 1.0;
}
int main() {
double pi = 4;
size_t o = 0;
struct {
double pi[;
size_t n;
} oracle[] = {
{ 3.14, 2 },
{ 3.141, 3 }
};
for (int i = 0; i < 10000; i++) {
int den = i * 2 + 3;
//(4 - 4/3 + 4/5 -4/7 + 4/9 -......)
pi += ((i % 2) ? 4.0 : -4.0) / den;
int special = 0;
if(
o < sizeof(oracle) / sizeof(*oracle) &&
cmp_n(pi, oracle[o].pi, oracle[o].n)
) {
special = 1;
o++;
}
printf("pi = %.15f%2s\n", pi, special ? "*" : "");
}
}
and the relevant data (with line numbers);
$ ./a.out | nl -v0 | grep '*'
117 pi = 3.149995866593470 *
1686 pi = 3.141000236580159 *
Note: you need to add the "%.15lf" format string other the pi output is rounded. double only gives you about 15 digits, and the cmp_n() scales the number and this may not work as expected as you get close to the precision supported by double.

Related

#29 expected expression - C compilation

I'm programing on Code Composer Studio a program that generate and show a sinusoid, this program should normally be implemented in a DSP, but since I don't have the DSK I'm just compiling it and trying to show the result in CCS.
I'm having a problem in the line 18 it shows that an expression is expected and I don't know why. I checked all comas and () {} and it seems correct.
#include <math.h>
#include <stdio.h>
const int sine_table[40] = { 0, 5125, 10125, 14876, 19260, 23170, 26509, 29196, 31163, 32364, 32767, 32364, 31163, 29196, 26509, 23170, 19260, 14876, 10125, 5125, 0, -5126, -10126, -14877, -19261, -23171, -26510, -29197, -31164, -32365, -32768, -32365, -31164, -29197, -26510, -23171, -19261, -14877, -10126, -5126 };
int i = 0;
int x1 = 0;
int x2 = 0;
float y = 0;
float sin1(float phase) {
x1 = (int) phase % 40; if (x1 < 0) x1 += 40; x2 = (x1 + 1) % 40;
y = (sine_table[x2] - sine_table[x1]) * ((float) ((int) (40 * 0.001 * i * 100) % 4100) / 100 - x1) + sine_table[x1];
return y;
}
int main(void) {
double pi = 3.1415926535897932384626433832795;
for (int i = 0; i < 1000; i++) {
float x = 40 * 0.001 * i;
float radians = x * 2 * pi / 40;
printf("%f %f %f\n", x, sin1(x) / 32768, sin(radians));
i = i + 1;
}
}

Taylor Series in C (problem with sin(240) and sin(300))

#include <stdio.h>
#include <math.h>
const int TERMS = 7;
const float PI = 3.14159265358979;
int fact(int n) {
return n<= 0 ? 1 : n * fact(n-1);
}
double sine(int x) {
double rad = x * (PI / 180);
double sin = 0;
int n;
for(n = 0; n < TERMS; n++) { // That's Taylor series!!
sin += pow(-1, n) * pow(rad, (2 * n) + 1)/ fact((2 * n) + 1);
}
return sin;
}
double cosine(int x) {
double rad = x * (PI / 180);
double cos = 0;
int n;
for(n = 0; n < TERMS; n++) { // That's also Taylor series!
cos += pow(-1, n) * pow(rad, 2 * n) / fact(2 * n);
}
return cos;
}
int main(void){
int y;
scanf("%d",&y);
printf("sine(%d)= %lf\n",y, sine(y));
printf("cosine(%d)= %lf\n",y, cosine(y));
return 0;
}
The code above was implemented to compute sine and cosine using Taylor series.
I tried testing the code and it works fine for sine(120).
I am getting wrong answers for sine(240) and sine(300).
Can anyone help me find out why those errors occur?
You should calculate the functions in the first quadrant only [0, pi/2). Exploit the properties of the functions to get the values for other angles. For instance, for values of x between [pi/2, pi), sin(x) can be calculated by sin(pi - x).
The sine of 120 degrees, which is 40 past 90 degrees, is the same as 50 degrees: 40 degrees before 90. Sine starts at 0, then rises toward 1 at 90 degrees, and then falls again in a mirror image to zero at 180.
The negative sine values from pi to 2pi are just -sin(x - pi). I'd handle everything by this recursive definition:
sin(x):
cases x of:
[0, pi/2) -> calculate (Taylor or whatever)
[pi/2, pi) -> sin(pi - x)
[pi/2, 2pi) -> -sin(x - pi)
< 0 -> sin(-x)
>= 2pi -> sin(fmod(x, 2pi)) // floating-point remainder
A similar approach for cos, using identity cases appropriate for it.
The key point is:
TERMS is too small to have proper precision. And if you increase TERMS, you have to change fact implementation as it will likely overflow when working with int.
I would use a sign to toggle the -1 power instead of pow(-1,n) overkill.
Then use double for the value of PI to avoid losing too many decimals
Then for high values, you should increase the number of terms (this is the main issue). using long long for your factorial method or you get overflow. I set 10 and get proper results:
#include <stdio.h>
#include <math.h>
const int TERMS = 10;
const double PI = 3.14159265358979;
long long fact(int n) {
return n<= 0 ? 1 : n * fact(n-1);
}
double powd(double x,int n) {
return n<= 0 ? 1 : x * powd(x,n-1);
}
double sine(int x) {
double rad = x * (PI / 180);
double sin = 0;
int n;
int sign = 1;
for(n = 0; n < TERMS; n++) { // That's Taylor series!!
sin += sign * powd(rad, (2 * n) + 1)/ fact((2 * n) + 1);
sign = -sign;
}
return sin;
}
double cosine(int x) {
double rad = x * (PI / 180);
double cos = 0;
int n;
int sign = 1;
for(n = 0; n < TERMS; n++) { // That's also Taylor series!
cos += sign * powd(rad, 2 * n) / fact(2 * n);
sign = -sign;
}
return cos;
}
int main(void){
int y;
scanf("%d",&y);
printf("sine(%d)= %lf\n",y, sine(y));
printf("cosine(%d)= %lf\n",y, cosine(y));
return 0;
}
result:
240
sine(240)= -0.866026
cosine(240)= -0.500001
Notes:
my recusive implementation of pow using successive multiplications is probably not needed, since we're dealing with floating point. It introduces accumulation error if n is big.
fact could be using floating point to allow bigger numbers and better precision. Actually I suggested long long but it would be better not to assume that the size will be enough. Better use standard type like int64_t for that.
fact and pow results could be pre-computed/hardcoded as well. This would save computation time.
const double TERMS = 14;
const double PI = 3.14159265358979;
double fact(double n) {return n <= 0.0 ? 1 : n * fact(n - 1);}
double sine(double x)
{
double rad = x * (PI / 180);
rad = fmod(rad, 2 * PI);
double sin = 0;
for (double n = 0; n < TERMS; n++)
sin += pow(-1, n) * pow(rad, (2 * n) + 1) / fact((2 * n) + 1);
return sin;
}
double cosine(double x)
{
double rad = x * (PI / 180);
rad = fmod(rad,2*PI);
double cos = 0;
for (double n = 0; n < TERMS; n++)
cos += pow(-1, n) * pow(rad, 2 * n) / fact(2 * n);
return cos;
}
int main()
{
printf("sine(240)= %lf\n", sine(240));
printf("cosine(300)= %lf\n",cosine(300));
}

how to print multiple max values using loop

Trying to calculate at which frequencies voltage hits max, i am able to print the most recent max but there may be lower values of frequency in which it is able to max voltage.
I am able to get the highest or lowest freq by switching the loop from + to - from or to 1000000 in increments of 10.
Tried nested if statement inside of VO > voMax
#include <stdio.h>
#include <conio.h>
#include <math.h>
#define PI 3.14f
#define Vi 5
#define L 4.3e-4
#define C 5.1e-6
int getFreq();
long getResist();
float getVO(float XL, float XC, int R);
float getXC(int f);
float getXL(int f);
int main()
{
long resist, freq, fMax;
float XL, XC, VO, voMax;
voMax = 0;
fMax = 0;
resist = getResist();
for (freq = 1000000; freq >= 0; freq -= 10)
{
XL = getXL(freq);
XC = getXC(freq);
VO = getVO(XL, XC, resist);
if (1000000 == freq)
{
fMax = freq;
voMax = VO;
}
else if (VO > voMax)
{
fMax = freq;
voMax = VO;
}
}
printf("VO = %f Frequency = %d\n", voMax, fMax);
getch();
return 0;
}
float getXL(long f)
{
float XL;
XL = 2 * PI * f * C;
return XL;
}
float getXC(long f)
{
float XC;
XC = 1 / (2 * PI * f * C);
return XC;
}
float getVO(float XL, float XC, long R)
{
float VO;
VO = (Vi * R) / sqrt((XL - XC) * (XL - XC) + R * R);
return VO;
}
int getFreq()
{
int freq;
freq = 0;
printf("please enter a frequency:");
scanf("%d", &freq);
return freq;
}
long getResist()
{
int resist;
resist = 0;
printf("please enter a resistance:");
scanf("%d", &resist);
return resist;
}
I want the voltage to print max at multiple freq.
Well, what you want is to generate "a lot" of data, and then make some analysis. I would actually implement it in two steps:
Generate the data (and save it in an array or in a file)
Do any analysis you need on that data.
After you get the desired result with this clear approach, you can move to the next step and try to optimize the algorithm, according to any optimization rule you need.
I want the voltage to print max at multiple freq.
I think you need a small code update. You have the following sequence:
voMax = 0;
fMax = 0;
resist = getResist();
for (freq = 1000000; freq >= 0; freq -= 10)
{
you should probably have:
fMax = 0;
resist = getResist();
for (freq = 1000000; freq >= 0; freq -= 10)
{
voMax = 0;
(I moved "voMax = 0;" inside the "for").
In that way, you can calculate max voltages for all frequencies, without interference from the other frequencies.

Formula nested in loop won't execute properly

I'm trying to solve a code to run this series pi = 4 - 4/3 + 4/5 - 4/7 + 4/9 ... and so on. The thing is, as i run with higher values, the function tends to 4, not 3,1415.... The program seem to be running only the greatest value that n assumes. Also i cant make %%.lflf work to set decimals according to a variable, (p). The algorithm seems correct but after days i'm desperate for any help, greatly appreciated.
if ( 2 == route ) {
printf("piseries calculator\n");
double pi,n,p;
printf("define precision");
scanf("%lf",&p);
n=0;
while (n++ <= p ) {
pi = (4) - (n * ( 4 / ( 1 + 2 *(n)))) +( n * ( 4 / ( 3 + 2 * (n))));
}
printf("%%.lflf",p,pi);
return 0;
}
First of all, make n and p integers.
Secondly n starts at 3 doesn't it?
Third the Pi series is 4.0 (- fraction + fraction)...
Finally you can printf using %.*lf to increase/limit the precision of the output.
if ( 2 == route )
{
printf("piseries calculator\n");
double pi=4.0;
int n,p;
printf("define precision");
scanf("%d",&p);
for(n=3;n<p;n+=2)
{
pi -= 4.0/n;
n+=2;
pi += 4.0/n;
}
printf("%.*lf",p,pi);
return 0;
}
I would scale it as well for those calculations
#include <stdio.h>
#define Niterations 1000
#define SCALE 1000
int main(void) {
double pi = 4.0 * SCALE;
for(unsigned i = 0; i < Niterations; i ++)
{
double f = 4.0 * SCALE / (3 + i * 2);
pi += (i & 1) ? f : -f;
}
printf("N iterations = %u, pi = %lf", Niterations, pi / SCALE);
// your code goes here
return 0;
}
Test it https://ideone.com/mSZNyg
Result: N iterations = 10000, pi = 3.141692643590519029572760700830258429050445556640625000000000 ...

The outermost for loop does not work as intended

I have been using Ubuntu 12.04 LTS with GCC to compile my the codes for my assignment for a while. However, recently I have run into two issues as follows:
The following code calculates zero for a nonzero value with the second formula is used.
There is a large amount of error in the calculation of the integral of the standard normal distribution from 0 to 5 or larger standard deviations.
How can I remedy these issues? I am especially obsessed with the first one. Any help or suggestion is appreciated. thanks in advance.
The code is as follows:
#include <stdio.h>
#include <math.h>
#include <limits.h>
#include <stdlib.h>
#define N 599
long double
factorial(long double n)
{
//Here s is the free parameter which is increased by one in each step and
//pro is the initial product and by setting pro to be 0 we also cover the
//case of zero factorial.
int s = 1;
long double pro = 1;
//Here pro stands for product.
if (n < 0)
printf("Factorial is not defined for a negative number \n");
else {
while (n >= s) {
pro *= s;
s++;
}
return pro;
}
}
int main()
{
// Since the function given is the standard normal distribution
// probability density function we have mean = 0 and variance = 1.
// Hence we also have z = x; while dealing with only positive values of
// x and keeping in mind that the PDF is symmetric around the mean.
long double * summand1 = malloc(N * sizeof(long double));
long double * summand2 = malloc(N * sizeof(long double));
int p = 0, k, z[5] = {0, 3, 5, 10, 20};
long double sum1[5] = {0}, sum2[5] = {0} , factor = 1.0;
for (p = 0; p <= 4; p++)
{
for (k = 0; k <= N; k++)
{
summand1[k] = (1 / sqrtl(M_PI * 2) )* powl(-1, k) * powl(z[p], 2 * k + 1) / ( factorial(k) * (2 * k + 1) * powl(2, k));
sum1[p] += summand1[k];
}
//Wolfamalpha site gives the same value here
for (k = 0; k <= N; k++)
{
factor *= (2 * k + 1);
summand2[k] = ((1 / sqrtl(M_PI * 2) ) * powl(z[p], 2 * k + 1) / factor);
//printf("%Le \n", factor);
sum2[p] += summand2[k];
}
sum2[p] = sum2[p] * expl((-powl(z[p],2)) / 2);
}
for (p = 0; p < 4; p++)
{
printf("The sum obtained for z between %d - %d \
\nusing the first formula is %Lf \n", z[p], z[p+1], sum1[p+1]);
printf("The sum obtained for z between %d - %d \
\nusing the second formula is %Lf \n", z[p], z[p+1], sum2[p+1]);
}
return 0;
}
The working code without the outermost for loop is
#include <stdio.h>
#include <math.h>
#include <limits.h>
#include <stdlib.h>
#define N 1200
long double
factorial(long double n)
{
//Here s is the free parameter which is increased by one in each step and
//pro is the initial product and by setting pro to be 0 we also cover the
//case of zero factorial.
int s = 1;
long double pro = 1;
//Here pro stands for product.
if (n < 0)
printf("Factorial is not defined for a negative number \n");
else {
while (n >= s) {
pro *= s;
s++;
}
return pro;
}
}
int main()
{
// Since the function given is the standard normal distribution
// probability density function we have mean = 0 and variance = 1.
// Hence we also have z = x; while dealing with only positive values of
// x and keeping in mind that the PDF is symmetric around the mean.
long double * summand1 = malloc(N * sizeof(long double));
long double * summand2 = malloc(N * sizeof(long double));
int k, z = 3;
long double sum1 = 0, sum2 = 0, pro = 1.0;
for (k = 0; k <= N; k++)
{
summand1[k] = (1 / sqrtl(M_PI * 2) )* powl(-1, k) * powl(z, 2 * k + 1) / ( factorial(k) * (2 * k + 1) * powl(2, k));
sum1 += summand1[k];
}
//Wolfamalpha site gives the same value here
printf("The sum obtained for z between 0-3 using the first formula is %Lf \n", sum1);
for (k = 0; k <= N; k++)
{
pro *= (2 * k + 1);
summand2[k] = ((1 / sqrtl(M_PI * 2) * powl(z, 2 * k + 1) / pro));
//printf("%Le \n", pro);
sum2 += summand2[k];
}
sum2 = sum2 * expl((-powl(z,2)) / 2);
printf("The sum obtained for z between 0-3 using the second formula is %Lf \n", sum2);
return 0;
}
I'm quite certain that the problem is in factor not being set back to 1 in the outer loop..
factor *= (2 * k + 1); (in the loop that calculates sum2.)
In the second version provided the one that works it starts with z=3
However in the first loop since you do not clear it between iterations on p by the time you reach z[2] it already is a huge number.
EDIT: Possible help with precision..
Basically you have a huge number powl(z[p], 2 * k + 1) divided by another huge number factor. huge floating point numbers lose their precision. The way to avoid that is to perform the division as soon as possible..
Instead of first calculating powl(z[p], 2 * k + 1) and dividing by factor :
- (z[p]z[p] ... . * z[p]) / (1*3*5*...(2*k+1))`
rearrange the calculation: (z[p]/1) * (z[p]^2/3) * (z[p]^2/5) ... (z[p]^2/(2*k+1))
You can do this in sumand2 calculation and a similar trick in summand1

Resources