# The next few requires eventually probably need to go in their own gem. They're all functions and constants used by # GSL-adapted pure Ruby math functions. require "distribution/math_extension/chebyshev_series" require "distribution/math_extension/erfc" require "distribution/math_extension/exponential_integral" require "distribution/math_extension/gammastar" require "distribution/math_extension/gsl_utilities" require "distribution/math_extension/incomplete_gamma" require "distribution/math_extension/incomplete_beta" require "distribution/math_extension/log_utilities" if RUBY_VERSION<"1.9" require 'mathn' def Prime.each(upper,&block) @primes=Prime.new @primes.each do |prime| break if prime > upper.to_i block.call(prime) end end else require 'prime' end require 'bigdecimal' require 'bigdecimal/math' module Distribution # Extension for Ruby18 # Includes gamma and lgamma module MathExtension18 LOG_2PI = Math.log(2 * Math::PI)# log(2PI) N = 8 B0 = 1.0 B1 = -1.0 / 2.0 B2 = 1.0 / 6.0 B4 = -1.0 / 30.0 B6 = 1.0 / 42.0 B8 = -1.0 / 30.0 B10 = 5.0 / 66.0 B12 = -691.0 / 2730.0 B14 = 7.0 / 6.0 B16 = -3617.0 / 510.0 # From statistics2 def loggamma(x) v = 1.0 while (x < N) v *= x x += 1.0 end w = 1.0 / (x * x) ret = B16 / (16 * 15) ret = ret * w + B14 / (14 * 13) ret = ret * w + B12 / (12 * 11) ret = ret * w + B10 / (10 * 9) ret = ret * w + B8 / ( 8 * 7) ret = ret * w + B6 / ( 6 * 5) ret = ret * w + B4 / ( 4 * 3) ret = ret * w + B2 / ( 2 * 1) ret = ret / x + 0.5 * LOG_2PI - Math.log(v) - x + (x - 0.5) * Math.log(x) ret end # Gamma function. # From statistics2 def gamma(x) if (x < 0.0) return Math::PI / (Math.sin(Math.PI * x) * Math.exp(loggamma(1 - x))) #/ end Math.exp(loggamma(x)) end end # Useful additions to Math module MathExtension # Factorization based on Prime Swing algorithm, by Luschny (the king of factorial numbers analysis :P ) # == Reference # * The Homepage of Factorial Algorithms. (C) Peter Luschny, 2000-2010 # == URL: http://www.luschny.de/math/factorial/csharp/FactorialPrimeSwing.cs.html class SwingFactorial attr_reader :result SmallOddSwing=[ 1, 1, 1, 3, 3, 15, 5, 35, 35, 315, 63, 693, 231, 3003, 429, 6435, 6435, 109395, 12155, 230945, 46189, 969969, 88179, 2028117, 676039, 16900975, 1300075, 35102025, 5014575,145422675, 9694845, 300540195, 300540195] SmallFactorial=[1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800, 39916800, 479001600, 6227020800, 87178291200, 1307674368000, 20922789888000, 355687428096000, 6402373705728000, 121645100408832000, 2432902008176640000] def bitcount(n) bc = n - ((n >> 1) & 0x55555555); bc = (bc & 0x33333333) + ((bc >> 2) & 0x33333333); bc = (bc + (bc >> 4)) & 0x0f0f0f0f; bc += bc >> 8; bc += bc >> 16; bc = bc & 0x3f; bc end def initialize(n) if (n<20) @result=SmallFactorial[n] #naive_factorial(n) else @prime_list=[] exp2 = n - bitcount(n); @result= recfactorial(n)<< exp2 end end def recfactorial(n) return 1 if n<2 (recfactorial(n/2)**2) * swing(n) end def swing(n) return SmallOddSwing[n] if (n<33) sqrtN = Math.sqrt(n).floor count=0 Prime.each(n/3) do |prime| next if prime<3 if (prime<=sqrtN) q=n _p=1 while((q=(q/prime).truncate)>0) do if((q%2)==1) _p*=prime end end if _p>1 @prime_list[count]=_p count+=1 end else if ((n/prime).truncate%2==1) @prime_list[count]=prime count+=1 end end end prod=get_primorial((n/2).truncate+1,n) prod * @prime_list[0,count].inject(1) {|ac,v| ac*v} end def get_primorial(low,up) prod=1; Prime.each(up) do |prime| next if prime