├── LICENSE ├── README.md └── src └── pi.jl /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 David van Leeuwen 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Pi.jl 2 | Various ways to compute π in Julia 3 | 4 | I collected these for fun after a remark on the Julia mailing list. 5 | 6 | ## Usage 7 | 8 | ```julia 9 | include("src/pil.jl") 10 | ``` 11 | 12 | In the following, `n` is the requested number of digits of π. 13 | 14 | - `mpfr_pi(n)`: divert the problem to the `mpfr` library 15 | - `atan_pi(n)`: compute π as $4 \arc \tan 1$ (probably the same as above) 16 | - `spigot_pi(n)`: compute π one digit at the time 17 | - `borwein2_pi(n)`: an algorithm from Borwein & Borwein 18 | - `borwein_1984_pi(n)`: another algorithm from Borwein 19 | - `chudnovsky2_1989_pi(n): an algorithm from Chudnovsky 20 | - `gaussLegendre_pi(n)`: the classical algorithm 21 | - `bbp_pi(n, start)`: compute π in hexidecimal digits, starting at an arbitrary offset, withou using arbitrary precision math 22 | 23 | ## Suggestions, improvements, etc 24 | 25 | Are very welcome, please submit a pull request. 26 | -------------------------------------------------------------------------------- /src/pi.jl: -------------------------------------------------------------------------------- 1 | ## pil.jl (c) 2015 David A. van Leeuwen and others 2 | ## This file is licensed under the MIT software license. 3 | 4 | ## Various algorithms to compute π in many (hexa)decimal digits. 5 | 6 | ## We count digits after the period, e.g., for ndigits=2, π ≈ 3.14 7 | 8 | nbits(ndigits::Int) = ceil(Int, log(2,10) * (ndigits+1)) 9 | 10 | ## Ivar Nesje, diverting problem to mpfr 11 | function mpfr_pi(ndigits::Int) 12 | with_bigfloat_precision(nbits(ndigits)) do 13 | big(π) 14 | end 15 | end 16 | 17 | ## seems to give identical result 18 | function atan_pi(ndigits::Int) 19 | with_bigfloat_precision(nbits(ndigits)) do 20 | 4atan(BigFloat(1)) 21 | end 22 | end 23 | 24 | ## spigot, after Rabinowitz and Wagon. This computes π one decimal digit at the time. 25 | ## Adapted from Hans W Borgers: 26 | function spigot_pi(n) 27 | p = 0 28 | Pi = fill(UInt8('0'), n+6) 29 | no_nines = 0 30 | d = n + 2 31 | N = floor(Int, 10*d/3.0 + 1) 32 | a = fill(2, N+1) 33 | ci = 1 34 | for l in 1:d 35 | for i=1:length(a) 36 | a[i] *= 10 37 | end 38 | for i in (N+1):-1:2 39 | j = 2*i - 1 40 | q, a[i] = divrem(a[i], j) 41 | a[i-1] += q * (i-1) 42 | end 43 | q, a[1] = divrem(a[1], 10) 44 | if q < 9 45 | Pi[ci] = UInt8('0')+p 46 | for i = 1:no_nines 47 | Pi[ci+i] = UInt8('9') 48 | end 49 | ci += no_nines+1 50 | p = q 51 | no_nines = 0 52 | elseif q == 9 53 | no_nines += 1 54 | elseif q == 10 55 | p += 1 56 | Pi[ci] = UInt('0')+p 57 | for i = 1:no_nines 58 | Pi[ci+i] = UInt8('0') 59 | end 60 | ci += no_nines+1 61 | p = 0 62 | no_nines = 0 63 | else 64 | error("spigot_pi: algorithm error!") 65 | end 66 | end 67 | Pi[1], Pi[2] = Pi[2], UInt8('.') # remove first 0 and insert decimal point 68 | ASCIIString(Pi[1:n+2]) 69 | end 70 | 71 | ## from numerical recipes, Borwein & Borwein 72 | function borwein2_pi(ndigits::Int) 73 | with_bigfloat_precision(nbits(ndigits)) do 74 | ɛ = BigFloat(10) ^ -ndigits 75 | x = √ BigFloat(2) 76 | p = 2 + x 77 | y = sx = √x 78 | while true 79 | lastp = p 80 | x = 0.5(sx + 1/sx) 81 | p *= (x+1)/(y+1) 82 | if abs(p-lastp) < ɛ break end 83 | sx = √x 84 | y = (y*sx + 1/sx) / (y+1) 85 | end 86 | p 87 | end 88 | end 89 | 90 | ## from Wikipedia http://en.wikipedia.org/wiki/Borwein%27s_algorithm 91 | function borwein_1984_pi(ndigits::Integer) 92 | with_bigfloat_precision(nbits(ndigits)) do 93 | ɛ = BigFloat(10) ^ -ndigits 94 | a = √ BigFloat(2) 95 | b = BigFloat(0) 96 | p = a + 2 97 | while true 98 | lastp = p 99 | sa = √a 100 | b = (b+1)sa / (a+b) 101 | a = 0.5(sa + 1/sa) 102 | p *= (1+a)b / (1+b) 103 | if abs(p-lastp) < ɛ break end 104 | end 105 | p 106 | end 107 | end 108 | 109 | function chudnovsky2_1989_pi(ndigits::Int) 110 | with_bigfloat_precision(nbits(ndigits)) do 111 | ɛ = BigFloat(10) ^ -ndigits 112 | threek = sixk = k = s = BigFloat(0) 113 | sign = k!3 = threek! = sixk! = BigFloat(1) 114 | denfact = BigFloat(640320) ^ 3 115 | den = √denfact 116 | while true 117 | lasts = s 118 | s += sign * sixk! * (13591409 + 545140134k) / (threek! * k!3 * den) 119 | if abs(lasts - s) < ɛ break end 120 | k += 1 121 | for i=1:3 122 | threek += 1 123 | threek! *= threek 124 | end 125 | for i=1:6 126 | sixk += 1 127 | sixk! *= sixk 128 | end 129 | k!3 *= k*k*k 130 | den *= denfact 131 | sign = -sign 132 | end 133 | 1 / 12s 134 | end 135 | end 136 | 137 | ## Johan Sigfrids 138 | function gaussLegendre_pi(ndigits::Integer) 139 | with_bigfloat_precision(nbits(ndigits)) do 140 | n = ceil(Int, log2(ndigits)) 141 | a = BigFloat(1) 142 | b = a / √ BigFloat(2) 143 | t = a / BigFloat(4) 144 | x = a 145 | while n > 0 146 | y = a 147 | a = (a + b) / 2 148 | b = √(b * y) 149 | t -= x * (y - a)^2 150 | x *= 2 151 | n -= 1 152 | end 153 | (a + b)^2 / (4 * t) 154 | end 155 | end 156 | 157 | 158 | ## helper function for BBP alorithm 159 | function modpow(b, n::Integer, c) 160 | ## wikipedia 161 | r = 1 % c 162 | b %= c 163 | while n > 0 164 | if isodd(n) 165 | r = (r*b) % c 166 | end 167 | n >>= 1 168 | b = (b*b) % c 169 | end 170 | return r 171 | ## Bailey, Borwein, Borwein, Plouffe (incorrect?) 172 | t = nextpow2(n+1) >> 1 173 | r = 1 174 | while true 175 | if n ≥ t 176 | r = (b*r) % c 177 | n -= t 178 | end 179 | t = t ÷ 2 180 | if t < 1 181 | break 182 | end 183 | r = (r*r) % c 184 | end 185 | return r 186 | ## Straightforward (slow) 187 | r = 1 188 | while n > 0 189 | r = (r*b) % c 190 | n -= 1 191 | end 192 | r 193 | end 194 | 195 | ## compute 1 digit according to the Borwein, Borwein, and Plouffe algorithm. 196 | ## http://crd-legacy.lbl.gov/~dhbailey/dhbpapers/pi-quest.pdf 197 | function bbp_pi_digit(n::Int) 198 | if n == 0 199 | return 3 200 | else 201 | n -= 1 202 | end 203 | const o = [1, 4, 5, 6] 204 | const w = [4, -2, -1, -1] 205 | frac = 0. 206 | for k=0:n 207 | for i=1:4 208 | den = 8k+o[i] 209 | frac += (w[i] * modpow(16, n-k, den)) / den 210 | end 211 | end 212 | floor(Int, mod(frac, 1) * 16)::Int 213 | end 214 | 215 | ## The Borwein, Borwein and Plouffe formula of a hex digit of pi. 216 | ## This can be run in parallel, and can start at any digit. 217 | ## cf. table 3 from the publication: `bbp_pi(14, 10^6)` 218 | function bbp_pi(n::Int, start::Int=0) 219 | if start==0 220 | range = 0:n 221 | else 222 | range = start + (0:n-1) 223 | end 224 | digits = @parallel (vcat) for i in range 225 | digit = bbp_pi_digit(i) 226 | if digit < 10 227 | d = '0'+digit 228 | else 229 | d = 'a'+digit-10 230 | end 231 | if i==0 232 | map(UInt8, vcat(d,'.')) 233 | else 234 | UInt8(d) 235 | end 236 | end 237 | ASCIIString(vcat(digits)) 238 | end 239 | 240 | function bbp_pi_float(n::Int) 241 | digits = @parallel (vcat) for i in 0:n 242 | digit = bbp_pi_digit(i) 243 | nibble = BitArray(4) 244 | for i = 1:4 245 | nibble[5-i] = isodd(digit) 246 | digit >>= 1 247 | end 248 | nibble 249 | end 250 | bigfloat(digits, 2) 251 | end 252 | 253 | ## This function interprets a bitvector as mantissa for a BigFloat number. 254 | ## Admittedy, somewhat clumsy. 255 | function bigfloat(x::BitVector, exp=1) 256 | ## remove leading falses and reverse 257 | nb = length(x) 258 | x = reverse(x) 259 | while length(x)>1 && !last(x) 260 | pop!(x) 261 | end 262 | if length(x)==1 263 | return with_bigfloat_precision(()->big(0.), nb) 264 | end 265 | ## shift bits until a leading true is found 266 | nb = length(x) 267 | firstbit = reinterpret(Uint, typemin(Int)) ## 0x8000000000000000 268 | while last(x.chunks) & firstbit == 0 269 | insert!(x, 1, false) 270 | end 271 | with_bigfloat_precision(nb) do 272 | f = big(1.) 273 | f.exp = exp 274 | for i=1:length(x.chunks) 275 | unsafe_store!(f.d, x.chunks[i], i) 276 | end 277 | return f 278 | end 279 | end 280 | 281 | # Helper to check bbp algorithm, converts float to hexadecimal string. 282 | function base16(x, n::Int) 283 | digits = Uint8[] 284 | nbefore = max(0,ifloor(log(16,x)))+1 285 | for i=1:nbefore 286 | x *= 16 287 | end 288 | for i = -nbefore:n 289 | if i==0 290 | push!(digits, '.') 291 | continue 292 | end 293 | d, r = divrem(x, 16) 294 | if d<10 295 | push!(digits, '0'+d) 296 | else 297 | push!(digits, 'a'+d-10) 298 | end 299 | x = 16r 300 | end 301 | ASCIIString(digits) 302 | end 303 | --------------------------------------------------------------------------------