From 7bbf2f308580f468802cd7d32c94fce1b9f1779e Mon Sep 17 00:00:00 2001 From: drbrain Date: Wed, 18 May 2011 21:19:18 +0000 Subject: * lib: Convert tabs to spaces for ruby files per http://redmine.ruby-lang.org/projects/ruby/wiki/DeveloperHowto#coding-style Patch by Steve Klabnik [Ruby 1.9 - Bug #4730] Patch by Jason Dew [Ruby 1.9 - Feature #4718] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@31635 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- lib/prime.rb | 674 +++++++++++++++++++++++++++++------------------------------ 1 file changed, 337 insertions(+), 337 deletions(-) (limited to 'lib/prime.rb') diff --git a/lib/prime.rb b/lib/prime.rb index a40d90e3d7..8d8598b9e1 100644 --- a/lib/prime.rb +++ b/lib/prime.rb @@ -99,397 +99,397 @@ class Prime def method_added(method) # :nodoc: (class<< self;self;end).def_delegator :instance, method - end 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 +# 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 +# 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 [[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 +# 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 - 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 +# 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 value > 1 - pv.push [value, 1] + if count != 0 + pv.push [prime, count] end - return pv + 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 +# 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 initialize(ubound = nil) + @ubound = ubound + end - def upper_bound=(ubound) - @ubound = ubound - end - def upper_bound - @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 + # 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 + # 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 + # 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 + # 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_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 + # 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 +# 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 + 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= @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 + # 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 - return @primes[index] + # 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 +# 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 + # 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 + 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<= lbound + start += p if start.even? + (start...ubound).step(2*p) do |n| + _, j, k = indices(n) + new_table[j] &= FILLED_ENTRY^(1<