mirror of
				https://github.com/ruby/ruby.git
				synced 2022-11-09 12:17:21 -05:00 
			
		
		
		
	* lib/mathn.rb (Integer): moved into prime.rb.
(Prime): ditto.
* lib/prime.rb (Integer): moved from mathn.rb.
  (Integer.each_prime): added.
  (Integer#prime?): added.
  (Prime): moved from mathn.rb.
    Its implmentation was rewritten. see [ruby-dev:35863].
    And patched by Keiju ISHITSUKA <keiju@ishitsuka.com>,
    see [ruby-dev:36128].
  (Prime.new):                     obsolete.
  (Prime.instance):                added.
  (Prime.each):                    added.
  (Prime.int_from_prime_division): added.
  (Prime.prime_division):          added.
  (Prime.prime?):                  added.
    Patch by TOYOFUKU Chikanobu
    <nobu_toyofuku at nifty.com> in [ruby-dev:36067].
  (Prime.cache):                   removed.
  (Prime.primes):                  removed.
  (Prime.primes_so_far):           removed.
  (Prime#int_from_prime_division): added.
  (Prime#prime_division):          added.
  (Prime#prime?):                  added.
  (Prime#primes):                  removed.
  (Prime#primes_so_far):           removed.
  (Prime::PseudoPrmeGenerator):    added.
  (Prime::EratosthenesGenerator):  added.
  (Prime::TrialDivisionGenerator): added.
  (Prime::Generator23):            added.
  (Prime::TrialDivision):          added.
    Extracted from the previous implementation of Prime
    by Keiju ISHITSUKA.
  (Prime::EratosthenesSieve):      added.
* lib/.document (prime.rb): added
* lib/README (prime.rb): added
* test/test_prime.rb: added.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@19095 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
			
			
This commit is contained in:
		
							parent
							
								
									9cab7d15ca
								
							
						
					
					
						commit
						fce093432e
					
				
					 6 changed files with 618 additions and 95 deletions
				
			
		
							
								
								
									
										43
									
								
								ChangeLog
									
										
									
									
									
								
							
							
						
						
									
										43
									
								
								ChangeLog
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -1,3 +1,46 @@
 | 
			
		|||
Wed Sep  3 22:31:11 2008  Yuki Sonoda (Yugui)  <yugui@yugui.jp>
 | 
			
		||||
 | 
			
		||||
	* lib/mathn.rb (Integer): moved into prime.rb.
 | 
			
		||||
	  (Prime): ditto.
 | 
			
		||||
 | 
			
		||||
	* lib/prime.rb (Integer): moved from mathn.rb.
 | 
			
		||||
	  (Integer.each_prime): added.
 | 
			
		||||
	  (Integer#prime?): added.
 | 
			
		||||
	  (Prime): moved from mathn.rb. 
 | 
			
		||||
	    Its implmentation was rewritten. see [ruby-dev:35863].
 | 
			
		||||
	    And patched by Keiju ISHITSUKA <keiju@ishitsuka.com>,
 | 
			
		||||
	    see [ruby-dev:36128]. 
 | 
			
		||||
	  (Prime.new):                     obsolete.
 | 
			
		||||
	  (Prime.instance):                added.
 | 
			
		||||
	  (Prime.each):                    added.
 | 
			
		||||
	  (Prime.int_from_prime_division): added.
 | 
			
		||||
	  (Prime.prime_division):          added.
 | 
			
		||||
	  (Prime.prime?):                  added.
 | 
			
		||||
	    Patch by TOYOFUKU Chikanobu 
 | 
			
		||||
	    <nobu_toyofuku at nifty.com> in [ruby-dev:36067].
 | 
			
		||||
	  (Prime.cache):                   removed.
 | 
			
		||||
	  (Prime.primes):                  removed.
 | 
			
		||||
	  (Prime.primes_so_far):           removed.
 | 
			
		||||
	  (Prime#int_from_prime_division): added.
 | 
			
		||||
	  (Prime#prime_division):          added.
 | 
			
		||||
	  (Prime#prime?):                  added.
 | 
			
		||||
	  (Prime#primes):                  removed.
 | 
			
		||||
	  (Prime#primes_so_far):           removed.
 | 
			
		||||
	  (Prime::PseudoPrmeGenerator):    added.
 | 
			
		||||
	  (Prime::EratosthenesGenerator):  added.
 | 
			
		||||
	  (Prime::TrialDivisionGenerator): added.
 | 
			
		||||
	  (Prime::Generator23):            added.
 | 
			
		||||
	  (Prime::TrialDivision):          added.
 | 
			
		||||
	    Extracted from the previous implementation of Prime
 | 
			
		||||
	    by Keiju ISHITSUKA.
 | 
			
		||||
	  (Prime::EratosthenesSieve):      added.
 | 
			
		||||
 | 
			
		||||
	* lib/.document (prime.rb): added
 | 
			
		||||
 | 
			
		||||
	* lib/README (prime.rb): added
 | 
			
		||||
 | 
			
		||||
	* test/test_prime.rb: added.
 | 
			
		||||
 | 
			
		||||
Wed Sep  3 21:49:00 2008  David A. Black <dblack@rubypal.com>
 | 
			
		||||
 | 
			
		||||
        * lib/scanf.rb: fixed bug involving matching literal '['
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -59,6 +59,7 @@ pathname.rb
 | 
			
		|||
ping.rb
 | 
			
		||||
pp.rb
 | 
			
		||||
prettyprint.rb
 | 
			
		||||
prime.rb
 | 
			
		||||
profile.rb
 | 
			
		||||
profiler.rb
 | 
			
		||||
pstore.rb
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -42,6 +42,7 @@ parsedate.rb	parses date string (obsolete)
 | 
			
		|||
pathname.rb	Object-Oriented Pathname Class
 | 
			
		||||
pp.rb		pretty print objects
 | 
			
		||||
prettyprint.rb	pretty printing algorithm
 | 
			
		||||
prime.rb        prime numbers and factorization
 | 
			
		||||
profile.rb	runs ruby profiler
 | 
			
		||||
profiler.rb	ruby profiler module
 | 
			
		||||
pstore.rb	persistent object strage using marshal
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										96
									
								
								lib/mathn.rb
									
										
									
									
									
								
							
							
						
						
									
										96
									
								
								lib/mathn.rb
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -12,101 +12,7 @@
 | 
			
		|||
require "complex.rb"
 | 
			
		||||
require "rational.rb"
 | 
			
		||||
require "matrix.rb"
 | 
			
		||||
 | 
			
		||||
class Integer
 | 
			
		||||
 | 
			
		||||
  def Integer.from_prime_division(pd)
 | 
			
		||||
    value = 1
 | 
			
		||||
    for prime, index in pd
 | 
			
		||||
      value *= prime**index
 | 
			
		||||
    end
 | 
			
		||||
    value
 | 
			
		||||
  end
 | 
			
		||||
  
 | 
			
		||||
  def prime_division
 | 
			
		||||
    raise ZeroDivisionError if self == 0
 | 
			
		||||
    ps = Prime.new
 | 
			
		||||
    value = self
 | 
			
		||||
    pv = []
 | 
			
		||||
    for prime in ps
 | 
			
		||||
      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 prime * prime  >= value
 | 
			
		||||
    end
 | 
			
		||||
    if value > 1
 | 
			
		||||
      pv.push [value, 1]
 | 
			
		||||
    end
 | 
			
		||||
    return pv
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
  
 | 
			
		||||
class Prime
 | 
			
		||||
  include Enumerable
 | 
			
		||||
  # 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
 | 
			
		||||
 | 
			
		||||
  class << self
 | 
			
		||||
    # Return the prime cache.
 | 
			
		||||
    def cache
 | 
			
		||||
      return @@primes
 | 
			
		||||
    end
 | 
			
		||||
    alias primes cache
 | 
			
		||||
    alias primes_so_far cache
 | 
			
		||||
  end
 | 
			
		||||
  
 | 
			
		||||
  def initialize
 | 
			
		||||
    @index = -1
 | 
			
		||||
  end
 | 
			
		||||
  
 | 
			
		||||
  # Return primes given by this instance so far.
 | 
			
		||||
  def primes
 | 
			
		||||
    return @@primes[0, @index + 1]
 | 
			
		||||
  end
 | 
			
		||||
  alias primes_so_far primes
 | 
			
		||||
  
 | 
			
		||||
  def succ
 | 
			
		||||
    @index += 1
 | 
			
		||||
    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
 | 
			
		||||
  alias next succ
 | 
			
		||||
 | 
			
		||||
  def each
 | 
			
		||||
    return to_enum(:each) unless block_given?
 | 
			
		||||
    loop do
 | 
			
		||||
      yield succ
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
require "prime.rb"
 | 
			
		||||
 | 
			
		||||
class Fixnum
 | 
			
		||||
  remove_method :/
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										446
									
								
								lib/prime.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										446
									
								
								lib/prime.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,446 @@
 | 
			
		|||
#
 | 
			
		||||
# = 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
 | 
			
		||||
#
 | 
			
		||||
# == 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.
 | 
			
		||||
# Futhermore, 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
 | 
			
		||||
 | 
			
		||||
  module OldCompatibility
 | 
			
		||||
    def succ
 | 
			
		||||
      @generator.succ
 | 
			
		||||
    end
 | 
			
		||||
    alias next succ
 | 
			
		||||
 | 
			
		||||
    def each(&block)
 | 
			
		||||
      loop do
 | 
			
		||||
	yield succ
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
  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 numer, passing the prime as
 | 
			
		||||
  # a parameter.
 | 
			
		||||
  #
 | 
			
		||||
  # +ubound+::
 | 
			
		||||
  #   Upper bound of prime numbers. The iterator stops after 
 | 
			
		||||
  #   yields all prime numbers p <= +ubound+.
 | 
			
		||||
  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)
 | 
			
		||||
    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 [[p_1, e_1], [p_2, e_2], ...., [p_n, e_n]], 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
 | 
			
		||||
    pv = []
 | 
			
		||||
    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.
 | 
			
		||||
    # +ubound+:: 
 | 
			
		||||
    def each(&block)
 | 
			
		||||
      return self.dup unless block
 | 
			
		||||
      if @ubound
 | 
			
		||||
	loop do
 | 
			
		||||
	  p = succ
 | 
			
		||||
	  break if p > @ubound
 | 
			
		||||
	  block.call p
 | 
			
		||||
	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
 | 
			
		||||
    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
 | 
			
		||||
    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
 | 
			
		||||
    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
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  # 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
 | 
			
		||||
 | 
			
		||||
  # An implementation of eratosthenes's sieve
 | 
			
		||||
  class EratosthenesSieve
 | 
			
		||||
    include Singleton
 | 
			
		||||
 | 
			
		||||
    def initialize # :nodoc:
 | 
			
		||||
      # bitmap for odd prime numbers less than 256.
 | 
			
		||||
      # For an arbitrary odd number n, @table[i][j] is 1 when n is prime where i,j = n.divmod(32) .
 | 
			
		||||
      @table = [0xcb6e, 0x64b4, 0x129a, 0x816d, 0x4c32, 0x864a, 0x820d, 0x2196]
 | 
			
		||||
    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 of given n
 | 
			
		||||
      i,j = n.divmod(32)
 | 
			
		||||
      loop do
 | 
			
		||||
	extend_table until @table.length > i
 | 
			
		||||
	if !@table[i].zero?
 | 
			
		||||
	  (j...32).step(2) do |j|
 | 
			
		||||
	    return 32*i+j if !@table[i][j.div(2)].zero?
 | 
			
		||||
	  end
 | 
			
		||||
	end
 | 
			
		||||
	i += 1; j = 1
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    private
 | 
			
		||||
    def extend_table
 | 
			
		||||
      orig_len = @table.length
 | 
			
		||||
      new_len = [orig_len**2, orig_len+256].min
 | 
			
		||||
      lbound = orig_len*32
 | 
			
		||||
      ubound = new_len*32
 | 
			
		||||
      @table.fill(0xFFFF, orig_len...new_len)
 | 
			
		||||
      (3..Integer(Math.sqrt(ubound))).step(2) do |p|
 | 
			
		||||
	i, j = p.divmod(32)
 | 
			
		||||
	next if @table[i][j.div(2)].zero?
 | 
			
		||||
 | 
			
		||||
	start = (lbound.div(2*p)*2+1)*p    # odd multiple of p which is greater than or equal to lbound
 | 
			
		||||
	(start...ubound).step(2*p) do |n|
 | 
			
		||||
	  i, j = n.divmod(32)
 | 
			
		||||
	  @table[i] &= 0xFFFF ^ (1<<(j.div(2)))
 | 
			
		||||
	end
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
							
								
								
									
										126
									
								
								test/test_prime.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										126
									
								
								test/test_prime.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,126 @@
 | 
			
		|||
require 'test/unit'
 | 
			
		||||
require 'prime'
 | 
			
		||||
require 'stringio'
 | 
			
		||||
 | 
			
		||||
class TestPrime < Test::Unit::TestCase
 | 
			
		||||
  # The first 100 prime numbers
 | 
			
		||||
  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, 103, 107, 109, 113, 127, 131, 
 | 
			
		||||
    137, 139, 149, 151, 157, 163, 167, 173, 179, 
 | 
			
		||||
    181, 191, 193, 197, 199, 211, 223, 227, 229, 
 | 
			
		||||
    233, 239, 241, 251, 257, 263, 269, 271, 277, 
 | 
			
		||||
    281, 283, 293, 307, 311, 313, 317, 331, 337, 
 | 
			
		||||
    347, 349, 353, 359, 367, 373, 379, 383, 389, 
 | 
			
		||||
    397, 401, 409, 419, 421, 431, 433, 439, 443, 
 | 
			
		||||
    449, 457, 461, 463, 467, 479, 487, 491, 499, 
 | 
			
		||||
    503, 509, 521, 523, 541,
 | 
			
		||||
  ]
 | 
			
		||||
  def test_each
 | 
			
		||||
    primes = []
 | 
			
		||||
    Prime.each do |p|
 | 
			
		||||
      break if p > 541
 | 
			
		||||
      primes << p
 | 
			
		||||
    end
 | 
			
		||||
    assert_equal PRIMES, primes
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def test_each_by_prime_number_theorem
 | 
			
		||||
    3.upto(15) do |i|
 | 
			
		||||
      max = 2**i
 | 
			
		||||
      primes = []
 | 
			
		||||
      Prime.each do |p|
 | 
			
		||||
        break if p >= max
 | 
			
		||||
        primes << p
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      # Prime number theorem
 | 
			
		||||
      assert primes.length >= max/Math.log(max)  
 | 
			
		||||
      delta = 0.05
 | 
			
		||||
      li = (2..max).step(delta).inject(0){|sum,x| sum + delta/Math.log(x)}
 | 
			
		||||
      assert primes.length <= li
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def test_each_without_block
 | 
			
		||||
    enum = Prime.each
 | 
			
		||||
    assert enum.respond_to?(:each)
 | 
			
		||||
    assert enum.kind_of?(Enumerable)
 | 
			
		||||
    assert enum.respond_to?(:with_index)
 | 
			
		||||
    assert enum.respond_to?(:next)
 | 
			
		||||
    assert enum.respond_to?(:succ)
 | 
			
		||||
    assert enum.respond_to?(:rewind)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def test_new
 | 
			
		||||
    buf = StringIO.new('', 'w')
 | 
			
		||||
    orig, $stderr = $stderr, buf
 | 
			
		||||
 | 
			
		||||
    enum = Prime.new
 | 
			
		||||
    assert !buf.string.empty?
 | 
			
		||||
    $stderr = orig
 | 
			
		||||
 | 
			
		||||
    assert enum.respond_to?(:each)
 | 
			
		||||
    assert enum.kind_of?(Enumerable)
 | 
			
		||||
    assert enum.respond_to?(:succ)
 | 
			
		||||
 | 
			
		||||
    assert Prime === enum
 | 
			
		||||
  ensure
 | 
			
		||||
    $stderr = orig
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def test_enumerator_succ
 | 
			
		||||
    enum = Prime.each
 | 
			
		||||
    assert_equal PRIMES[0, 50], 50.times.map{ enum.succ }
 | 
			
		||||
    assert_equal PRIMES[50, 50], 50.times.map{ enum.succ }
 | 
			
		||||
    enum.rewind
 | 
			
		||||
    assert_equal PRIMES[0, 100], 100.times.map{ enum.succ }
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def test_enumerator_with_index
 | 
			
		||||
    enum = Prime.each
 | 
			
		||||
    last = -1
 | 
			
		||||
    enum.with_index do |p,i|
 | 
			
		||||
      break if i >= 100
 | 
			
		||||
      assert_equal last+1, i
 | 
			
		||||
      assert_equal PRIMES[i], p
 | 
			
		||||
      last = i
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  class TestInteger < Test::Unit::TestCase
 | 
			
		||||
    def test_prime_division
 | 
			
		||||
      pd = PRIMES.inject(&:*).prime_division
 | 
			
		||||
      assert_equal PRIMES.map{|p| [p, 1]}, pd
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def test_from_prime_division
 | 
			
		||||
      assert_equal PRIMES.inject(&:*), Integer.from_prime_division(PRIMES.map{|p| [p,1]})
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def test_prime?
 | 
			
		||||
      # small primes
 | 
			
		||||
      assert 2.prime?
 | 
			
		||||
      assert 3.prime?
 | 
			
		||||
 | 
			
		||||
      # squared prime
 | 
			
		||||
      assert !4.prime?
 | 
			
		||||
      assert !9.prime?
 | 
			
		||||
 | 
			
		||||
      # mersenne numbers
 | 
			
		||||
      assert (2**31-1).prime?
 | 
			
		||||
      assert !(2**32-1).prime?
 | 
			
		||||
 | 
			
		||||
      # fermat numbers
 | 
			
		||||
      assert (2**(2**4)+1).prime?
 | 
			
		||||
      assert !(2**(2**5)+1).prime? # Euler!
 | 
			
		||||
 | 
			
		||||
      # large composite
 | 
			
		||||
      assert !((2**13-1) * (2**17-1)).prime?
 | 
			
		||||
 | 
			
		||||
      # factorial
 | 
			
		||||
      assert !(2...100).inject(&:*).prime?
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue