line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package ConstantCalculus::CircleConstant; |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
# Set the VERSION. |
4
|
|
|
|
|
|
|
our $VERSION = "0.03"; |
5
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
# Load the Perl pragmas. |
7
|
1
|
|
|
1
|
|
75236
|
use 5.008009; |
|
1
|
|
|
|
|
4
|
|
8
|
1
|
|
|
1
|
|
11
|
use strict; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
20
|
|
9
|
1
|
|
|
1
|
|
11
|
use warnings; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
50
|
|
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
# Load the Perl pragma Exporter. |
12
|
1
|
|
|
1
|
|
11
|
use vars qw(@ISA @EXPORT @EXPORT_OK); |
|
1
|
|
|
|
|
12
|
|
|
1
|
|
|
|
|
75
|
|
13
|
1
|
|
|
1
|
|
10
|
use Exporter 'import'; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
132
|
|
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
# Base class of this module. |
16
|
|
|
|
|
|
|
our @ISA = qw(Exporter); |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
# Exporting the implemented subroutine. |
19
|
|
|
|
|
|
|
our @EXPORT = qw( |
20
|
|
|
|
|
|
|
chudnovsky_algorithm |
21
|
|
|
|
|
|
|
borwein25_algorithm |
22
|
|
|
|
|
|
|
pi_borwein25 |
23
|
|
|
|
|
|
|
tau_borwein25 |
24
|
|
|
|
|
|
|
pi_chudnovsky |
25
|
|
|
|
|
|
|
tau_chudnovsky |
26
|
|
|
|
|
|
|
bbp_algorithm |
27
|
|
|
|
|
|
|
bbp_digits |
28
|
|
|
|
|
|
|
bbp_digit |
29
|
|
|
|
|
|
|
S |
30
|
|
|
|
|
|
|
$PI_DEC |
31
|
|
|
|
|
|
|
$PI_HEX |
32
|
|
|
|
|
|
|
); |
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
# Exporting subroutines on demand basis. |
35
|
|
|
|
|
|
|
@EXPORT_OK = qw( |
36
|
|
|
|
|
|
|
factorial |
37
|
|
|
|
|
|
|
sqrtroot |
38
|
|
|
|
|
|
|
modexp |
39
|
|
|
|
|
|
|
estimate_terms |
40
|
|
|
|
|
|
|
truncate_places |
41
|
|
|
|
|
|
|
); |
42
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
# Disable a warning. |
44
|
1
|
|
|
1
|
|
7
|
no warnings 'recursion'; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
42
|
|
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
# Load the Perl module. |
47
|
1
|
|
|
1
|
|
654
|
use bignum; |
|
1
|
|
|
|
|
5686
|
|
|
1
|
|
|
|
|
11
|
|
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
# Set the precision for bignum. |
50
|
|
|
|
|
|
|
bignum -> precision(-14); |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
# Initialise pre-defined values of Pi. |
53
|
|
|
|
|
|
|
our $PI_DEC = undef; |
54
|
|
|
|
|
|
|
our $PI_HEX = undef; |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
# Initialise the array with the hexadecimal numbers. |
57
|
|
|
|
|
|
|
our @HX = ("0", "1", "2", "3", "4", "5", "6", "7", |
58
|
|
|
|
|
|
|
"8", "9", "A", "B", "C", "D", "E", "F"); |
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
# ---------------------------------------------------------------------------- # |
61
|
|
|
|
|
|
|
# Subroutine modexp() # |
62
|
|
|
|
|
|
|
# # |
63
|
|
|
|
|
|
|
# Description: # |
64
|
|
|
|
|
|
|
# The subroutine returns the result of a modular exponentiation. A modular # |
65
|
|
|
|
|
|
|
# exponentiation is an exponentiation applied over a modulus. The result of # |
66
|
|
|
|
|
|
|
# the modular exponentiation is the remainder when an integer b (the base) # |
67
|
|
|
|
|
|
|
# is exponentiated by e (the exponent) and divided by a positive integer m # |
68
|
|
|
|
|
|
|
# (modulus). # |
69
|
|
|
|
|
|
|
# # |
70
|
|
|
|
|
|
|
# @params $b Value of the base # |
71
|
|
|
|
|
|
|
# $e Value of the exponent # |
72
|
|
|
|
|
|
|
# $m Value of the modulus # |
73
|
|
|
|
|
|
|
# @returns $y Result of the modular exponentiation # |
74
|
|
|
|
|
|
|
# ---------------------------------------------------------------------------- # |
75
|
|
|
|
|
|
|
sub modexp { |
76
|
|
|
|
|
|
|
# Assign the subroutine arguments to the local variables. |
77
|
0
|
|
|
0
|
1
|
0
|
my($b, $e, $m) = @_; |
78
|
|
|
|
|
|
|
# Initialise the return variable. |
79
|
0
|
|
|
|
|
0
|
my $y = 1; |
80
|
|
|
|
|
|
|
# Perfom the modular exponentiation. |
81
|
0
|
|
|
|
|
0
|
do { |
82
|
0
|
0
|
|
|
|
0
|
($y *= $b) %= $m if ($e % 2); |
83
|
0
|
|
|
|
|
0
|
($b *= $b) %= $m; |
84
|
|
|
|
|
|
|
} while ($e = ($e/2) - (($e/2) % 1)); |
85
|
|
|
|
|
|
|
# Return the result of the modular exponentiation. |
86
|
0
|
|
|
|
|
0
|
return $y; |
87
|
|
|
|
|
|
|
}; |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
# ---------------------------------------------------------------------------- # |
90
|
|
|
|
|
|
|
# Subroutine sqrtroot() # |
91
|
|
|
|
|
|
|
# # |
92
|
|
|
|
|
|
|
# Description: # |
93
|
|
|
|
|
|
|
# The subroutine calculates the square root of given number. # |
94
|
|
|
|
|
|
|
# # |
95
|
|
|
|
|
|
|
# @params $x Number for which the square root is sought # |
96
|
|
|
|
|
|
|
# @returns $y Square root of the given number $x # |
97
|
|
|
|
|
|
|
# ---------------------------------------------------------------------------- # |
98
|
|
|
|
|
|
|
sub sqrtroot { |
99
|
|
|
|
|
|
|
# Assign the subroutine argument to the local variable. |
100
|
0
|
|
|
0
|
1
|
0
|
my $x = $_[0]; |
101
|
|
|
|
|
|
|
# Set the start values for the iteration. |
102
|
0
|
|
|
|
|
0
|
my $y = 1; |
103
|
0
|
|
|
|
|
0
|
my $y0 = 0; |
104
|
|
|
|
|
|
|
# Initialise the loop variables. |
105
|
0
|
|
|
|
|
0
|
my $i = 0; |
106
|
0
|
|
|
|
|
0
|
my $run = 1; |
107
|
|
|
|
|
|
|
# Run an infinite loop until the exit conditions is reached. |
108
|
0
|
|
|
|
|
0
|
while ($run == 1) { |
109
|
|
|
|
|
|
|
# Calculate the approximation. |
110
|
0
|
|
|
|
|
0
|
$y -= ($y * $y - $x) / (2 * $y); |
111
|
|
|
|
|
|
|
# Check the exit condition. |
112
|
0
|
0
|
|
|
|
0
|
$run = ($y0 == $y ? 0 : 1); |
113
|
|
|
|
|
|
|
# Save the approximation. |
114
|
0
|
|
|
|
|
0
|
$y0 = $y; |
115
|
|
|
|
|
|
|
# Increment the running variable. |
116
|
0
|
|
|
|
|
0
|
$i++; |
117
|
|
|
|
|
|
|
}; |
118
|
|
|
|
|
|
|
# Return the square root. |
119
|
0
|
|
|
|
|
0
|
return $y; |
120
|
|
|
|
|
|
|
}; |
121
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
# ---------------------------------------------------------------------------- # |
123
|
|
|
|
|
|
|
# Subroutine factorial() # |
124
|
|
|
|
|
|
|
# # |
125
|
|
|
|
|
|
|
# Description: # |
126
|
|
|
|
|
|
|
# The subroutine calculates the factorial of given number. # |
127
|
|
|
|
|
|
|
# # |
128
|
|
|
|
|
|
|
# @params $n Number for which the factorial is sought # |
129
|
|
|
|
|
|
|
# @returns $fact Factorial of the given number $n # |
130
|
|
|
|
|
|
|
# ---------------------------------------------------------------------------- # |
131
|
|
|
|
|
|
|
sub factorial { |
132
|
|
|
|
|
|
|
# Assign the subroutine argument to the local variable. |
133
|
0
|
|
|
0
|
1
|
0
|
my $n = $_[0]; |
134
|
|
|
|
|
|
|
# Calculate the factorial of a number by recursion. |
135
|
0
|
0
|
|
|
|
0
|
my $fact = ($n == 0 ? 1 : factorial($n - 1) * $n); |
136
|
|
|
|
|
|
|
# Return the value of the factorial. |
137
|
0
|
|
|
|
|
0
|
return $fact; |
138
|
|
|
|
|
|
|
}; |
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
# ---------------------------------------------------------------------------- # |
141
|
|
|
|
|
|
|
# Subroutine truncate_places() # |
142
|
|
|
|
|
|
|
# ---------------------------------------------------------------------------- # |
143
|
|
|
|
|
|
|
sub truncate_places { |
144
|
|
|
|
|
|
|
# Assign the subroutine arguments to the local variables. |
145
|
0
|
|
|
0
|
1
|
0
|
my $decimal = $_[0]; |
146
|
0
|
|
|
|
|
0
|
my $places = $_[1]; |
147
|
|
|
|
|
|
|
# Calculate the multiplication factor. |
148
|
0
|
|
|
|
|
0
|
my $factor = 10**$places; |
149
|
|
|
|
|
|
|
# Truncate the places using the multiplication factor. |
150
|
0
|
|
|
|
|
0
|
$decimal = int($decimal*$factor) / ($factor); |
151
|
|
|
|
|
|
|
# Truncate the decimal using the places plus two chars. |
152
|
0
|
|
|
|
|
0
|
$decimal = substr($decimal, 0, $places + 2); |
153
|
|
|
|
|
|
|
# Return the truncated decimal number. |
154
|
0
|
|
|
|
|
0
|
return $decimal; |
155
|
|
|
|
|
|
|
}; |
156
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
# ---------------------------------------------------------------------------- # |
158
|
|
|
|
|
|
|
# Subroutine estimate_terms() # |
159
|
|
|
|
|
|
|
# ---------------------------------------------------------------------------- # |
160
|
|
|
|
|
|
|
sub estimate_terms { |
161
|
|
|
|
|
|
|
# Assign the subroutine arguments to the local variables. |
162
|
0
|
0
|
|
0
|
1
|
0
|
my $places = (defined $_[0] ? $_[0] : 0); |
163
|
0
|
0
|
|
|
|
0
|
my $new_places = (defined $_[1] ? $_[1] : 0); |
164
|
|
|
|
|
|
|
# Declare the return variable. |
165
|
0
|
|
|
|
|
0
|
my $number_terms = undef; |
166
|
|
|
|
|
|
|
# Determine the estimated number of terms. |
167
|
0
|
0
|
|
|
|
0
|
if ($places <= 1) { |
|
|
0
|
|
|
|
|
|
168
|
0
|
|
|
|
|
0
|
$number_terms = $places; |
169
|
|
|
|
|
|
|
} elsif ($places <= $new_places) { |
170
|
0
|
|
|
|
|
0
|
$number_terms = 1; |
171
|
|
|
|
|
|
|
} else { |
172
|
0
|
|
|
|
|
0
|
$number_terms = int($places / $new_places) + 1; |
173
|
|
|
|
|
|
|
}; |
174
|
|
|
|
|
|
|
# Return the estimated number of terms. |
175
|
0
|
|
|
|
|
0
|
return $number_terms; |
176
|
|
|
|
|
|
|
}; |
177
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
#------------------------------------------------------------------------------# |
179
|
|
|
|
|
|
|
# Subroutine is_unsigned_int() # |
180
|
|
|
|
|
|
|
#------------------------------------------------------------------------------# |
181
|
|
|
|
|
|
|
sub is_unsigned_int { |
182
|
|
|
|
|
|
|
# Assign the subroutine argument to the local variable. |
183
|
0
|
0
|
|
0
|
0
|
0
|
my $arg = (defined $_[0] ? $_[0] : ''); |
184
|
|
|
|
|
|
|
# Set the Perl conform regex pattern. |
185
|
0
|
|
|
|
|
0
|
my $re = qr/^(([1-9][0-9]*)|0)$/; |
186
|
|
|
|
|
|
|
# Check the argument with the regex pattern. |
187
|
0
|
0
|
|
|
|
0
|
my $is_unsigned_int = (($arg =~ $re) ? 1 : 0); |
188
|
|
|
|
|
|
|
# Return 0 (false) or 1 (true). |
189
|
0
|
|
|
|
|
0
|
return $is_unsigned_int; |
190
|
|
|
|
|
|
|
}; |
191
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
# ---------------------------------------------------------------------------- # |
193
|
|
|
|
|
|
|
# Subroutine check_places() # |
194
|
|
|
|
|
|
|
# ---------------------------------------------------------------------------- # |
195
|
|
|
|
|
|
|
sub check_places { |
196
|
|
|
|
|
|
|
# Assign the subroutine argument to the local variable. |
197
|
0
|
0
|
|
0
|
0
|
0
|
my $places = (defined $_[0] ? $_[0] : 0); |
198
|
|
|
|
|
|
|
# Set the string for the farewell message. |
199
|
0
|
|
|
|
|
0
|
my $msg = "The number of places is not valid. Terminating processing. Bye!"; |
200
|
|
|
|
|
|
|
# Check if the given places are a valid number. |
201
|
0
|
0
|
|
|
|
0
|
if (is_unsigned_int($places) != 1) { |
202
|
|
|
|
|
|
|
# Print a message into the terminal window. |
203
|
0
|
|
|
|
|
0
|
print $msg . "\n"; |
204
|
|
|
|
|
|
|
# Exit the script. |
205
|
0
|
|
|
|
|
0
|
exit; |
206
|
|
|
|
|
|
|
}; |
207
|
|
|
|
|
|
|
# Return 1 (true). |
208
|
0
|
|
|
|
|
0
|
return 1; |
209
|
|
|
|
|
|
|
}; |
210
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
# ---------------------------------------------------------------------------- # |
212
|
|
|
|
|
|
|
# Subroutine S() # |
213
|
|
|
|
|
|
|
# ---------------------------------------------------------------------------- # |
214
|
|
|
|
|
|
|
sub S { |
215
|
|
|
|
|
|
|
# Assign the subroutine arguments to local variables. |
216
|
0
|
|
|
0
|
1
|
0
|
my ($j, $n, $p) = @_; |
217
|
|
|
|
|
|
|
# Set the precision for bignum. |
218
|
0
|
|
|
|
|
0
|
bignum -> precision(-$p); |
219
|
|
|
|
|
|
|
# Initialise the local variables. |
220
|
0
|
|
|
|
|
0
|
my $sum = 0; |
221
|
0
|
|
|
|
|
0
|
my $l = 0; |
222
|
0
|
|
|
|
|
0
|
my $r = 0; |
223
|
0
|
|
|
|
|
0
|
my $d = 0; |
224
|
0
|
|
|
|
|
0
|
my $k = 0; |
225
|
0
|
|
|
|
|
0
|
my $r0 = 0; |
226
|
0
|
|
|
|
|
0
|
my $run = 1; |
227
|
|
|
|
|
|
|
# Calculate the left sum. |
228
|
0
|
|
|
|
|
0
|
while ($k <= $n) { |
229
|
|
|
|
|
|
|
# Calculate the value of the denominator. |
230
|
0
|
|
|
|
|
0
|
$d = 8*$k+$j; |
231
|
|
|
|
|
|
|
# Calculate the left partial sum. |
232
|
0
|
|
|
|
|
0
|
$l = ($l + modexp(16, $n-$k, $d) / $d) % 1; |
233
|
|
|
|
|
|
|
# Increment the loop counter $k. |
234
|
0
|
|
|
|
|
0
|
$k += 1; |
235
|
|
|
|
|
|
|
}; |
236
|
|
|
|
|
|
|
# Reset the loop counter. |
237
|
0
|
|
|
|
|
0
|
$k = $n + 1; |
238
|
|
|
|
|
|
|
# Calculate the right sum. |
239
|
0
|
|
|
|
|
0
|
while ($run == 1) { |
240
|
|
|
|
|
|
|
# Calculate the value of the denominator. |
241
|
0
|
|
|
|
|
0
|
$d = 8*$k+$j; |
242
|
|
|
|
|
|
|
# Calculate the right partial sum. |
243
|
0
|
|
|
|
|
0
|
$r = $r0 + (16**($n-$k)) / $d; |
244
|
|
|
|
|
|
|
# Check the exit condition of the loop. |
245
|
0
|
0
|
|
|
|
0
|
$run = ($r0 == $r ? 0 : 1); |
246
|
|
|
|
|
|
|
# Save the old partial sum. |
247
|
0
|
|
|
|
|
0
|
$r0 = $r; |
248
|
|
|
|
|
|
|
# Increment the loop counter $k. |
249
|
0
|
|
|
|
|
0
|
$k += 1; |
250
|
|
|
|
|
|
|
}; |
251
|
|
|
|
|
|
|
# Calculate the total sum. |
252
|
0
|
|
|
|
|
0
|
$sum = $l + $r; |
253
|
|
|
|
|
|
|
# Return the total sum. |
254
|
0
|
|
|
|
|
0
|
return $sum; |
255
|
|
|
|
|
|
|
}; |
256
|
|
|
|
|
|
|
|
257
|
|
|
|
|
|
|
#------------------------------------------------------------------------------# |
258
|
|
|
|
|
|
|
# Subroutine bbp_digit() # |
259
|
|
|
|
|
|
|
#------------------------------------------------------------------------------# |
260
|
|
|
|
|
|
|
sub bbp_digit { |
261
|
|
|
|
|
|
|
# Assign the subroutine arguments to the local variables. |
262
|
0
|
|
|
0
|
1
|
0
|
my ($n, $p) = @_; |
263
|
|
|
|
|
|
|
# Set the precision for bignum. |
264
|
0
|
|
|
|
|
0
|
bignum -> precision(-$p); |
265
|
|
|
|
|
|
|
# Decrement the value with the digit of interest by 1. |
266
|
0
|
|
|
|
|
0
|
$n -= 1; |
267
|
|
|
|
|
|
|
# Calculate the fraction with the hex numbers from the nth digit upwards. |
268
|
0
|
|
|
|
|
0
|
my $dec = (4*S(1, $n, $p) - 2*S(4, $n, $p) - |
269
|
|
|
|
|
|
|
S(5, $n, $p) - S(6, $n, $p)) % 1; |
270
|
|
|
|
|
|
|
# Get the decimal representation of the digit. |
271
|
0
|
|
|
|
|
0
|
$dec = ($dec * 16) - ($dec * 16) % 1; |
272
|
|
|
|
|
|
|
# Get the hexadecimal representation of the digit. |
273
|
0
|
|
|
|
|
0
|
my $hex = $HX[$dec]; |
274
|
|
|
|
|
|
|
# Return the hex number. |
275
|
0
|
|
|
|
|
0
|
return $hex; |
276
|
|
|
|
|
|
|
}; |
277
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
#------------------------------------------------------------------------------# |
279
|
|
|
|
|
|
|
# Subroutine bbp_digits() # |
280
|
|
|
|
|
|
|
#------------------------------------------------------------------------------# |
281
|
|
|
|
|
|
|
sub bbp_digits { |
282
|
|
|
|
|
|
|
# Assign the subroutine arguments to the local variables. |
283
|
0
|
|
|
0
|
1
|
0
|
my ($n, $digits, $p) = @_; |
284
|
|
|
|
|
|
|
# Set the precision for bignum. |
285
|
0
|
|
|
|
|
0
|
bignum -> precision(-$p); |
286
|
|
|
|
|
|
|
# Initialise the local variables. |
287
|
0
|
|
|
|
|
0
|
my $newdec = undef; |
288
|
0
|
|
|
|
|
0
|
my $hex_digit = ''; |
289
|
0
|
|
|
|
|
0
|
my $hex_digits = ''; |
290
|
|
|
|
|
|
|
# Decrement the value with the digit of interest by 1. |
291
|
0
|
|
|
|
|
0
|
$n -= 1; |
292
|
|
|
|
|
|
|
# Calculate the fraction with the hex numbers from the nth digit upwards. |
293
|
0
|
|
|
|
|
0
|
my $dec = (4*S(1, $n, $p) - 2*S(4, $n, $p) - |
294
|
|
|
|
|
|
|
S(5, $n, $p) - S(6, $n, $p)) % 1; |
295
|
|
|
|
|
|
|
# Calculate the hexadecimal number. |
296
|
0
|
|
|
|
|
0
|
for (my $j = 0; $j < length($dec); $j++) { |
297
|
0
|
|
|
|
|
0
|
$newdec = $dec * 16; |
298
|
0
|
|
|
|
|
0
|
$dec = $newdec - ($newdec % 1); |
299
|
0
|
|
|
|
|
0
|
$hex_digit = $HX[$dec]; |
300
|
0
|
|
|
|
|
0
|
$hex_digits = $hex_digits . $hex_digit; |
301
|
0
|
|
|
|
|
0
|
$dec = $newdec - $dec; |
302
|
|
|
|
|
|
|
}; |
303
|
|
|
|
|
|
|
# Return the hexadecimal number. |
304
|
0
|
|
|
|
|
0
|
return substr($hex_digits, 0, $digits); |
305
|
|
|
|
|
|
|
}; |
306
|
|
|
|
|
|
|
|
307
|
|
|
|
|
|
|
#------------------------------------------------------------------------------# |
308
|
|
|
|
|
|
|
# Subroutine bbp_algorith() # |
309
|
|
|
|
|
|
|
#------------------------------------------------------------------------------# |
310
|
|
|
|
|
|
|
sub bbp_algorithm { |
311
|
|
|
|
|
|
|
# Assign the subroutine arguments to the local variables. |
312
|
0
|
|
|
0
|
1
|
0
|
my ($places, $p) = @_; |
313
|
|
|
|
|
|
|
# Set the precision for bignum. |
314
|
0
|
|
|
|
|
0
|
bignum -> precision(-$p); |
315
|
|
|
|
|
|
|
# Initialise the local variable $pi_hex. |
316
|
0
|
|
|
|
|
0
|
my $pi_hex = "3."; |
317
|
|
|
|
|
|
|
# Declare the local variable $nth_digit. |
318
|
0
|
|
|
|
|
0
|
my $digits = undef; |
319
|
|
|
|
|
|
|
# Determine the hexadecimal places in a loop. |
320
|
0
|
|
|
|
|
0
|
for (my $i = 1; $i <= $places; $i++) { |
321
|
0
|
|
|
|
|
0
|
$digits = bbp_digit($i, $p); |
322
|
0
|
|
|
|
|
0
|
$pi_hex = $pi_hex . $digits; |
323
|
|
|
|
|
|
|
}; |
324
|
|
|
|
|
|
|
# Return Pi in hexadecimal representation. |
325
|
0
|
|
|
|
|
0
|
return $pi_hex; |
326
|
|
|
|
|
|
|
}; |
327
|
|
|
|
|
|
|
|
328
|
|
|
|
|
|
|
# ---------------------------------------------------------------------------- # |
329
|
|
|
|
|
|
|
# Subroutine borwein25_algorithm() # |
330
|
|
|
|
|
|
|
# ---------------------------------------------------------------------------- # |
331
|
|
|
|
|
|
|
sub borwein25_algorithm { |
332
|
|
|
|
|
|
|
# Assign the hash with the subroutine arguments to the local hash. |
333
|
0
|
|
|
0
|
1
|
0
|
my (%params) = @_; |
334
|
|
|
|
|
|
|
# Initialise the local variables. |
335
|
0
|
|
|
|
|
0
|
my $type0 = "pi"; |
336
|
0
|
|
|
|
|
0
|
my $type1 = "tau"; |
337
|
|
|
|
|
|
|
# Make a reference from the hash. |
338
|
0
|
|
|
|
|
0
|
my $args = \%params; |
339
|
|
|
|
|
|
|
# Initialise the locale variables. |
340
|
0
|
|
|
|
|
0
|
my $places = $args->{Places}; |
341
|
0
|
|
|
|
|
0
|
my $n = $args->{Terms}; |
342
|
0
|
|
|
|
|
0
|
my $p = $args->{Precision}; |
343
|
0
|
|
|
|
|
0
|
my $trim = $args->{Trim}; |
344
|
0
|
|
|
|
|
0
|
my $type = $args->{Type}; |
345
|
|
|
|
|
|
|
# Check if the the local variables are defined. |
346
|
0
|
0
|
|
|
|
0
|
$places = (defined $places ? $places : 0); |
347
|
0
|
0
|
|
|
|
0
|
$n = (defined $n ? $n : 0); |
348
|
0
|
0
|
|
|
|
0
|
$p = (defined $p ? $p : $places); |
349
|
0
|
0
|
|
|
|
0
|
$trim = (defined $trim ? $trim : $places); |
350
|
0
|
0
|
|
|
|
0
|
$type = (defined $type ? $type : $type0); |
351
|
|
|
|
|
|
|
# Set the precision. |
352
|
0
|
|
|
|
|
0
|
bignum -> precision(-$p); |
353
|
|
|
|
|
|
|
# Initialise the return variable. |
354
|
0
|
|
|
|
|
0
|
my $circle_constant = 0; |
355
|
|
|
|
|
|
|
# Set the local constants. |
356
|
0
|
|
|
|
|
0
|
my $sqrt61 = sqrtroot(61); |
357
|
0
|
|
|
|
|
0
|
my $A = (212175710912 * $sqrt61) + 1657145277365; |
358
|
0
|
|
|
|
|
0
|
my $B = (13773980892672 * $sqrt61) + 107578229802750; |
359
|
0
|
|
|
|
|
0
|
my $C = (5280 * (236674 + 30303 * $sqrt61))**3; |
360
|
0
|
|
|
|
|
0
|
my $factor = sqrtroot($C) / 12; |
361
|
|
|
|
|
|
|
# Set the initial values. |
362
|
0
|
|
|
|
|
0
|
my $a_k = 0; |
363
|
0
|
|
|
|
|
0
|
my $a_sum = 0; |
364
|
0
|
|
|
|
|
0
|
my $numerator = 0; |
365
|
0
|
|
|
|
|
0
|
my $denominator = 0; |
366
|
|
|
|
|
|
|
# Set the sign to 1. |
367
|
0
|
|
|
|
|
0
|
my $sign = 1; |
368
|
|
|
|
|
|
|
# Run index is of type int. |
369
|
0
|
|
|
|
|
0
|
for (my $k = 0; $k <= $n; $k++) { |
370
|
|
|
|
|
|
|
# Calculate numerator and denominator. |
371
|
0
|
|
|
|
|
0
|
$numerator = factorial(6*$k)*($A +$k*$B); |
372
|
0
|
|
|
|
|
0
|
$denominator = (factorial($k)**3)*factorial(3*$k)*($C**($k)); |
373
|
|
|
|
|
|
|
# Calculate the quotient. |
374
|
0
|
|
|
|
|
0
|
$a_k = $sign*($numerator / $denominator); |
375
|
|
|
|
|
|
|
# Add quotient to total sum. |
376
|
0
|
|
|
|
|
0
|
$a_sum += $a_k; |
377
|
|
|
|
|
|
|
# Change the sign. |
378
|
0
|
|
|
|
|
0
|
$sign *= -1; |
379
|
|
|
|
|
|
|
}; |
380
|
|
|
|
|
|
|
# Calculate the value of the circle_constant. |
381
|
0
|
|
|
|
|
0
|
$circle_constant = $factor / $a_sum; |
382
|
|
|
|
|
|
|
# Determine the value for Pi or for Tau. |
383
|
0
|
0
|
|
|
|
0
|
if ($type eq $type0) { |
|
|
0
|
|
|
|
|
|
384
|
0
|
|
|
|
|
0
|
$circle_constant = 1.0 * $circle_constant; |
385
|
|
|
|
|
|
|
} elsif ($type eq $type1) { |
386
|
0
|
|
|
|
|
0
|
$circle_constant = 2.0 * $circle_constant; |
387
|
|
|
|
|
|
|
}; |
388
|
|
|
|
|
|
|
# Cut the decimal number to the needed places. |
389
|
0
|
|
|
|
|
0
|
$circle_constant = truncate_places($circle_constant, $trim); |
390
|
|
|
|
|
|
|
# Return the value of the circle constant. |
391
|
0
|
|
|
|
|
0
|
return "$circle_constant"; |
392
|
|
|
|
|
|
|
}; |
393
|
|
|
|
|
|
|
|
394
|
|
|
|
|
|
|
# ---------------------------------------------------------------------------- # |
395
|
|
|
|
|
|
|
# Subroutine chudnovsky_algorithm() # |
396
|
|
|
|
|
|
|
# ---------------------------------------------------------------------------- # |
397
|
|
|
|
|
|
|
sub chudnovsky_algorithm { |
398
|
|
|
|
|
|
|
# Assign the hash with the subroutine arguments to the local hash. |
399
|
0
|
|
|
0
|
1
|
0
|
my (%params) = @_; |
400
|
|
|
|
|
|
|
# Initialise the local variables. |
401
|
0
|
|
|
|
|
0
|
my $type0 = "pi"; |
402
|
0
|
|
|
|
|
0
|
my $type1 = "tau"; |
403
|
|
|
|
|
|
|
# Make a reference from the hash. |
404
|
0
|
|
|
|
|
0
|
my $args = \%params; |
405
|
|
|
|
|
|
|
# Initialise the locale variables. |
406
|
0
|
|
|
|
|
0
|
my $places = $args->{Places}; |
407
|
0
|
|
|
|
|
0
|
my $n = $args->{Terms}; |
408
|
0
|
|
|
|
|
0
|
my $p = $args->{Precision}; |
409
|
0
|
|
|
|
|
0
|
my $trim = $args->{Trim}; |
410
|
0
|
|
|
|
|
0
|
my $type = $args->{Type}; |
411
|
|
|
|
|
|
|
# Check if the the local variables are defined. |
412
|
0
|
0
|
|
|
|
0
|
$places = (defined $places ? $places : 0); |
413
|
0
|
0
|
|
|
|
0
|
$n = (defined $n ? $n : 0); |
414
|
0
|
0
|
|
|
|
0
|
$p = (defined $p ? $p : $places); |
415
|
0
|
0
|
|
|
|
0
|
$trim = (defined $trim ? $trim : $places); |
416
|
0
|
0
|
|
|
|
0
|
$type = (defined $type ? $type : $type0); |
417
|
|
|
|
|
|
|
# Set the precision. |
418
|
0
|
|
|
|
|
0
|
bignum -> precision(-$p); |
419
|
|
|
|
|
|
|
# Initialise the return variable. |
420
|
0
|
|
|
|
|
0
|
my $circle_constant = 0; |
421
|
|
|
|
|
|
|
# Set the local integer constants. |
422
|
0
|
|
|
|
|
0
|
my $c0 = 545140134; |
423
|
0
|
|
|
|
|
0
|
my $c1 = 13591409; |
424
|
0
|
|
|
|
|
0
|
my $c2 = 640320; |
425
|
0
|
|
|
|
|
0
|
my $c3 = 4270934400; |
426
|
0
|
|
|
|
|
0
|
my $c4 = 10005; |
427
|
|
|
|
|
|
|
# Set the initial values. |
428
|
0
|
|
|
|
|
0
|
my $a_k = 0; |
429
|
0
|
|
|
|
|
0
|
my $a_sum = 0; |
430
|
0
|
|
|
|
|
0
|
my $numerator = 0; |
431
|
0
|
|
|
|
|
0
|
my $denominator = 0; |
432
|
|
|
|
|
|
|
# Set the sign to 1. |
433
|
0
|
|
|
|
|
0
|
my $sign = 1; |
434
|
|
|
|
|
|
|
# Run index is of type int. |
435
|
0
|
|
|
|
|
0
|
for (my $k = 0; $k <= $n; $k++) { |
436
|
|
|
|
|
|
|
# Calculate numerator and denominator. |
437
|
0
|
|
|
|
|
0
|
$numerator = factorial(6*$k)*($c0*$k+$c1); |
438
|
0
|
|
|
|
|
0
|
$denominator = factorial(3*$k)*(factorial($k)**3)*($c2**(3*$k)); |
439
|
|
|
|
|
|
|
# Calculate the quotient. |
440
|
0
|
|
|
|
|
0
|
$a_k = $sign*($numerator / $denominator); |
441
|
|
|
|
|
|
|
# Add quotient to total sum. |
442
|
0
|
|
|
|
|
0
|
$a_sum += $a_k; |
443
|
|
|
|
|
|
|
# Change the sign. |
444
|
0
|
|
|
|
|
0
|
$sign *= -1; |
445
|
|
|
|
|
|
|
}; |
446
|
|
|
|
|
|
|
# Calculate the value of the circle_constant. |
447
|
0
|
|
|
|
|
0
|
$circle_constant = $c3 / (sqrt($c4)*$a_sum); |
448
|
|
|
|
|
|
|
# Determine Pi or Tau. |
449
|
0
|
0
|
|
|
|
0
|
if ($type eq $type0) { |
|
|
0
|
|
|
|
|
|
450
|
0
|
|
|
|
|
0
|
$circle_constant = 1.0 * $circle_constant; |
451
|
|
|
|
|
|
|
} elsif ($type eq $type1) { |
452
|
0
|
|
|
|
|
0
|
$circle_constant = 2.0 * $circle_constant; |
453
|
|
|
|
|
|
|
}; |
454
|
|
|
|
|
|
|
# Cut the decimal number to the needed places. |
455
|
0
|
|
|
|
|
0
|
$circle_constant = truncate_places($circle_constant, $trim); |
456
|
|
|
|
|
|
|
# Return the value of the circle constant. |
457
|
0
|
|
|
|
|
0
|
return "$circle_constant"; |
458
|
|
|
|
|
|
|
}; |
459
|
|
|
|
|
|
|
|
460
|
|
|
|
|
|
|
# ---------------------------------------------------------------------------- # |
461
|
|
|
|
|
|
|
# Subroutine chudnovsky_caller() # |
462
|
|
|
|
|
|
|
# ---------------------------------------------------------------------------- # |
463
|
|
|
|
|
|
|
sub chudnovsky_caller { |
464
|
|
|
|
|
|
|
# Assign the subroutine arguments to the local variables. |
465
|
0
|
|
|
0
|
0
|
0
|
my $places = $_[0]; |
466
|
0
|
|
|
|
|
0
|
my $method = $_[1]; |
467
|
|
|
|
|
|
|
# Check if the places are valid. If not exit the script. |
468
|
0
|
|
|
|
|
0
|
check_places($places); |
469
|
|
|
|
|
|
|
# Calculate the required number of terms. |
470
|
0
|
|
|
|
|
0
|
my $terms = estimate_terms($places, 14); |
471
|
|
|
|
|
|
|
# Set the precision for the calculation. |
472
|
0
|
|
|
|
|
0
|
my $precision = $places + 15; |
473
|
|
|
|
|
|
|
# Get the value of the circle constant from the calculation. |
474
|
0
|
|
|
|
|
0
|
my $circle_constant = chudnovsky_algorithm( |
475
|
|
|
|
|
|
|
Places => $places, |
476
|
|
|
|
|
|
|
Terms => $terms, |
477
|
|
|
|
|
|
|
Precision => $precision, |
478
|
|
|
|
|
|
|
Trim => $places, |
479
|
|
|
|
|
|
|
Type => $method |
480
|
|
|
|
|
|
|
); |
481
|
|
|
|
|
|
|
# Return the value of the circle constant Pi or Tau. |
482
|
0
|
|
|
|
|
0
|
return "$circle_constant"; |
483
|
|
|
|
|
|
|
}; |
484
|
|
|
|
|
|
|
|
485
|
|
|
|
|
|
|
# ---------------------------------------------------------------------------- # |
486
|
|
|
|
|
|
|
# Subroutine borwein25_caller() # |
487
|
|
|
|
|
|
|
# ---------------------------------------------------------------------------- # |
488
|
|
|
|
|
|
|
sub borwein25_caller { |
489
|
|
|
|
|
|
|
# Assign the subroutine arguments to the local variables. |
490
|
0
|
|
|
0
|
0
|
0
|
my $places = $_[0]; |
491
|
0
|
|
|
|
|
0
|
my $method = $_[1]; |
492
|
|
|
|
|
|
|
# Check if the places are valid. If not exit the script. |
493
|
0
|
|
|
|
|
0
|
check_places($places); |
494
|
|
|
|
|
|
|
# Calculate the required number of terms. |
495
|
0
|
|
|
|
|
0
|
my $terms = estimate_terms($places, 25); |
496
|
|
|
|
|
|
|
# Set the precision for the calculation. |
497
|
0
|
|
|
|
|
0
|
my $precision = $places + 26; |
498
|
|
|
|
|
|
|
# Get the value of the circle constant from the calculation. |
499
|
0
|
|
|
|
|
0
|
my $circle_constant = borwein25_algorithm( |
500
|
|
|
|
|
|
|
Places => $places, |
501
|
|
|
|
|
|
|
Terms => $terms, |
502
|
|
|
|
|
|
|
Precision => $precision, |
503
|
|
|
|
|
|
|
Trim => $places, |
504
|
|
|
|
|
|
|
Type => $method |
505
|
|
|
|
|
|
|
); |
506
|
|
|
|
|
|
|
# Return the value of the circle constant Pi or Tau. |
507
|
0
|
|
|
|
|
0
|
return "$circle_constant"; |
508
|
|
|
|
|
|
|
}; |
509
|
|
|
|
|
|
|
|
510
|
|
|
|
|
|
|
# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ # |
511
|
|
|
|
|
|
|
# Call the caller subroutines # |
512
|
|
|
|
|
|
|
# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ # |
513
|
0
|
|
|
0
|
1
|
0
|
sub pi_chudnovsky { return chudnovsky_caller($_[0], "pi") }; |
514
|
0
|
|
|
0
|
1
|
0
|
sub tau_chudnovsky { return chudnovsky_caller($_[0], "tau") }; |
515
|
0
|
|
|
0
|
1
|
0
|
sub pi_borwein25 { return borwein25_caller($_[0], "pi") }; |
516
|
0
|
|
|
0
|
1
|
0
|
sub tau_borwein25 { return borwein25_caller($_[0], "tau") }; |
517
|
|
|
|
|
|
|
|
518
|
|
|
|
|
|
|
# ============================================================================ # |
519
|
|
|
|
|
|
|
# Subroutine read_pi() # |
520
|
|
|
|
|
|
|
# ============================================================================ # |
521
|
|
|
|
|
|
|
sub read_pi { |
522
|
|
|
|
|
|
|
# Assign the subroutine argument to the local variable. |
523
|
2
|
|
|
2
|
0
|
4
|
my $type = $_[0]; |
524
|
|
|
|
|
|
|
# Initialise the local variables. |
525
|
2
|
|
|
|
|
3
|
my $line = ""; |
526
|
2
|
|
|
|
|
4
|
my $pi = ""; |
527
|
|
|
|
|
|
|
# Assemble the begin and end pattern. |
528
|
2
|
|
|
|
|
5
|
my $pattern0 = "# Begin Pi ${type}"; |
529
|
2
|
|
|
|
|
4
|
my $pattern1 = "# End Pi ${type}"; |
530
|
|
|
|
|
|
|
# Read the data from the DATA section. |
531
|
2
|
|
|
|
|
23
|
while () { |
532
|
|
|
|
|
|
|
# Read data only between the two given pattern. |
533
|
1118
|
100
|
|
|
|
2986
|
if (/$pattern0/../$pattern1/) { |
534
|
46
|
100
|
100
|
|
|
222
|
next if /$pattern0/ || /$pattern1/; |
535
|
42
|
|
|
|
|
72
|
$line = $_; |
536
|
42
|
|
|
|
|
334
|
$line =~ s/^\s+|\s+$//g; |
537
|
42
|
|
|
|
|
126
|
$pi = $pi . $line; |
538
|
|
|
|
|
|
|
}; |
539
|
|
|
|
|
|
|
}; |
540
|
|
|
|
|
|
|
# Return Pi. |
541
|
2
|
|
|
|
|
16
|
return $pi; |
542
|
|
|
|
|
|
|
}; |
543
|
|
|
|
|
|
|
|
544
|
|
|
|
|
|
|
# ============================================================================ # |
545
|
|
|
|
|
|
|
# Subroutine read_data() # |
546
|
|
|
|
|
|
|
# # |
547
|
|
|
|
|
|
|
# Description: # |
548
|
|
|
|
|
|
|
# The subroutine reads Pi in decimal and hexadecimal representation from the # |
549
|
|
|
|
|
|
|
# DATA section. # |
550
|
|
|
|
|
|
|
# ============================================================================ # |
551
|
|
|
|
|
|
|
sub read_data { |
552
|
|
|
|
|
|
|
# Save the position of DATA. |
553
|
1
|
|
|
1
|
0
|
4
|
my $data_start = tell DATA; |
554
|
|
|
|
|
|
|
# Read decimal Pi with 1000 places. |
555
|
1
|
|
|
|
|
4
|
my $pi_dec = uc(read_pi("dec")); |
556
|
|
|
|
|
|
|
# Reposition the filehandle right past to __DATA__ |
557
|
1
|
|
|
|
|
6
|
seek DATA, $data_start, 0; |
558
|
|
|
|
|
|
|
# Read hexadecimal Pi with 1000 places. |
559
|
1
|
|
|
|
|
46
|
my $pi_hex = uc(read_pi("hex")); |
560
|
|
|
|
|
|
|
# Return PI. |
561
|
1
|
|
|
|
|
5
|
return $pi_dec, $pi_hex; |
562
|
|
|
|
|
|
|
}; |
563
|
|
|
|
|
|
|
|
564
|
|
|
|
|
|
|
# Read data from DATA. |
565
|
|
|
|
|
|
|
($PI_DEC, $PI_HEX) = read_data(); |
566
|
|
|
|
|
|
|
|
567
|
|
|
|
|
|
|
1; |
568
|
|
|
|
|
|
|
|
569
|
|
|
|
|
|
|
__DATA__ |