Advertisement
Guest User

factorial

a guest
Apr 19th, 2013
84
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Ruby 2.21 KB | None | 0 0
  1. def product(arr)
  2.     def rec_product(n, step, arr)
  3.         return arr[n] if step > n
  4.         newstep = step << 1
  5.         t = rec_product(n, newstep, arr) *
  6.             rec_product(n-step, newstep, arr)
  7.         return t
  8.     end
  9.     rec_product(arr.length-1, 1, arr)
  10. end
  11.  
  12. SMALL_ODD_SWING = [ 1,1,1,3,3,15,5,35,35,315,63,693,231,3003,429,6435,6435,109395,
  13.                   12155,230945,46189,969969,88179,2028117,676039,16900975,1300075,
  14.                   35102025,5014575,145422675,9694845,300540195,300540195 ]
  15.  
  16. PRECOMPUTED_ODD_SWINGS_NUM = SMALL_ODD_SWING.length
  17.  
  18. require 'prime'
  19. PRIMES = Prime.each(1_000_000).to_a
  20.  
  21. def lower_bound(arr, n)
  22.   l = 0
  23.   r = arr.length
  24.   while r > l
  25.     m = (l + r) / 2
  26.     if arr[m] < n
  27.       l = m + 1
  28.     else
  29.       r = m
  30.     end
  31.   end
  32.   l
  33. end
  34.  
  35. class Integer
  36.   def primes_upto(n)
  37.     b = lower_bound(PRIMES, self)
  38.     e = lower_bound(PRIMES, n + 1)
  39.     PRIMES[b ... e]
  40.   end
  41. end
  42.  
  43. def odd_swing(n)
  44.     return SMALL_ODD_SWING[n] if n < PRECOMPUTED_ODD_SWINGS_NUM
  45.     root_n = (Math.sqrt n).floor
  46.     prime_list = []
  47.     a_primes = 3.primes_upto(root_n)
  48.     b_primes = (root_n+1).primes_upto(n / 3)
  49.     a_primes.each do |prime|
  50.         q, p = n, 1
  51.         while true do
  52.             q /= prime
  53.             break if q == 0
  54.             p *= prime if q & 1 == 1
  55.         end
  56.         prime_list << p if p > 1
  57.     end
  58.     b_primes.each do |prime|
  59.         prime_list << prime if (n / prime) & 1 == 1
  60.     end
  61.     product(prime_list) * product(((n/2)+1).primes_upto(n))
  62. end
  63.  
  64. class FactorialCalculator
  65.   def calc(n)
  66.       @swings = []
  67.       @counter = 0
  68.       shift = 0
  69.       t = n
  70.       while t > 0 do
  71.           if t >= PRECOMPUTED_ODD_SWINGS_NUM
  72.               @swings << odd_swing(t)
  73.               @counter += 1
  74.           end
  75.           t /= 2
  76.           shift += t
  77.       end
  78.       return rec_factorial(n) << shift
  79.   end
  80.  
  81.   private
  82.   def rec_factorial(n)
  83.       return 1 if n < 2
  84.       t = rec_factorial(n/2)
  85.       t *= t
  86.       if n < PRECOMPUTED_ODD_SWINGS_NUM
  87.           return t * SMALL_ODD_SWING[n]
  88.       else
  89.           @counter -= 1
  90.           return t * @swings[@counter]
  91.       end
  92.   end
  93. end
  94.  
  95. puts FactorialCalculator.new.calc(1_000_000).to_s(16)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement