C Programming: How to calculate Pi to 4th decimal place? - c

Okay, I want to make a C program that calculates pi accurately to 4th decimal place (3.1415...). I thought that double is more accurate than float type... Even with a trillion terms (n=trillion), the program cannot go past 3.1414... Can someone help? Am I using an incorrect data type to store my Pi value or is my loops incorrect?
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char** argv) {
int n;
while(1){
printf("Please enter how many terms (n) you wish to add to approximate Pi: ");
scanf("%d", &n);
if(n>=1)
break;
}
int x;
int count =2;
double negSum=0;
double posSum=0;
double pi = 0;
for(x=1;x<=n;x++){
do{
if(x%2==1){
posSum += (4.0)/(2.0*x-1.0);
count++;
}
else{
negSum += (-4.0)/(2.0*x-1.0);
count++;
}
pi = negSum + posSum;
}
while(pi>3.1414999 && pi<3.14160000);
}
//pi = negSum + posSum;
printf("The value of Pi using your approximation is %f, and the iteration was %d", pi, count);
return (EXIT_SUCCESS);
}
Here is some of my sample input/output:
Please enter how many terms (n) you wish to add to approximate Pi: 98713485
The value of Pi using your approximation is 3.141407, and the iteration was 98713488

The series you are using:
pi = 4(1 - 1/3 + 1/5 - 1/7 + 1/9 ...)
converges REALLY slowly to pi. It is the evaluation of a Taylor series for 4arctan(x) at x=1 and converges conditionally (it is right on edge of the interval of convergence). That's not going to be a very numerically efficient way to compute pi.
Beyond that, I haven't carefully checked your implementation, but some others have pointed out problems in the comments.

To compute Pi to 4th decimal place, you could use Gauss-Legendre algorithm:
#include <math.h>
#include <stdio.h>
int main(void) {
const double PI = acos(-1), SQRT2 = sqrt(2.0);
double a = 1, b = 1/SQRT2, t = .25, p = 1;
double an, piold, pi = 1, eps = 1e-6; /* use +2 decimal places */
int iteration_count = 0;
do {
++iteration_count;
an = .5 * (a + b);
b = sqrt(a * b);
t -= p * (a - an) * (a - an);
a = an;
p *= 2;
piold = pi;
pi = (a + b) * (a + b) / (4 * t);
} while (fabs(pi - piold) > eps);
printf("got pi=%f with rel. err=%.2e in %d iterations\n",
pi, (pi - PI) / PI, iteration_count);
return 0;
}
To run it:
$ gcc *.c -lm && ./a.out
Output
got pi=3.141593 with rel. err=2.83e-16 in 3 iterations

Related

Print Value of pi. How many terms of this series do you have to use before you first get 3.14? 3.141? 3.1415? 3.14159?

