| 1 |
/** Calculate pi at compile time |
|---|
| 2 |
* |
|---|
| 3 |
* Compile with dmd -c pi.d |
|---|
| 4 |
*/ |
|---|
| 5 |
module calcpi; |
|---|
| 6 |
|
|---|
| 7 |
import meta.math; |
|---|
| 8 |
import meta.conv; |
|---|
| 9 |
|
|---|
| 10 |
/** real evaluateSeries!(real x, real metafunction!(real y, int n) term) |
|---|
| 11 |
* |
|---|
| 12 |
* Evaluate a power series at compile time. |
|---|
| 13 |
* |
|---|
| 14 |
* Given a metafunction of the form |
|---|
| 15 |
* real term!(real y, int n), |
|---|
| 16 |
* which gives the nth term of a convergent series at the point y |
|---|
| 17 |
* (where the first term is n==1), and a real number x, |
|---|
| 18 |
* this metafunction calculates the infinite sum at the point x |
|---|
| 19 |
* by adding terms until the sum doesn't change any more. |
|---|
| 20 |
*/ |
|---|
| 21 |
template evaluateSeries(real x, alias term, int n=1, real sumsofar=0.0) |
|---|
| 22 |
{ |
|---|
| 23 |
static if (n>1 && sumsofar == sumsofar + term!(x, n+1)) { |
|---|
| 24 |
const real evaluateSeries = sumsofar; |
|---|
| 25 |
} else { |
|---|
| 26 |
const real evaluateSeries = evaluateSeries!(x, term, n+1, sumsofar + term!(x, n)); |
|---|
| 27 |
} |
|---|
| 28 |
} |
|---|
| 29 |
|
|---|
| 30 |
/*** Calculate atan(x) at compile time. |
|---|
| 31 |
* |
|---|
| 32 |
* Uses the Maclaurin formula |
|---|
| 33 |
* atan(z) = z - z^3/3 + Z^5/5 - Z^7/7 + ... |
|---|
| 34 |
*/ |
|---|
| 35 |
template atan(real z) |
|---|
| 36 |
{ |
|---|
| 37 |
const real atan = evaluateSeries!(z, atanTerm); |
|---|
| 38 |
} |
|---|
| 39 |
|
|---|
| 40 |
template atanTerm(real x, int n) |
|---|
| 41 |
{ |
|---|
| 42 |
const real atanTerm = (n & 1 ? 1 : -1) * pow!(x, 2*n-1)/(2*n-1); |
|---|
| 43 |
} |
|---|
| 44 |
|
|---|
| 45 |
/// Machin's formula for pi |
|---|
| 46 |
/// pi/4 = 4 atan(1/5) - atan(1/239). |
|---|
| 47 |
pragma(msg, "PI = " ~ fcvt!(4.0 * (4*atan!(1/5.0) - atan!(1/239.0))) ); |
|---|