mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
* test/test_prime.rb
(TestPrime#test_eratosthenes_works_fine_after_timeout): test for [ruby-dev:39465]. * lib/prime.rb (Prime::EratosthenesSieve): fixed [ruby-dev:39465]. suppressed memory reallocation. constantified some magic numbers. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@25388 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
79a8955f8d
commit
c0b42eedea
3 changed files with 82 additions and 21 deletions
11
ChangeLog
11
ChangeLog
|
@ -1,3 +1,14 @@
|
||||||
|
Sun Oct 18 09:49:14 2009 Yuki Sonoda (Yugui) <yugui@yugui.jp>
|
||||||
|
|
||||||
|
* test/test_prime.rb
|
||||||
|
(TestPrime#test_eratosthenes_works_fine_after_timeout):
|
||||||
|
test for [ruby-dev:39465].
|
||||||
|
|
||||||
|
* lib/prime.rb (Prime::EratosthenesSieve):
|
||||||
|
fixed [ruby-dev:39465].
|
||||||
|
suppressed memory reallocation.
|
||||||
|
constantified some magic numbers.
|
||||||
|
|
||||||
Sat Oct 17 22:11:03 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
|
Sat Oct 17 22:11:03 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
|
||||||
|
|
||||||
* marshal.c (id2encidx): register encoding name.
|
* marshal.c (id2encidx): register encoding name.
|
||||||
|
|
66
lib/prime.rb
66
lib/prime.rb
|
@ -408,44 +408,68 @@ class Prime
|
||||||
class EratosthenesSieve
|
class EratosthenesSieve
|
||||||
include Singleton
|
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:
|
def initialize # :nodoc:
|
||||||
# bitmap for odd prime numbers less than 256.
|
# 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) .
|
# For an arbitrary odd number n, @tables[i][j][k] is
|
||||||
@table = [0xcb6e, 0x64b4, 0x129a, 0x816d, 0x4c32, 0x864a, 0x820d, 0x2196]
|
# * 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
|
end
|
||||||
|
|
||||||
# returns the least odd prime number which is greater than +n+.
|
# returns the least odd prime number which is greater than +n+.
|
||||||
def next_to(n)
|
def next_to(n)
|
||||||
n = (n-1).div(2)*2+3 # the next odd number of given n
|
n = (n-1).div(2)*2+3 # the next odd number to given n
|
||||||
i,j = n.divmod(32)
|
table_index, integer_index, bit_index = indices(n)
|
||||||
loop do
|
loop do
|
||||||
extend_table until @table.length > i
|
extend_table until @tables.length > table_index
|
||||||
if !@table[i].zero?
|
for j in integer_index...ENTRIES_PER_TABLE
|
||||||
(j...32).step(2) do |k|
|
if !@tables[table_index][j].zero?
|
||||||
return 32*i+k if !@table[i][k.div(2)].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
|
||||||
end
|
end
|
||||||
i += 1; j = 1
|
bit_index = 0
|
||||||
|
end
|
||||||
|
table_index += 1; integer_index = 0
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
def extend_table
|
# for an odd number +n+, returns (i, j, k) such that @tables[i][j][k] represents primarity of the number
|
||||||
orig_len = @table.length
|
def indices(n)
|
||||||
new_len = [orig_len**2, orig_len+256].min
|
# binary digits of n: |0|1|2|3|4|5|6|7|8|9|10|11|....
|
||||||
lbound = orig_len*32
|
# indices: |-| k | j | i
|
||||||
ubound = new_len*32
|
# because of NUMS_PER_ENTRY, NUMS_PER_TABLE
|
||||||
@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
|
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|
|
(start...ubound).step(2*p) do |n|
|
||||||
i, j = n.divmod(32)
|
_, j, k = indices(n)
|
||||||
@table[i] &= 0xFFFF ^ (1<<(j.div(2)))
|
new_table[j] &= FILLED_ENTRY^(1<<k)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@tables << new_table.freeze
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
require 'test/unit'
|
require 'test/unit'
|
||||||
require 'prime'
|
require 'prime'
|
||||||
require 'stringio'
|
require 'stringio'
|
||||||
|
require 'timeout'
|
||||||
|
|
||||||
class TestPrime < Test::Unit::TestCase
|
class TestPrime < Test::Unit::TestCase
|
||||||
# The first 100 prime numbers
|
# The first 100 prime numbers
|
||||||
|
@ -143,4 +144,29 @@ class TestPrime < Test::Unit::TestCase
|
||||||
assert !-4.prime?
|
assert !-4.prime?
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_eratosthenes_works_fine_after_timeout
|
||||||
|
sieve = Prime::EratosthenesSieve.instance
|
||||||
|
sieve.send(:initialize)
|
||||||
|
begin
|
||||||
|
# simulates that Timeout.timeout interrupts Prime::EratosthenesSieve#extend_table
|
||||||
|
def sieve.Integer(n)
|
||||||
|
n = super(n)
|
||||||
|
sleep 10 if /extend_table/ =~ caller.first
|
||||||
|
return n
|
||||||
|
end
|
||||||
|
|
||||||
|
begin
|
||||||
|
Timeout.timeout(0.5) { Prime.each(7*37){} }
|
||||||
|
flunk("timeout expected")
|
||||||
|
rescue Timeout::Error
|
||||||
|
end
|
||||||
|
ensure
|
||||||
|
class << sieve
|
||||||
|
remove_method :Integer
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
refute_includes Prime.each(7*37).to_a, 7*37, "[ruby-dev:39465]"
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue