Promote prime to the bundled gems
This commit is contained in:
parent
eae7fd0ea3
commit
c9178c1127
Notes:
git
2021-05-27 14:42:39 +09:00
@ -205,10 +205,6 @@ Yukihiro Matsumoto (matz)
|
||||
Tanaka Akira (akr)
|
||||
https://github.com/ruby/prettyprint
|
||||
https://rubygems.org/gems/prettyprint
|
||||
[lib/prime.rb]
|
||||
Marc-André Lafortune (marcandre)
|
||||
https://github.com/ruby/prime
|
||||
https://rubygems.org/gems/prime
|
||||
[lib/pstore.rb]
|
||||
_unmaintained_
|
||||
https://github.com/ruby/pstore
|
||||
@ -399,6 +395,8 @@ Yukihiro Matsumoto (matz)
|
||||
https://github.com/ruby/rexml
|
||||
[rss]
|
||||
https://github.com/ruby/rss
|
||||
[prime]
|
||||
https://github.com/ruby/prime
|
||||
[rbs]
|
||||
https://github.com/ruby/rbs
|
||||
[typeprof]
|
||||
|
@ -58,7 +58,6 @@ OpenStruct:: Class to build custom data structures, similar to a Hash
|
||||
OpenURI:: An easy-to-use wrapper for Net::HTTP, Net::HTTPS and Net::FTP
|
||||
PP:: Provides a PrettyPrinter for Ruby objects
|
||||
PrettyPrinter:: Implements a pretty printing algorithm for readable structure
|
||||
Prime:: Prime numbers and factorization library
|
||||
PStore:: Implements a file based persistence mechanism based on a Hash
|
||||
Resolv:: Thread-aware DNS resolver library in Ruby
|
||||
resolv-replace.rb:: Replace Socket DNS with Resolv
|
||||
@ -111,5 +110,6 @@ Rake:: Ruby build program with capabilities similar to make
|
||||
Test::Unit:: A compatibility layer for MiniTest
|
||||
REXML:: An XML toolkit for Ruby
|
||||
RSS:: Family of libraries that support various formats of XML "feeds"
|
||||
Prime:: Prime numbers and factorization library
|
||||
RBS:: RBS is a language to describe the structure of Ruby programs
|
||||
TypeProf:: A type analysis tool for Ruby code based on abstract interpretation
|
||||
|
@ -5,5 +5,6 @@ rake 13.0.3 https://github.com/ruby/rake
|
||||
test-unit 3.4.1 https://github.com/test-unit/test-unit 3.4.1
|
||||
rexml 3.2.5 https://github.com/ruby/rexml
|
||||
rss 0.2.9 https://github.com/ruby/rss 0.2.9
|
||||
prime 0.1.2 https://github.com/ruby/prime
|
||||
typeprof 0.14.1 https://github.com/ruby/typeprof
|
||||
rbs 1.2.0 https://github.com/ruby/rbs
|
||||
|
@ -1,28 +0,0 @@
|
||||
begin
|
||||
require_relative "lib/prime"
|
||||
rescue LoadError
|
||||
# for Ruby core repository
|
||||
require_relative "prime"
|
||||
end
|
||||
|
||||
Gem::Specification.new do |spec|
|
||||
spec.name = "prime"
|
||||
spec.version = Prime::VERSION
|
||||
spec.authors = ["Marc-Andre Lafortune"]
|
||||
spec.email = ["ruby-core@marc-andre.ca"]
|
||||
|
||||
spec.summary = %q{Prime numbers and factorization library.}
|
||||
spec.description = %q{Prime numbers and factorization library.}
|
||||
spec.homepage = "https://github.com/ruby/prime"
|
||||
spec.licenses = ["Ruby", "BSD-2-Clause"]
|
||||
|
||||
spec.files = [".gitignore", "Gemfile", "LICENSE.txt", "README.md", "Rakefile", "bin/console", "bin/setup", "lib/prime.rb", "prime.gemspec"]
|
||||
spec.bindir = "exe"
|
||||
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
||||
spec.require_paths = ["lib"]
|
||||
|
||||
spec.required_ruby_version = ">= 2.5.0"
|
||||
|
||||
spec.add_dependency "singleton"
|
||||
spec.add_dependency "forwardable"
|
||||
end
|
561
lib/prime.rb
561
lib/prime.rb
@ -1,561 +0,0 @@
|
||||
# frozen_string_literal: false
|
||||
#
|
||||
# = 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, else returns false.
|
||||
# Not recommended for very big integers (> 10**23).
|
||||
def prime?
|
||||
return self >= 2 if self <= 3
|
||||
|
||||
if (bases = miller_rabin_bases)
|
||||
return miller_rabin_test(bases)
|
||||
end
|
||||
|
||||
return true if self == 5
|
||||
return false unless 30.gcd(self) == 1
|
||||
(7..Integer.sqrt(self)).step(30) do |p|
|
||||
return false if
|
||||
self%(p) == 0 || self%(p+4) == 0 || self%(p+6) == 0 || self%(p+10) == 0 ||
|
||||
self%(p+12) == 0 || self%(p+16) == 0 || self%(p+22) == 0 || self%(p+24) == 0
|
||||
end
|
||||
true
|
||||
end
|
||||
|
||||
MILLER_RABIN_BASES = [
|
||||
[2],
|
||||
[2,3],
|
||||
[31,73],
|
||||
[2,3,5],
|
||||
[2,3,5,7],
|
||||
[2,7,61],
|
||||
[2,13,23,1662803],
|
||||
[2,3,5,7,11],
|
||||
[2,3,5,7,11,13],
|
||||
[2,3,5,7,11,13,17],
|
||||
[2,3,5,7,11,13,17,19,23],
|
||||
[2,3,5,7,11,13,17,19,23,29,31,37],
|
||||
[2,3,5,7,11,13,17,19,23,29,31,37,41],
|
||||
].map!(&:freeze).freeze
|
||||
private_constant :MILLER_RABIN_BASES
|
||||
|
||||
private def miller_rabin_bases
|
||||
# Miller-Rabin's complexity is O(k log^3n).
|
||||
# So we can reduce the complexity by reducing the number of bases tested.
|
||||
# Using values from https://en.wikipedia.org/wiki/Miller%E2%80%93Rabin_primality_test
|
||||
i = case
|
||||
when self < 0xffff then
|
||||
# For small integers, Miller Rabin can be slower
|
||||
# There is no mathematical significance to 0xffff
|
||||
return nil
|
||||
# when self < 2_047 then 0
|
||||
when self < 1_373_653 then 1
|
||||
when self < 9_080_191 then 2
|
||||
when self < 25_326_001 then 3
|
||||
when self < 3_215_031_751 then 4
|
||||
when self < 4_759_123_141 then 5
|
||||
when self < 1_122_004_669_633 then 6
|
||||
when self < 2_152_302_898_747 then 7
|
||||
when self < 3_474_749_660_383 then 8
|
||||
when self < 341_550_071_728_321 then 9
|
||||
when self < 3_825_123_056_546_413_051 then 10
|
||||
when self < 318_665_857_834_031_151_167_461 then 11
|
||||
when self < 3_317_044_064_679_887_385_961_981 then 12
|
||||
else return nil
|
||||
end
|
||||
MILLER_RABIN_BASES[i]
|
||||
end
|
||||
|
||||
private def miller_rabin_test(bases)
|
||||
return false if even?
|
||||
|
||||
r = 0
|
||||
d = self >> 1
|
||||
while d.even?
|
||||
d >>= 1
|
||||
r += 1
|
||||
end
|
||||
|
||||
self_minus_1 = self-1
|
||||
bases.each do |a|
|
||||
x = a.pow(d, self)
|
||||
next if x == 1 || x == self_minus_1 || a == self
|
||||
|
||||
return false if r.times do
|
||||
x = x.pow(2, self)
|
||||
break if x == self_minus_1
|
||||
end
|
||||
end
|
||||
true
|
||||
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
|
||||
#
|
||||
# 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 an external iterator of prime enumeration which is
|
||||
# compatible with an Enumerator.
|
||||
#
|
||||
# +Prime+::+PseudoPrimeGenerator+ is the base class for generators.
|
||||
# There are few implementations of generator.
|
||||
#
|
||||
# [+Prime+::+EratosthenesGenerator+]
|
||||
# Uses Eratosthenes' sieve.
|
||||
# [+Prime+::+TrialDivisionGenerator+]
|
||||
# Uses the trial division method.
|
||||
# [+Prime+::+Generator23+]
|
||||
# Generates all positive integers which are not divisible by either 2 or 3.
|
||||
# This sequence is very bad as a pseudo-prime sequence. But this
|
||||
# is faster and uses much less memory than the 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
|
||||
|
||||
VERSION = "0.1.2"
|
||||
|
||||
include Enumerable
|
||||
include Singleton
|
||||
|
||||
class << self
|
||||
extend Forwardable
|
||||
include Enumerable
|
||||
|
||||
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 it
|
||||
# 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 +obj+ is an Integer and is prime. Also returns
|
||||
# true if +obj+ is a Module that is an ancestor of +Prime+.
|
||||
# Otherwise returns false.
|
||||
def include?(obj)
|
||||
case obj
|
||||
when Integer
|
||||
prime?(obj)
|
||||
when Module
|
||||
Module.instance_method(:include?).bind(Prime).call(obj)
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
# Returns true if +value+ is a prime number, else returns false.
|
||||
# Integer#prime? is much more performant.
|
||||
#
|
||||
# == Parameters
|
||||
#
|
||||
# +value+:: an arbitrary integer to be checked.
|
||||
# +generator+:: optional. A pseudo-prime generator.
|
||||
def prime?(value, generator = Prime::Generator23.new)
|
||||
raise ArgumentError, "Expected a prime generator, got #{generator}" unless generator.respond_to? :each
|
||||
raise ArgumentError, "Expected an integer, got #{value}" unless value.respond_to?(:integer?) && value.integer?
|
||||
return false if value < 2
|
||||
generator.each do |num|
|
||||
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.
|
||||
#
|
||||
# For the decomposition:
|
||||
#
|
||||
# [[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.
|
||||
#
|
||||
# == Parameters
|
||||
# +pd+:: Array of pairs of integers.
|
||||
# Each pair consists of a prime number -- a prime factor --
|
||||
# and a natural number -- its exponent (multiplicity).
|
||||
#
|
||||
# == Example
|
||||
# Prime.int_from_prime_division([[3, 2], [5, 1]]) #=> 45
|
||||
# 3**2 * 5 #=> 45
|
||||
#
|
||||
def int_from_prime_division(pd)
|
||||
pd.inject(1){|value, (prime, index)|
|
||||
value * prime**index
|
||||
}
|
||||
end
|
||||
|
||||
# Returns the factorization of +value+.
|
||||
#
|
||||
# For an arbitrary integer:
|
||||
#
|
||||
# p_1**e_1 * p_2**e_2 * ... * p_n**e_n,
|
||||
#
|
||||
# prime_division returns an array of pairs of integers:
|
||||
#
|
||||
# [[p_1, e_1], [p_2, e_2], ..., [p_n, e_n]].
|
||||
#
|
||||
# Each pair consists of a prime number -- a prime factor --
|
||||
# and a natural number -- its exponent (multiplicity).
|
||||
#
|
||||
# == Parameters
|
||||
# +value+:: An arbitrary integer.
|
||||
# +generator+:: Optional. A pseudo-prime generator.
|
||||
# +generator+.succ must return the next
|
||||
# pseudo-prime number in ascending order.
|
||||
# It must generate all prime numbers,
|
||||
# but may also generate non-prime numbers, too.
|
||||
#
|
||||
# === Exceptions
|
||||
# +ZeroDivisionError+:: when +value+ is zero.
|
||||
#
|
||||
# == Example
|
||||
#
|
||||
# Prime.prime_division(45) #=> [[3, 2], [5, 1]]
|
||||
# 3**2 * 5 #=> 45
|
||||
#
|
||||
def prime_division(value, generator = Prime::Generator23.new)
|
||||
raise ZeroDivisionError if value == 0
|
||||
if value < 0
|
||||
value = -value
|
||||
pv = [[-1, 1]]
|
||||
else
|
||||
pv = []
|
||||
end
|
||||
generator.each do |prime|
|
||||
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
|
||||
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 number.
|
||||
def each
|
||||
return self.dup unless block_given?
|
||||
if @ubound
|
||||
last_value = nil
|
||||
loop do
|
||||
prime = succ
|
||||
break last_value if prime > @ubound
|
||||
last_value = yield prime
|
||||
end
|
||||
else
|
||||
loop do
|
||||
yield succ
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# see +Enumerator+#with_index.
|
||||
def with_index(offset = 0, &block)
|
||||
return enum_for(:with_index, offset) { Float::INFINITY } unless block
|
||||
return each_with_index(&block) if offset == 0
|
||||
|
||||
each do |prime|
|
||||
yield prime, offset
|
||||
offset += 1
|
||||
end
|
||||
end
|
||||
|
||||
# see +Enumerator+#with_object.
|
||||
def with_object(obj)
|
||||
return enum_for(:with_object, obj) { Float::INFINITY } unless block_given?
|
||||
each do |prime|
|
||||
yield prime, obj
|
||||
end
|
||||
end
|
||||
|
||||
def size
|
||||
Float::INFINITY
|
||||
end
|
||||
end
|
||||
|
||||
# An implementation of +PseudoPrimeGenerator+.
|
||||
#
|
||||
# Uses +EratosthenesSieve+.
|
||||
class EratosthenesGenerator < PseudoPrimeGenerator
|
||||
def initialize
|
||||
@last_prime_index = -1
|
||||
super
|
||||
end
|
||||
|
||||
def succ
|
||||
@last_prime_index += 1
|
||||
EratosthenesSieve.instance.get_nth_prime(@last_prime_index)
|
||||
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 integers which are greater than 2 and
|
||||
# are not divisible by either 2 or 3.
|
||||
#
|
||||
# This is a pseudo-prime generator, suitable on
|
||||
# checking primality of an integer by brute force
|
||||
# method.
|
||||
class Generator23 < PseudoPrimeGenerator
|
||||
def initialize
|
||||
@prime = 1
|
||||
@step = nil
|
||||
super
|
||||
end
|
||||
|
||||
def succ
|
||||
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
|
||||
@prime
|
||||
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 +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
|
||||
@primes[index]
|
||||
end
|
||||
end
|
||||
|
||||
# Internal use. An implementation of Eratosthenes' sieve
|
||||
class EratosthenesSieve
|
||||
include Singleton
|
||||
|
||||
def initialize
|
||||
@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]
|
||||
# @max_checked must be an even number
|
||||
@max_checked = @primes.last + 1
|
||||
end
|
||||
|
||||
def get_nth_prime(n)
|
||||
compute_primes while @primes.size <= n
|
||||
@primes[n]
|
||||
end
|
||||
|
||||
private
|
||||
def compute_primes
|
||||
# max_segment_size must be an even number
|
||||
max_segment_size = 1e6.to_i
|
||||
max_cached_prime = @primes.last
|
||||
# do not double count primes if #compute_primes is interrupted
|
||||
# by Timeout.timeout
|
||||
@max_checked = max_cached_prime + 1 if max_cached_prime > @max_checked
|
||||
|
||||
segment_min = @max_checked
|
||||
segment_max = [segment_min + max_segment_size, max_cached_prime * 2].min
|
||||
root = Integer.sqrt(segment_max)
|
||||
|
||||
segment = ((segment_min + 1) .. segment_max).step(2).to_a
|
||||
|
||||
(1..Float::INFINITY).each do |sieving|
|
||||
prime = @primes[sieving]
|
||||
break if prime > root
|
||||
composite_index = (-(segment_min + 1 + prime) / 2) % prime
|
||||
while composite_index < segment.size do
|
||||
segment[composite_index] = nil
|
||||
composite_index += prime
|
||||
end
|
||||
end
|
||||
|
||||
@primes.concat(segment.compact!)
|
||||
|
||||
@max_checked = segment_max
|
||||
end
|
||||
end
|
||||
end
|
@ -1,298 +0,0 @@
|
||||
# frozen_string_literal: false
|
||||
require 'test/unit'
|
||||
require 'prime'
|
||||
require 'timeout'
|
||||
|
||||
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_include?
|
||||
assert_equal(false, Prime.include?(nil))
|
||||
assert_equal(true, Prime.include?(3))
|
||||
assert_equal(false, Prime.include?(4))
|
||||
assert_equal(true, Prime.include?(Enumerable))
|
||||
assert_equal(false, Prime.include?(Comparable))
|
||||
end
|
||||
|
||||
def test_integer_each_prime
|
||||
primes = []
|
||||
Integer.each_prime(1000) 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_operator primes.length, :>=, max/Math.log(max)
|
||||
delta = 0.05
|
||||
li = (2..max).step(delta).inject(0){|sum,x| sum + delta/Math.log(x)}
|
||||
assert_operator primes.length, :<=, li
|
||||
end
|
||||
end
|
||||
|
||||
def test_each_without_block
|
||||
enum = Prime.each
|
||||
assert_respond_to(enum, :each)
|
||||
assert_kind_of(Enumerable, enum)
|
||||
assert_respond_to(enum, :with_index)
|
||||
assert_respond_to(enum, :next)
|
||||
assert_respond_to(enum, :succ)
|
||||
assert_respond_to(enum, :rewind)
|
||||
end
|
||||
|
||||
def test_instance_without_block
|
||||
enum = Prime.instance.each
|
||||
assert_respond_to(enum, :each)
|
||||
assert_kind_of(Enumerable, enum)
|
||||
assert_respond_to(enum, :with_index)
|
||||
assert_respond_to(enum, :next)
|
||||
assert_respond_to(enum, :succ)
|
||||
assert_respond_to(enum, :rewind)
|
||||
end
|
||||
|
||||
def test_new
|
||||
assert_raise(NoMethodError) { Prime.new }
|
||||
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
|
||||
|
||||
def test_enumerator_with_index_with_offset
|
||||
enum = Prime.each
|
||||
last = 5-1
|
||||
enum.with_index(5).each do |p,i|
|
||||
break if i >= 100+5
|
||||
assert_equal last+1, i
|
||||
assert_equal PRIMES[i-5], p
|
||||
last = i
|
||||
end
|
||||
end
|
||||
|
||||
def test_enumerator_with_object
|
||||
object = Object.new
|
||||
enum = Prime.each
|
||||
enum.with_object(object).each do |p, o|
|
||||
assert_equal object, o
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
def test_enumerator_size
|
||||
enum = Prime.each
|
||||
assert_equal Float::INFINITY, enum.size
|
||||
assert_equal Float::INFINITY, enum.with_object(nil).size
|
||||
assert_equal Float::INFINITY, enum.with_index(42).size
|
||||
end
|
||||
|
||||
def test_default_instance_does_not_have_compatibility_methods
|
||||
assert_not_respond_to(Prime.instance, :succ)
|
||||
assert_not_respond_to(Prime.instance, :next)
|
||||
end
|
||||
|
||||
def test_prime_each_basic_argument_checking
|
||||
assert_raise(ArgumentError) { Prime.prime?(1,2) }
|
||||
assert_raise(ArgumentError) { Prime.prime?(1.2) }
|
||||
end
|
||||
|
||||
def test_prime?
|
||||
assert_equal Prime.prime?(1), false
|
||||
assert_equal Prime.prime?(2), true
|
||||
assert_equal Prime.prime?(4), false
|
||||
end
|
||||
|
||||
class TestPseudoPrimeGenerator < Test::Unit::TestCase
|
||||
def test_upper_bound
|
||||
pseudo_prime_generator = Prime::PseudoPrimeGenerator.new(42)
|
||||
assert_equal pseudo_prime_generator.upper_bound, 42
|
||||
end
|
||||
|
||||
def test_succ
|
||||
pseudo_prime_generator = Prime::PseudoPrimeGenerator.new(42)
|
||||
assert_raise(NotImplementedError) { pseudo_prime_generator.succ }
|
||||
end
|
||||
|
||||
def test_next
|
||||
pseudo_prime_generator = Prime::PseudoPrimeGenerator.new(42)
|
||||
assert_raise(NotImplementedError) { pseudo_prime_generator.next }
|
||||
end
|
||||
|
||||
def test_rewind
|
||||
pseudo_prime_generator = Prime::PseudoPrimeGenerator.new(42)
|
||||
assert_raise(NotImplementedError) { pseudo_prime_generator.rewind }
|
||||
end
|
||||
end
|
||||
|
||||
class TestTrialDivisionGenerator < 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(nil, Prime::TrialDivisionGenerator.new) do |p|
|
||||
break if p > 541
|
||||
primes << p
|
||||
end
|
||||
assert_equal PRIMES, primes
|
||||
end
|
||||
|
||||
def test_rewind
|
||||
generator = Prime::TrialDivisionGenerator.new
|
||||
assert_equal generator.next, 2
|
||||
assert_equal generator.next, 3
|
||||
generator.rewind
|
||||
assert_equal generator.next, 2
|
||||
end
|
||||
end
|
||||
|
||||
class TestGenerator23 < Test::Unit::TestCase
|
||||
def test_rewind
|
||||
generator = Prime::Generator23.new
|
||||
assert_equal generator.next, 2
|
||||
assert_equal generator.next, 3
|
||||
generator.rewind
|
||||
assert_equal generator.next, 2
|
||||
end
|
||||
end
|
||||
|
||||
class TestInteger < Test::Unit::TestCase
|
||||
def test_prime_division
|
||||
pd = PRIMES.inject(&:*).prime_division
|
||||
assert_equal PRIMES.map{|p| [p, 1]}, pd
|
||||
|
||||
pd = (-PRIMES.inject(&:*)).prime_division
|
||||
assert_equal [-1, *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]})
|
||||
|
||||
assert_equal(-PRIMES.inject(&:*), Integer.from_prime_division([[-1, 1]] + PRIMES.map{|p| [p,1]}))
|
||||
end
|
||||
|
||||
def test_prime?
|
||||
PRIMES.each do |p|
|
||||
assert_predicate(p, :prime?)
|
||||
end
|
||||
|
||||
composites = (0..PRIMES.last).to_a - PRIMES
|
||||
composites.each do |c|
|
||||
assert_not_predicate(c, :prime?)
|
||||
end
|
||||
|
||||
# mersenne numbers
|
||||
assert_predicate((2**31-1), :prime?)
|
||||
assert_not_predicate((2**32-1), :prime?)
|
||||
|
||||
# fermat numbers
|
||||
assert_predicate((2**(2**4)+1), :prime?)
|
||||
assert_not_predicate((2**(2**5)+1), :prime?) # Euler!
|
||||
|
||||
# large composite
|
||||
assert_not_predicate(((2**13-1) * (2**17-1)), :prime?)
|
||||
|
||||
# factorial
|
||||
assert_not_predicate((2...100).inject(&:*), :prime?)
|
||||
|
||||
# negative
|
||||
assert_not_predicate(-1, :prime?)
|
||||
assert_not_predicate(-2, :prime?)
|
||||
assert_not_predicate(-3, :prime?)
|
||||
assert_not_predicate(-4, :prime?)
|
||||
|
||||
assert_equal 1229, (1..10_000).count(&:prime?)
|
||||
assert_equal 861, (100_000..110_000).count(&:prime?)
|
||||
end
|
||||
|
||||
def test_prime_in_ractor
|
||||
assert_ractor(<<~RUBY, require: 'prime')
|
||||
# Test usage of private constant...
|
||||
assert_equal false, Ractor.new { ((2**13-1) * (2**17-1)).prime? }.take
|
||||
RUBY
|
||||
end if defined?(Ractor)
|
||||
end
|
||||
|
||||
def test_eratosthenes_works_fine_after_timeout
|
||||
sieve = Prime::EratosthenesSieve.instance
|
||||
sieve.send(:initialize)
|
||||
# simulates that Timeout.timeout interrupts Prime::EratosthenesSieve#compute_primes
|
||||
class << Integer
|
||||
alias_method :org_sqrt, :sqrt
|
||||
end
|
||||
begin
|
||||
def Integer.sqrt(n)
|
||||
sleep 10 if /compute_primes/ =~ caller.first
|
||||
org_sqrt(n)
|
||||
end
|
||||
assert_raise(Timeout::Error) do
|
||||
Timeout.timeout(0.5) { Prime.each(7*37){} }
|
||||
end
|
||||
ensure
|
||||
class << Integer
|
||||
remove_method :sqrt
|
||||
alias_method :sqrt, :org_sqrt
|
||||
remove_method :org_sqrt
|
||||
end
|
||||
end
|
||||
|
||||
assert_not_include Prime.each(7*37).to_a, 7*37, "[ruby-dev:39465]"
|
||||
end
|
||||
end
|
@ -24,7 +24,6 @@ REPOSITORIES = {
|
||||
strscan: 'ruby/strscan',
|
||||
ipaddr: 'ruby/ipaddr',
|
||||
logger: 'ruby/logger',
|
||||
prime: 'ruby/prime',
|
||||
matrix: 'ruby/matrix',
|
||||
ostruct: 'ruby/ostruct',
|
||||
irb: 'ruby/irb',
|
||||
|
Loading…
x
Reference in New Issue
Block a user