mirror of
				https://github.com/ruby/ruby.git
				synced 2022-11-09 12:17:21 -05:00 
			
		
		
		
	 790e7f797b
			
		
	
	
		790e7f797b
		
	
	
	
	
		
			
			Patch by Ershad K [Github Fixes #234] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@38798 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
		
			
				
	
	
		
			509 lines
		
	
	
	
		
			14 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
			
		
		
	
	
			509 lines
		
	
	
	
		
			14 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
| #
 | |
| # = prime.rb
 | |
| #
 | |
| # Prime numbers and factorization library.
 | |
| #
 | |
| # Copyright::
 | |
| #   Copyright (c) 1998-2008 Keiju ISHITSUKA(SHL Japan Inc.)
 | |
| #   Copyright (c) 2008 Yuki Sonoda (Yugui) <yugui@yugui.jp>
 | |
| #
 | |
| # Documentation::
 | |
| #   Yuki Sonoda
 | |
| #
 | |
| 
 | |
| require "singleton"
 | |
| require "forwardable"
 | |
| 
 | |
| class Integer
 | |
|   # Re-composes a prime factorization and returns the product.
 | |
|   #
 | |
|   # See Prime#int_from_prime_division for more details.
 | |
|   def Integer.from_prime_division(pd)
 | |
|     Prime.int_from_prime_division(pd)
 | |
|   end
 | |
| 
 | |
|   # Returns the factorization of +self+.
 | |
|   #
 | |
|   # See Prime#prime_division for more details.
 | |
|   def prime_division(generator = Prime::Generator23.new)
 | |
|     Prime.prime_division(self, generator)
 | |
|   end
 | |
| 
 | |
|   # Returns true if +self+ is a prime number, false for a composite.
 | |
|   def prime?
 | |
|     Prime.prime?(self)
 | |
|   end
 | |
| 
 | |
|   # Iterates the given block over all prime numbers.
 | |
|   #
 | |
|   # See +Prime+#each for more details.
 | |
|   def Integer.each_prime(ubound, &block) # :yields: prime
 | |
|     Prime.each(ubound, &block)
 | |
|   end
 | |
| end
 | |
| 
 | |
| #
 | |
| # The set of all prime numbers.
 | |
| #
 | |
| # == Example
 | |
| #
 | |
| #   Prime.each(100) do |prime|
 | |
| #     p prime  #=> 2, 3, 5, 7, 11, ...., 97
 | |
| #   end
 | |
| #
 | |
| # Prime is Enumerable:
 | |
| #
 | |
| #   Prime.first 5 # => [2, 3, 5, 7, 11]
 | |
| #
 | |
| # == Retrieving the instance
 | |
| #
 | |
| # +Prime+.new is obsolete. Now +Prime+ has the default instance and you can
 | |
| # access it as +Prime+.instance.
 | |
| #
 | |
| # For convenience, each instance method of +Prime+.instance can be accessed
 | |
| # as a class method of +Prime+.
 | |
| #
 | |
| # e.g.
 | |
| #   Prime.instance.prime?(2)  #=> true
 | |
| #   Prime.prime?(2)           #=> true
 | |
| #
 | |
| # == Generators
 | |
| #
 | |
| # A "generator" provides an implementation of enumerating pseudo-prime
 | |
| # numbers and it remembers the position of enumeration and upper bound.
 | |
| # Furthermore, it is a external iterator of prime enumeration which is
 | |
| # compatible to an Enumerator.
 | |
| #
 | |
| # +Prime+::+PseudoPrimeGenerator+ is the base class for generators.
 | |
| # There are few implementations of generator.
 | |
| #
 | |
| # [+Prime+::+EratosthenesGenerator+]
 | |
| #   Uses eratosthenes's sieve.
 | |
| # [+Prime+::+TrialDivisionGenerator+]
 | |
| #   Uses the trial division method.
 | |
| # [+Prime+::+Generator23+]
 | |
| #   Generates all positive integers which is not divided by 2 nor 3.
 | |
| #   This sequence is very bad as a pseudo-prime sequence. But this
 | |
| #   is faster and uses much less memory than other generators. So,
 | |
| #   it is suitable for factorizing an integer which is not large but
 | |
| #   has many prime factors. e.g. for Prime#prime? .
 | |
| 
 | |
| class Prime
 | |
|   include Enumerable
 | |
|   @the_instance = Prime.new
 | |
| 
 | |
|   # obsolete. Use +Prime+::+instance+ or class methods of +Prime+.
 | |
|   def initialize
 | |
|     @generator = EratosthenesGenerator.new
 | |
|     extend OldCompatibility
 | |
|     warn "Prime::new is obsolete. use Prime::instance or class methods of Prime."
 | |
|   end
 | |
| 
 | |
|   class << self
 | |
|     extend Forwardable
 | |
|     include Enumerable
 | |
|     # Returns the default instance of Prime.
 | |
|     def instance; @the_instance end
 | |
| 
 | |
|     def method_added(method) # :nodoc:
 | |
|       (class<< self;self;end).def_delegator :instance, method
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   # Iterates the given block over all prime numbers.
 | |
|   #
 | |
|   # == Parameters
 | |
|   #
 | |
|   # +ubound+::
 | |
|   #   Optional. An arbitrary positive number.
 | |
|   #   The upper bound of enumeration. The method enumerates
 | |
|   #   prime numbers infinitely if +ubound+ is nil.
 | |
|   # +generator+::
 | |
|   #   Optional. An implementation of pseudo-prime generator.
 | |
|   #
 | |
|   # == Return value
 | |
|   #
 | |
|   # An evaluated value of the given block at the last time.
 | |
|   # Or an enumerator which is compatible to an +Enumerator+
 | |
|   # if no block given.
 | |
|   #
 | |
|   # == Description
 | |
|   #
 | |
|   # Calls +block+ once for each prime number, passing the prime as
 | |
|   # a parameter.
 | |
|   #
 | |
|   # +ubound+::
 | |
|   #   Upper bound of prime numbers. The iterator stops after
 | |
|   #   yields all prime numbers p <= +ubound+.
 | |
|   #
 | |
|   # == Note
 | |
|   #
 | |
|   # +Prime+.+new+ returns a object extended by +Prime+::+OldCompatibility+
 | |
|   # in order to compatibility to Ruby 1.8, and +Prime+#each is overwritten
 | |
|   # by +Prime+::+OldCompatibility+#+each+.
 | |
|   #
 | |
|   # +Prime+.+new+ is now obsolete. Use +Prime+.+instance+.+each+ or simply
 | |
|   # +Prime+.+each+.
 | |
|   def each(ubound = nil, generator = EratosthenesGenerator.new, &block)
 | |
|     generator.upper_bound = ubound
 | |
|     generator.each(&block)
 | |
|   end
 | |
| 
 | |
| 
 | |
|   # Returns true if +value+ is prime, false for a composite.
 | |
|   #
 | |
|   # == Parameters
 | |
|   #
 | |
|   # +value+:: an arbitrary integer to be checked.
 | |
|   # +generator+:: optional. A pseudo-prime generator.
 | |
|   def prime?(value, generator = Prime::Generator23.new)
 | |
|     value = -value if value < 0
 | |
|     return false if value < 2
 | |
|     for num in generator
 | |
|       q,r = value.divmod num
 | |
|       return true if q < num
 | |
|       return false if r == 0
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   # Re-composes a prime factorization and returns the product.
 | |
|   #
 | |
|   # == Parameters
 | |
|   # +pd+:: Array of pairs of integers. The each internal
 | |
|   #        pair consists of a prime number -- a prime factor --
 | |
|   #        and a natural number -- an exponent.
 | |
|   #
 | |
|   # == Example
 | |
|   # For <tt>[[p_1, e_1], [p_2, e_2], ...., [p_n, e_n]]</tt>, it returns:
 | |
|   #
 | |
|   #   p_1**e_1 * p_2**e_2 * .... * p_n**e_n.
 | |
|   #
 | |
|   #   Prime.int_from_prime_division([[2,2], [3,1]])  #=> 12
 | |
|   def int_from_prime_division(pd)
 | |
|     pd.inject(1){|value, (prime, index)|
 | |
|       value *= prime**index
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   # Returns the factorization of +value+.
 | |
|   #
 | |
|   # == Parameters
 | |
|   # +value+:: An arbitrary integer.
 | |
|   # +generator+:: Optional. A pseudo-prime generator.
 | |
|   #               +generator+.succ must return the next
 | |
|   #               pseudo-prime number in the ascendent
 | |
|   #               order. It must generate all prime numbers,
 | |
|   #               but may generate non prime numbers.
 | |
|   #
 | |
|   # === Exceptions
 | |
|   # +ZeroDivisionError+:: when +value+ is zero.
 | |
|   #
 | |
|   # == Example
 | |
|   # For an arbitrary integer:
 | |
|   #
 | |
|   #   n = p_1**e_1 * p_2**e_2 * .... * p_n**e_n,
 | |
|   #
 | |
|   # prime_division(n) returns:
 | |
|   #
 | |
|   #   [[p_1, e_1], [p_2, e_2], ...., [p_n, e_n]].
 | |
|   #
 | |
|   #   Prime.prime_division(12) #=> [[2,2], [3,1]]
 | |
|   #
 | |
|   def prime_division(value, generator= Prime::Generator23.new)
 | |
|     raise ZeroDivisionError if value == 0
 | |
|     if value < 0
 | |
|       value = -value
 | |
|       pv = [[-1, 1]]
 | |
|     else
 | |
|       pv = []
 | |
|     end
 | |
|     for prime in generator
 | |
|       count = 0
 | |
|       while (value1, mod = value.divmod(prime)
 | |
|              mod) == 0
 | |
|         value = value1
 | |
|         count += 1
 | |
|       end
 | |
|       if count != 0
 | |
|         pv.push [prime, count]
 | |
|       end
 | |
|       break if value1 <= prime
 | |
|     end
 | |
|     if value > 1
 | |
|       pv.push [value, 1]
 | |
|     end
 | |
|     return pv
 | |
|   end
 | |
| 
 | |
|   # An abstract class for enumerating pseudo-prime numbers.
 | |
|   #
 | |
|   # Concrete subclasses should override succ, next, rewind.
 | |
|   class PseudoPrimeGenerator
 | |
|     include Enumerable
 | |
| 
 | |
|     def initialize(ubound = nil)
 | |
|       @ubound = ubound
 | |
|     end
 | |
| 
 | |
|     def upper_bound=(ubound)
 | |
|       @ubound = ubound
 | |
|     end
 | |
|     def upper_bound
 | |
|       @ubound
 | |
|     end
 | |
| 
 | |
|     # returns the next pseudo-prime number, and move the internal
 | |
|     # position forward.
 | |
|     #
 | |
|     # +PseudoPrimeGenerator+#succ raises +NotImplementedError+.
 | |
|     def succ
 | |
|       raise NotImplementedError, "need to define `succ'"
 | |
|     end
 | |
| 
 | |
|     # alias of +succ+.
 | |
|     def next
 | |
|       raise NotImplementedError, "need to define `next'"
 | |
|     end
 | |
| 
 | |
|     # Rewinds the internal position for enumeration.
 | |
|     #
 | |
|     # See +Enumerator+#rewind.
 | |
|     def rewind
 | |
|       raise NotImplementedError, "need to define `rewind'"
 | |
|     end
 | |
| 
 | |
|     # Iterates the given block for each prime numbers.
 | |
|     def each(&block)
 | |
|       return self.dup unless block
 | |
|       if @ubound
 | |
|         last_value = nil
 | |
|         loop do
 | |
|           prime = succ
 | |
|           break last_value if prime > @ubound
 | |
|           last_value = block.call(prime)
 | |
|         end
 | |
|       else
 | |
|         loop do
 | |
|           block.call(succ)
 | |
|         end
 | |
|       end
 | |
|     end
 | |
| 
 | |
|     # see +Enumerator+#with_index.
 | |
|     alias with_index each_with_index
 | |
| 
 | |
|     # see +Enumerator+#with_object.
 | |
|     def with_object(obj)
 | |
|       return enum_for(:with_object) unless block_given?
 | |
|       each do |prime|
 | |
|         yield prime, obj
 | |
|       end
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   # An implementation of +PseudoPrimeGenerator+.
 | |
|   #
 | |
|   # Uses +EratosthenesSieve+.
 | |
|   class EratosthenesGenerator < PseudoPrimeGenerator
 | |
|     def initialize
 | |
|       @last_prime = nil
 | |
|       super
 | |
|     end
 | |
| 
 | |
|     def succ
 | |
|       @last_prime = @last_prime ? EratosthenesSieve.instance.next_to(@last_prime) : 2
 | |
|     end
 | |
|     def rewind
 | |
|       initialize
 | |
|     end
 | |
|     alias next succ
 | |
|   end
 | |
| 
 | |
|   # An implementation of +PseudoPrimeGenerator+ which uses
 | |
|   # a prime table generated by trial division.
 | |
|   class TrialDivisionGenerator<PseudoPrimeGenerator
 | |
|     def initialize
 | |
|       @index = -1
 | |
|       super
 | |
|     end
 | |
| 
 | |
|     def succ
 | |
|       TrialDivision.instance[@index += 1]
 | |
|     end
 | |
|     def rewind
 | |
|       initialize
 | |
|     end
 | |
|     alias next succ
 | |
|   end
 | |
| 
 | |
|   # Generates all integer which are greater than 2 and
 | |
|   # are not divided by 2 nor 3.
 | |
|   #
 | |
|   # This is a pseudo-prime generator, suitable on
 | |
|   # checking primality of a integer by brute force
 | |
|   # method.
 | |
|   class Generator23<PseudoPrimeGenerator
 | |
|     def initialize
 | |
|       @prime = 1
 | |
|       @step = nil
 | |
|       super
 | |
|     end
 | |
| 
 | |
|     def succ
 | |
|       loop do
 | |
|         if (@step)
 | |
|           @prime += @step
 | |
|           @step = 6 - @step
 | |
|         else
 | |
|           case @prime
 | |
|           when 1; @prime = 2
 | |
|           when 2; @prime = 3
 | |
|           when 3; @prime = 5; @step = 2
 | |
|           end
 | |
|         end
 | |
|         return @prime
 | |
|       end
 | |
|     end
 | |
|     alias next succ
 | |
|     def rewind
 | |
|       initialize
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   # Internal use. An implementation of prime table by trial division method.
 | |
|   class TrialDivision
 | |
|     include Singleton
 | |
| 
 | |
|     def initialize # :nodoc:
 | |
|       # These are included as class variables to cache them for later uses.  If memory
 | |
|       #   usage is a problem, they can be put in Prime#initialize as instance variables.
 | |
| 
 | |
|       # There must be no primes between @primes[-1] and @next_to_check.
 | |
|       @primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101]
 | |
|       # @next_to_check % 6 must be 1.
 | |
|       @next_to_check = 103            # @primes[-1] - @primes[-1] % 6 + 7
 | |
|       @ulticheck_index = 3            # @primes.index(@primes.reverse.find {|n|
 | |
|       #   n < Math.sqrt(@@next_to_check) })
 | |
|       @ulticheck_next_squared = 121   # @primes[@ulticheck_index + 1] ** 2
 | |
|     end
 | |
| 
 | |
|     # Returns the cached prime numbers.
 | |
|     def cache
 | |
|       return @primes
 | |
|     end
 | |
|     alias primes cache
 | |
|     alias primes_so_far cache
 | |
| 
 | |
|     # Returns the +index+th prime number.
 | |
|     #
 | |
|     # +index+ is a 0-based index.
 | |
|     def [](index)
 | |
|       while index >= @primes.length
 | |
|         # Only check for prime factors up to the square root of the potential primes,
 | |
|         #   but without the performance hit of an actual square root calculation.
 | |
|         if @next_to_check + 4 > @ulticheck_next_squared
 | |
|           @ulticheck_index += 1
 | |
|           @ulticheck_next_squared = @primes.at(@ulticheck_index + 1) ** 2
 | |
|         end
 | |
|         # Only check numbers congruent to one and five, modulo six. All others
 | |
| 
 | |
|         #   are divisible by two or three.  This also allows us to skip checking against
 | |
|         #   two and three.
 | |
|         @primes.push @next_to_check if @primes[2..@ulticheck_index].find {|prime| @next_to_check % prime == 0 }.nil?
 | |
|         @next_to_check += 4
 | |
|         @primes.push @next_to_check if @primes[2..@ulticheck_index].find {|prime| @next_to_check % prime == 0 }.nil?
 | |
|         @next_to_check += 2
 | |
|       end
 | |
|       return @primes[index]
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   # Internal use. An implementation of eratosthenes's sieve
 | |
|   class EratosthenesSieve
 | |
|     include Singleton
 | |
| 
 | |
|     BITS_PER_ENTRY = 16  # each entry is a set of 16-bits in a Fixnum
 | |
|     NUMS_PER_ENTRY = BITS_PER_ENTRY * 2 # twiced because even numbers are omitted
 | |
|     ENTRIES_PER_TABLE = 8
 | |
|     NUMS_PER_TABLE = NUMS_PER_ENTRY * ENTRIES_PER_TABLE
 | |
|     FILLED_ENTRY = (1 << NUMS_PER_ENTRY) - 1
 | |
| 
 | |
|     def initialize # :nodoc:
 | |
|       # bitmap for odd prime numbers less than 256.
 | |
|       # For an arbitrary odd number n, @tables[i][j][k] is
 | |
|       # * 1 if n is prime,
 | |
|       # * 0 if n is composite,
 | |
|       # where i,j,k = indices(n)
 | |
|       @tables = [[0xcb6e, 0x64b4, 0x129a, 0x816d, 0x4c32, 0x864a, 0x820d, 0x2196].freeze]
 | |
|     end
 | |
| 
 | |
|     # returns the least odd prime number which is greater than +n+.
 | |
|     def next_to(n)
 | |
|       n = (n-1).div(2)*2+3 # the next odd number to given n
 | |
|       table_index, integer_index, bit_index = indices(n)
 | |
|       loop do
 | |
|         extend_table until @tables.length > table_index
 | |
|         for j in integer_index...ENTRIES_PER_TABLE
 | |
|           if !@tables[table_index][j].zero?
 | |
|             for k in bit_index...BITS_PER_ENTRY
 | |
|               return NUMS_PER_TABLE*table_index + NUMS_PER_ENTRY*j + 2*k+1 if !@tables[table_index][j][k].zero?
 | |
|             end
 | |
|           end
 | |
|           bit_index = 0
 | |
|         end
 | |
|         table_index += 1; integer_index = 0
 | |
|       end
 | |
|     end
 | |
| 
 | |
|     private
 | |
|     # for an odd number +n+, returns (i, j, k) such that @tables[i][j][k] represents primarity of the number
 | |
|     def indices(n)
 | |
|       #   binary digits of n: |0|1|2|3|4|5|6|7|8|9|10|11|....
 | |
|       #   indices:            |-|    k  |  j  |     i
 | |
|       # because of NUMS_PER_ENTRY, NUMS_PER_TABLE
 | |
| 
 | |
|       k = (n & 0b00011111) >> 1
 | |
|       j = (n & 0b11100000) >> 5
 | |
|       i = n >> 8
 | |
|       return i, j, k
 | |
|     end
 | |
| 
 | |
|     def extend_table
 | |
|       lbound = NUMS_PER_TABLE * @tables.length
 | |
|       ubound = lbound + NUMS_PER_TABLE
 | |
|       new_table = [FILLED_ENTRY] * ENTRIES_PER_TABLE # which represents primarity in lbound...ubound
 | |
|       (3..Integer(Math.sqrt(ubound))).step(2) do |p|
 | |
|         i, j, k = indices(p)
 | |
|         next if @tables[i][j][k].zero?
 | |
| 
 | |
|         start = (lbound.div(p)+1)*p  # least multiple of p which is >= lbound
 | |
|         start += p if start.even?
 | |
|         (start...ubound).step(2*p) do |n|
 | |
|           _, j, k = indices(n)
 | |
|           new_table[j] &= FILLED_ENTRY^(1<<k)
 | |
|         end
 | |
|       end
 | |
|       @tables << new_table.freeze
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   # Provides a +Prime+ object with compatibility to Ruby 1.8 when instantiated via +Prime+.+new+.
 | |
|   module OldCompatibility
 | |
|     # Returns the next prime number and forwards internal pointer.
 | |
|     def succ
 | |
|       @generator.succ
 | |
|     end
 | |
|     alias next succ
 | |
| 
 | |
|     # Overwrites Prime#each.
 | |
|     #
 | |
|     # Iterates the given block over all prime numbers. Note that enumeration
 | |
|     # starts from the current position of internal pointer, not rewound.
 | |
|     def each(&block)
 | |
|       return @generator.dup unless block_given?
 | |
|       loop do
 | |
|         yield succ
 | |
|       end
 | |
|     end
 | |
|   end
 | |
| end
 |