How to resolve the algorithm Euler's constant 0.5772... step by step in the C programming language
How to resolve the algorithm Euler's constant 0.5772... step by step in the C programming language
Table of Contents
Problem Statement
Compute the Euler constant 0.5772... Discovered by Leonhard Euler around 1730, it is the most ubiquitous mathematical constant after pi and e, but appears more arcane than these. Denoted gamma (γ), it measures the amount by which the partial sums of the harmonic series (the simplest diverging series) differ from the logarithmic function (its approximating integral): lim n → ∞ (1 + 1/2 + 1/3 + … + 1/n − log(n)). The definition of γ converges too slowly to be numerically useful, but in 1735 Euler himself applied his recently discovered summation formula to compute ‘the notable number’ accurate to 15 places. For a single-precision implementation this is still the most economic algorithm. In 1961, the young Donald Knuth used Euler's method to evaluate γ to 1271 places. Knuth found that the computation of the Bernoulli numbers required in the Euler-Maclaurin formula was the most time-consuming part of the procedure. The next year Dura Sweeney computed 3566 places, using a formula based on the expansion of the exponential integral which didn't need Bernoulli numbers. It's a bit-hungry method though: 2d digits of working precision obtain d correct places only. This was remedied in 1988 by David Bailey; meanwhile Richard Brent and Ed McMillan had published an even more efficient algorithm based on Bessel function identities and found 30100 places in 20 hours time. Nowadays the old records have far been exceeded: over 6·1011 decimal places are already known. These massive computations suggest that γ is neither rational nor algebraic, but this is yet to be proven.
[1] Gourdon and Sebah, The Euler constant γ. (for all formulas) [2] Euler's original journal article translated from the latin (p. 9)
Let's start with the solution:
Step by Step solution about How to resolve the algorithm Euler's constant 0.5772... step by step in the C programming language
Source Code 1
This C program provides a comparison of five methods for computing Euler's constant, denoted as gamma in the code. Euler's constant is approximately 0.5772156649.
Explanation:
-
Initialization: The program defines a precision value
eps
to control the accuracy of the calculations. It also sets up data structures and variables for each of the five methods. -
Method 1:
- The first method computes Euler's constant using the definition as the limit of the harmonic series.
- It calculates
h
as the sum of reciprocals from 1 ton
. a
is computed aslog(n + 0.5 + 1/(24*n))
.- The difference between
h
anda
is the error in this method.
-
Method 2:
- This method is due to Sweeney (1963).
- It initializes
s
as an array of two doubles:s[0] = 0
ands[1] = n
. - It iterates until
r
becomes less thaneps
. - In each iteration, it updates
r
,k
, ands
. - The final value of
gamma
iss[1] - s[0] - log(n)
.
-
Method 3:
- This method is due to Bailey (1988).
- It initializes
a
,h
,n2
,r
,k
, andb
. - It iterates until the absolute difference between
a
andb
is less thaneps
. - In each iteration, it updates
a
,h
,b
,r
, andk
. - The final value of
gamma
isa - n * log(2)
.
-
Method 4:
- This method is due to Brent and McMillan (1980).
- It initializes
a
,b
,u
,v
,n2
,k2
,k
, andm
. - It iterates until the absolute value of
a
is less thaneps
. - In each iteration, it updates
k2
,k
,a
,b
,u
, andv
. - The final value of
gamma
isu / v
.
-
Method 5:
- This method is based on Euler's original method from 1735.
- It uses the Bernoulli numbers with even indices to compute
C
as a correction to the harmonic sum. - It calculates
h
,h - log(n)
, and then addsC
to get the final value ofgamma
.
-
Output: The program prints the results of all five methods along with the number of iterations required for each method. It also prints the true value of Euler's constant for comparison.
Source Code 2
This C program uses the Brent-McMillan algorithm to compute Euler's constant with arbitrary precision using the GNU Multiple Precision Library (GMP).
Explanation:
-
Initialization: The program defines precision parameters
e10
ande2
to control the accuracy of the calculations. It also initializes the GMP multi-precision float pointersu
,v
, andk2
. -
Function
ln
: This function computes the natural logarithm using the Taylor series foratanh(x-y/x+y)
whenx - y = 1
. -
Main Function:
- The program defines various unsigned long integers and sets
n
,r
,s
, andt
based on a chosen precision level. - It computes
a
as the sum of multiples of the logarithms of16/15
,25/24
, and81/80
. - It initializes
a
,b
,u
,v
, andk2
and iterates the Brent-McMillan algorithm until the absolute error is less thaneps
. - In each iteration, it updates
k2
,b
,a
,u
, andv
. - Finally, it prints the computed value of Euler's constant and the number of iterations required.
- The program defines various unsigned long integers and sets
Source Code 3
This C program also uses the GNU Multi-Precision Floating-Point Reliable Library (MPFR) to compute Euler's constant with arbitrary precision.
Explanation:
-
Initialization: The program sets the decimal precision to 100 and the binary precision accordingly. It initializes the MPFR multi-precision float pointer
a
. -
Main Function:
- The program uses the
mpfr_const_euler
function to compute Euler's constant and stores it ina
. - It prints the computed value of Euler's constant and the time taken for the computation.
- The program uses the
Source code in the c programming language
/*********************************************
Subject: Comparing five methods for
computing Euler's constant 0.5772...
tested : tcc-0.9.27
--------------------------------------------*/
#include <math.h>
#include <stdio.h>
#define eps 1e-6
int main(void) {
double a, b, h, n2, r, u, v;
int k, k2, m, n;
printf("From the definition, err. 3e-10\n");
n = 400;
h = 1;
for (k = 2; k <= n; k++) {
h += 1.0 / k;
}
//faster convergence: Negoi, 1997
a = log(n +.5 + 1.0 / (24*n));
printf("Hn %.16f\n", h);
printf("gamma %.16f\nk = %d\n\n", h - a, n);
printf("Sweeney, 1963, err. idem\n");
n = 21;
double s[] = {0, n};
r = n;
k = 1;
do {
k += 1;
r *= (double) n / k;
s[k & 1] += r / k;
} while (r > eps);
printf("gamma %.16f\nk = %d\n\n", s[1] - s[0] - log(n), k);
printf("Bailey, 1988\n");
n = 5;
a = 1;
h = 1;
n2 = pow(2,n);
r = 1;
k = 1;
do {
k += 1;
r *= n2 / k;
h += 1.0 / k;
b = a; a += r * h;
} while (fabs(b - a) > eps);
a *= n2 / exp(n2);
printf("gamma %.16f\nk = %d\n\n", a - n * log(2), k);
printf("Brent-McMillan, 1980\n");
n = 13;
a = -log(n);
b = 1;
u = a;
v = b;
n2 = n * n;
k2 = 0;
k = 0;
do {
k2 += 2*k + 1;
k += 1;
a *= n2 / k;
b *= n2 / k2;
a = (a + b) / k;
u += a;
v += b;
} while (fabs(a) > eps);
printf("gamma %.16f\nk = %d\n\n", u / v, k);
printf("How Euler did it in 1735\n");
//Bernoulli numbers with even indices
double B2[] = {1.0,1.0/6,-1.0/30,1.0/42,-1.0/30,\
5.0/66,-691.0/2730,7.0/6,-3617.0/510,43867.0/798};
m = 7;
if (m > 9) return(0);
n = 10;
//n-th harmonic number
h = 1;
for (k = 2; k <= n; k++) {
h += 1.0 / k;
}
printf("Hn %.16f\n", h);
h -= log(n);
printf(" -ln %.16f\n", h);
//expansion C = -digamma(1)
a = -1.0 / (2*n);
n2 = n * n;
r = 1;
for (k = 1; k <= m; k++) {
r *= n2;
a += B2[k] / (2*k * r);
}
printf("err %.16f\ngamma %.16f\nk = %d", a, h + a, n + m);
printf("\n\nC = 0.57721566490153286...\n");
}
/**************************************************
Subject: Computation of Euler's constant 0.5772...
with the Brent-McMillan algorithm B1,
Math. Comp. 34 (1980), 305-312
tested : tcc-0.9.27 with gmp 6.2.0
-------------------------------------------------*/
#include <gmp.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
//multi-precision float pointers
mpf_ptr u, v, k2;
//precision parameters
unsigned long e10, e2;
long e;
double f;
//log(x/y) with the Taylor series for atanh(x-y/x+y)
void ln (mpf_ptr s, unsigned long x, unsigned long y) {
mpf_ptr d = u, q = v;
unsigned long k;
//Möbius transformation
k = x; x -= y; y += k;
if (x != 1) {
printf ("ln: illegal argument x - y != 1");
exit;
}
//s = 1 / (x + y)
mpf_set_ui (s, y);
mpf_ui_div (s, 1, s);
//k2 = s * s
mpf_mul (k2, s, s);
mpf_set (d, s);
k = 1;
do {
k += 2;
//d *= k2
mpf_mul (d, d, k2);
//q = d / k
mpf_div_ui (q, d, k);
//s += q
mpf_add (s, s, q);
f = mpf_get_d_2exp (&e, q);
} while (abs(e) < e2);
//s *= 2
mpf_mul_2exp (s, s, 1);
}
int main (void) {
mpf_ptr a = malloc(sizeof(__mpf_struct));
mpf_ptr b = malloc(sizeof(__mpf_struct));
u = malloc(sizeof(__mpf_struct));
v = malloc(sizeof(__mpf_struct));
k2 = malloc(sizeof(__mpf_struct));
//unsigned long integers
unsigned long k, n, n2, r, s, t;
clock_t tim = clock();
// n = 2^i * 3^j * 5^k
// log(n) = r * log(16/15) + s * log(25/24) + t * log(81/80)
// solve linear system for r, s, t
// 4 -3 -4| i
// -1 -1 4| j
// -1 2 -1| k
//examples
t = 1;
switch (t) {
case 1 :
n = 60;
r = 41;
s = 30;
t = 18;
//100 digits
break;
case 2 :
n = 4800;
r = 85;
s = 62;
t = 37;
//8000 digits, 0.6 s
break;
case 3 :
n = 9375;
r = 91;
s = 68;
t = 40;
//15625 digits, 2.5 s
break;
default :
n = 18750;
r = 98;
s = 73;
t = 43;
//31250 digits, 12 s. @2.00GHz
}
//decimal precision
e10 = n / .6;
//binary precision
e2 = (1 + e10) / .30103;
//initialize mpf's
mpf_set_default_prec (e2);
mpf_inits (a, b, u, v, k2, (mpf_ptr)0);
//Compute log terms
ln (b, 16, 15);
//a = r * b
mpf_mul_ui (a, b, r);
ln (b, 25, 24);
//a += s * b
mpf_mul_ui (u, b, s);
mpf_add (a, a, u);
ln (b, 81, 80);
//a += t * b
mpf_mul_ui (u, b, t);
mpf_add (a, a, u);
//gmp_printf ("log(%lu) %.*Ff\n", n, e10, a);
//B&M, algorithm B1
//a = -a, b = 1
mpf_neg (a, a);
mpf_set_ui (b, 1);
mpf_set (u, a);
mpf_set (v, b);
k = 0;
n2 = n * n;
//k2 = k * k
mpf_set_ui (k2, 0);
do {
//k2 += 2k + 1
mpf_add_ui (k2, k2, (k << 1) + 1);
k += 1;
//b = b * n2 / k2
mpf_div (b, b, k2);
mpf_mul_ui (b, b, n2);
//a = (a * n2 / k + b) / k
mpf_div_ui (a, a, k);
mpf_mul_ui (a, a, n2);
mpf_add (a, a, b);
mpf_div_ui (a, a, k);
//u += a, v += b
mpf_add (u, u, a);
mpf_add (v, v, b);
f = mpf_get_d_2exp (&e, a);
} while (abs(e) < e2);
mpf_div (u, u, v);
gmp_printf ("gamma %.*Ff (maxerr. 1e-%lu)\n", e10, u, e10);
gmp_printf ("k = %lu\n\n", k);
tim = clock() - tim;
printf("time: %.7f s\n",((double)tim)/CLOCKS_PER_SEC);
}
/*******************************************
Subject: Euler's constant 0.5772...
tested : tcc-0.9.27 with mpfr 4.1.0
------------------------------------------*/
#include <gmp.h>
#include <mpfr.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main (void) {
mpfr_ptr a = malloc(sizeof(__mpfr_struct));
unsigned long e2, e10;
clock_t tim = clock();
//decimal precision
e10 = 100;
//binary precision
e2 = (1 + e10) / .30103;
mpfr_init2 (a, e2);
mpfr_const_euler (a, MPFR_RNDN);
mpfr_printf ("gamma %.*Rf\n\n", e10, a);
tim = clock() - tim;
gmp_printf ("time: %.7f s\n",((double)tim)/CLOCKS_PER_SEC);
}
You may also check:How to resolve the algorithm Compile-time calculation step by step in the OCaml programming language
You may also check:How to resolve the algorithm Environment variables step by step in the Common Lisp programming language
You may also check:How to resolve the algorithm Array concatenation step by step in the MiniScript programming language
You may also check:How to resolve the algorithm Align columns step by step in the Beads programming language
You may also check:How to resolve the algorithm Stair-climbing puzzle step by step in the C# programming language