#include <stdio.h>
#include <math.h>
int main(void) {
// Set the initial value of pi to 0
double pi = 0.0;
// Set the initial value of the term to 1
double term = 1.0;
// Set the initial value of the divisor to 1
double divisor = 1.0;
// Print the table header
printf("%10s%25s\n", "Number of terms", "Approximation of pi");
// Calculate and print the approximations of pi
for (int i = 1; i <= 20; i++) {
pi += term / divisor;
printf("%10d%25.10f\n", i, pi*4.0);
term *= -1.0;
divisor += 2.0;
}
return 0;
}
I tried to correct the code but still can't get closer to the value as it is ask by my teacher in our assignment...
The Question is..
Calculate the value of π from the infinite series. Print a table that
shows the value of π approximated by one term of this series, by two terms, by three terms,
and so on. How many terms of this series do you have to use before you first get 3.14?
3.141? 3.1415? 3.14159?
How many terms of this series do you have to use before you first get 3.14? 3.141? 3.1415? 3.14159?
The details of "first get 3.14" are a bit unclear. Below attempts something like OP's goal and illustrates the slow convergence as computation time is proportional to the number of terms.
The high number of terms, each incurring round-off errors in the division and addition eventually render this computation too inaccurate for high term count.
int main(void) {
double pi_true = 3.1415926535897932384626433832795;
double threshold = 0.5;
int dp = 0;
// Set the initial value of pi to 0
double pi = 0.0;
// Set the initial value of the term to 1
double term = 1.0;
// Set the initial value of the divisor to 1
double divisor = 1.0;
// Print the table header
printf("%7s %12s %-25.16f\n", "", "", pi_true);
printf("%7s %12s %-25s\n", "", "# of terms", "Approximation of pi");
// Calculate and print the approximations of pi
for (long long i = 1; ; i++) {
pi += term / divisor;
double diff = fabs(4*pi - pi_true);
if (diff <= threshold) {
printf("%7.1e %12lld %-25.16f %-25.*f\n", diff, i, pi * 4.0, dp++, pi * 4.0);
fflush(stdout);
threshold /= 10;
if (4*pi == pi_true) {
break;
}
}
term *= -1.0;
divisor += 2.0;
}
puts("Done");
return 0;
}
Output
3.1415926535897931
# of terms Approximation of pi
4.7e-01 2 2.6666666666666670 3
5.0e-02 20 3.0916238066678399 3.1
5.0e-03 200 3.1365926848388161 3.14
5.0e-04 2000 3.1410926536210413 3.141
5.0e-05 20000 3.1415426535898248 3.1415
5.0e-06 200001 3.1415976535647618 3.14160
5.0e-07 2000001 3.1415931535894743 3.141593
5.0e-08 19999992 3.1415926035897974 3.1415926
5.0e-09 199984633 3.1415926585897931 3.14159266
5.0e-10 1993125509 3.1415926540897927 3.141592654
5.0e-11 19446391919 3.1415926536397927 3.1415926536
...
Ref 3.1415926535897931
On a 2nd attempt, perhaps this is closer to OP's goal
int main(void) {
double pi_true = 3.1415926535897932384626433832795;
double threshold_lo = 2.5;
double threshold_hi = 3.5;
double error_band = 0.5;
int dp = 0;
// Set the initial value of pi to 0
double pi = 0.0;
// Set the initial value of the term to 4
double term = 4.0;
// Set the initial value of the divisor to 1
double divisor = 1.0;
// Print the table header
printf("%12s %-25.16f\n", "", pi_true);
printf("%12s %-25s\n", "# of terms", "Approximation of pi");
// Calculate and print the approximations of pi
for (long long i = 1;; i++) {
pi += term / divisor;
if (pi > threshold_lo && pi < threshold_hi) {
printf("%12lld %-25.16f %-25.*f\n", i, pi, dp++, pi);
fflush(stdout);
char buf[100] = "3.1415926535897932384626433832795";
buf[dp + 2] = 0;
error_band /= 10.0;
double target = atof(buf);
threshold_lo = target - error_band;
threshold_hi = target + error_band;
}
term *= -1.0;
divisor += 2.0;
}
puts("Done");
return 0;
}
Output
3.1415926535897931
# of terms Approximation of pi
2 2.6666666666666670 3
12 3.0584027659273332 3.1
152 3.1350137774059244 3.14
916 3.1405009508583017 3.141
7010 3.1414500002381582 3.1415
130658 3.1415850000208838 3.14159
866860 3.1415915000009238 3.141592
9653464 3.1415925500000141 3.1415926
116423306 3.1415926450000007 3.14159265
919102060 3.1415926525000004 3.141592653
7234029994 3.1415926534500005 3.1415926535

Calculate the value of 𝜋 from the infinite series in 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.

Estimating the value of Pi using the Monte Carlo Method

