Advertisement
DRVTiny

bbp.cr

Oct 15th, 2021
962
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Ruby 2.90 KB | None | 0 0
  1. require "math"
  2. macro dcl(*args)
  3.   {% aa = [] of (Path|Call) %}
  4.   {% for x in args %}
  5.     {% if x.is_a?(TypeDeclaration) %}
  6.       {% aa.push(x.var) %}
  7.       {% t = x.type %}
  8.     {% else %}    
  9.       {% aa.push(x) %}
  10.     {% end %}
  11.   {% end %}
  12.   {% for v in aa %}
  13.     {{v.id}} : {{t.id}}
  14.   {% end %}
  15. ##  {% debug %}
  16. end
  17.  
  18. def mul_mod(a : Int64, b : Int64, m : Int64)
  19.   (a * b) % m  
  20. end
  21.  
  22. def inv_mod(x : Int64, y : Int64)
  23.    dcl q, u, v, a, c, t : Int64
  24.    
  25.    u = x
  26.    v = y
  27.    c = 1
  28.    a = 0
  29.    loop do
  30.      q = (v / u).to_i64
  31.      t = c
  32.      c = a - q * c
  33.      a = t
  34.      
  35.      t = u
  36.      u = v - q * u
  37.      v = t
  38.      break if u == 0    
  39.    end
  40.    a %= y
  41.    a += y if a < 0
  42.    a
  43. end
  44.  
  45. def pow_mod(a : Int64, b : Int64, m : Int64)
  46.   dcl r, aa : Int64
  47.  
  48.   r = 1
  49.   aa = a
  50.   loop do
  51.     if b & 1 > 0
  52.       r = mul_mod(r, aa, m)
  53.     end
  54.     b >>= 1
  55.      
  56.     break if b == 0
  57.     aa = mul_mod(aa, aa, m)
  58.   end
  59.   r
  60. end
  61.  
  62. def is_prime(n : Int64)
  63.     return false if n & 1 == 0
  64.    
  65.     i = 3_i64
  66.    
  67.     while i <= n
  68.       res, rem = n.divmod(i)
  69.       return !(rem == 0) if i > res || rem == 0      
  70.       i += 2
  71.     end
  72.     true
  73. end
  74.  
  75. def next_prime(n : Int64)
  76.   cn = n + 1 + n & 1
  77.   until is_prime(cn)
  78.     cn += 1
  79.   end
  80.   cn
  81. end
  82.  
  83. def main
  84.   dcl av, a, vmax, nbig, n, num, den, k, kq, kq2, t, v, s, i : Int64
  85.   sum : Float64
  86.   n = ARGV[0]?.try &.to_i64 || raise "This program computes the n'th decimal digit of PI\nUsage: PROGRAM n, where \"n\" is the digit you want"
  87.   nbig = ((n + 20) * Math.log(10) / Math.log(2)).to_i64
  88.  
  89.   sum = 0
  90.   a = 3
  91.   while a <= (2 * nbig)
  92.     vmax = (Math.log(2 * nbig) / Math.log(a)).to_i64;
  93.     av = a ** vmax
  94.  
  95.     s = 0
  96.     num = 1
  97.     den = 1
  98.     v = 0
  99.     kq = 1
  100.     kq2 = 1
  101.     (1_i64..nbig).each do |k|
  102.         t = k
  103.         if kq >= a
  104.           loop do
  105.             t = (t / a).to_i64
  106.             v -= 1
  107.             break unless (t % a) == 0
  108.           end    
  109.           kq = 0
  110.         end
  111.         kq += 1
  112.         num = mul_mod(num, t, av)
  113.  
  114.         t = (2_i64 * k - 1_i64);
  115.         if kq2 >= a
  116.             if kq2 == a
  117.               loop do
  118.                 t = (t / a).to_i64
  119.                 v += 1
  120.                 break unless (t % a) == 0
  121.               end
  122.             end
  123.             kq2 -= a
  124.         end
  125.         den = mul_mod(den, t, av)
  126.         kq2 += 2
  127.  
  128.         if v > 0
  129.             t = inv_mod(den, av)
  130.             t = mul_mod(t, num, av)
  131.             t = mul_mod(t, k, av)
  132.             (v..vmax-1).each do
  133.               t = mul_mod(t, a, av)
  134.             end
  135.             s += t
  136.             s -= av if s >= av
  137.         end
  138.     end
  139.  
  140.     t = pow_mod(10, n - 1, av)
  141.     s = mul_mod(s, t, av)
  142.     sum = (sum + s.to_f64 / av.to_f64) % 1.0_f64
  143.    
  144.     a = next_prime(a)
  145.   end # while a <= (2 * nbig)
  146.  
  147.   printf("Decimal digits of pi at position %d: %09d\n", n, (sum * 1e+9).to_i64 )
  148. end
  149.  
  150. main
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement