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…
Reference in a new issue