I am writing a C program that will be able to accept an input value that dictates the number of iterations that will be used to estimate Pi.
For example, the number of points to be created as the number of iterations increases and the value of Pi also.
Here is the code I have so far:
#include <stdio.h>
#include <stdlib.h>
main()
{
const double pp = (double)RAND_MAX * RAND_MAX;
int innerPoint = 0, i, count;
printf("Enter the number of points:");
scanf("%d", &innerPoint);
for (i = 0; i < count; ++i){
float x = rand();
float y = rand();
if (x * x + y * y <= 1){
++innerPoint;
}
int ratio = 4 *(innerPoint/ i);
printf("Pi value is:", ratio);
}
}
Help fix my code as I'm facing program errors.
rand() returns an integer [0...RAND_MAX].
So something like:
float x = rand()*scale; // Scale is about 1.0/RAND_MAX
The quality of the Monte Carlo method is dependent on a good random number generator. rand() may not be that good, but let us assume it is a fair random number generator for this purpose.
The range of [0...RAND_MAX] is RAND_MAX+1 different values that should be distributed evenly from [0.0...1.0].
((float) rand())/RAND_MAX biases the end points 0.0 and 1.0 giving them twice the weight of others.
Consider instead [0.5, 1.5, 2.5, ... RAND_MAX + 0.5]/(RAND_MAX + 1).
RAND_MAX may exceed the precision of float so converting rand() or RAND_MAX, both int, to float can incurring rounding and further disturb the Monte Carlo method. Consider double.
#define RAND_MAX_P1 ((double)RAND_MAX + 1.0)
// float x = rand();
double x = ((double) rand() + 0.5)/RAND_MAX_P1;
x * x + y * y can also incur excessive rounding. C has hypot(x,y) for a better precision sqrt(x*x + y*y). Yet here, with small count, it likely makes no observable difference.
// if (x * x + y * y <= 1)
if (hypot(x, y <= 1.0))
I am sure it is not the best solution, but it should do the job and is similar to your code. Use a sample size of at least 10000 to get a value near PI.
As mentioned in the commenter: You should look at the data types of the return values functions give you.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main()
{
// Initialize random number generation
srand(time(NULL));
int samples = 10000;
int points_inside =0;
// Read integer - sample size (use at least 10000 to get near PI)
printf("Enter the number of points:");
scanf("%d", &samples);
for (int i = 0; i < samples; ++i){
// Get two numbers between 0 and 1
float x = (float) rand() / (float)RAND_MAX;
float y = (float) rand() / (float)RAND_MAX;
// Check if point is inside
if (x * x + y * y <= 1){
points_inside++;
}
// Calculate current ratio
float current_ratio = 4 * ((float) points_inside / (float) i);
printf("Current value of pi value is: %f \n", current_ratio);
}
}

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.

Calculating Maxwell-Boltzmann Distribution

I am trying to calculate Maxwell-Boltzmann Distribution but this code gives 0.00000, what is the problem?
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
int main()
{
float e=2.718228183, pi=3.14159265, m=2.66*pow(10,-23), t, k=1.38*pow(10,-23), v, result;
scanf("%f %f", &t, &v);
result = sqrt(pow( m / (2*pi*k*t), 3)) * 4 * pi * pow(v,2) * pow(e, -(m * pow(v,2)) / (2*k*t));
printf("%f", result);
}
As described in the comments, the use of float together with the reduced precision of the constants give a result that is not representable anymore as a float. Changing the data type to double alone gives two decimal digits of accuracy. If we use exp, more digits for pi and do a bit of recombination of the computations we get 12 digits of accuracy. E.g.:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main()
{
double pi = 3.1415926535897932384626433832795028842, m = 2.66e-23, k =
1.38e-23;
double t, v, v2, dkt, result;
// check omitted
scanf("%lf %lf", &t, &v);
v2 = v * v;
dkt = 2 * k * t;
result = pow(m / (pi * dkt), 3 / 2.0) * 4 * pi * v2 * exp(-(m * v2) / (dkt));
printf("%.20g\n", result);
return 0;
}
The result from Pari/GP is 8.1246636077915008261803395870165527173e-9 and the result we get with the code above is 8.1246636077914841125e-09. Without the intermediate results v2, dkt and the replacement of sqrt we got 8.1246636077914824582e-09, not much of a difference, especially with accuracy where it gained nothing.
If you want the full 16 decimal digits of accuracy you need to take the whole thing apart and take a different approach.
replace
double pi=acos(-1.);
instead of
double pi=3.1415926535897932384626433832795028842;

Resources