[#35789] [Ruby 1.9 - Bug #407] (Open) String#<< — Shyouhei Urabe <redmine@...>

チケット #407 が報告されました。 (by Shyouhei Urabe)

13 messages 2008/08/06

[#35845] [Bug #437] test_strftime(TestTime) fails on Solaris — Shugo Maeda <redmine@...>

Bug #437: test_strftime(TestTime) fails on Solaris

24 messages 2008/08/13
[#35855] Re: [Bug #437] test_strftime(TestTime) fails on Solaris — "Shugo Maeda" <shugo@...> 2008/08/15

前田です。

[#35856] Re: [Bug #437] test_strftime(TestTime) fails on Solaris — SATOH Fumiyasu <fumiyas@...> 2008/08/15

さとうふみやす @ OSS テクノロジです。

[#35857] Re: [Bug #437] test_strftime(TestTime) fails on Solaris — Yukihiro Matsumoto <matz@...> 2008/08/15

まつもと ゆきひろです

[#35870] Re: [Bug #437] test_strftime(TestTime) fails on Solaris — "Shugo Maeda" <shugo@...> 2008/08/18

前田です。

[#35863] Refactoring of enumerating prime numbers — "Yugui (Yuki Sonoda)" <yugui@...>

Yuguiです。

20 messages 2008/08/16
[#35865] Re: Refactoring of enumerating prime numbers — keiju@... (keiju ISHITSUKA) 2008/08/17

けいじゅ@いしつかです.

[#35867] Re: Refactoring of enumerating prime numbers — "Yugui (Yuki Sonoda)" <yugui@...> 2008/08/17

Yuguiです。

[#35875] Re: Refactoring of enumerating prime numbers — keiju@... (keiju ISHITSUKA) 2008/08/19

けいじゅ@いしつかです.

[#35877] Re: Refactoring of enumerating prime numbers — Nobuyoshi Nakada <nobu@...> 2008/08/19

なかだです。

[#35882] Re: Refactoring of enumerating prime numbers — keiju@... (石塚圭樹) 2008/08/20

けいじゅ@いしつかです.

[#35904] [Feature:1.9] pack format 'm' based on RFC 4648 — "Yusuke ENDOH" <mame@...>

遠藤です。

14 messages 2008/08/21
[#36442] [Feature #471] pack format 'm' based on RFC 4648 — Yuki Sonoda <redmine@...> 2008/09/22

チケット #471 が更新されました。 (by Yuki Sonoda)

[#35906] %N for Time#strftime — "Shugo Maeda" <shugo@...>

前田です。

13 messages 2008/08/21

[#35986] 1.9と1.8で、delegateのインスタンスのクラス名の違う — Fujioka <fuj@...>

xibbarこと藤岡です。

17 messages 2008/08/26
[#35987] Re: 1.9と1.8で、delegateのインスタンスのクラス名の違う — Yukihiro Matsumoto <matz@...> 2008/08/26

まつもと ゆきひろです

[#35991] Re: 1.9と1.8で、delegateのインスタンスのクラス名の違う — keiju@... (石塚圭樹) 2008/08/26

けいじゅ@いしつかです.

[#35994] Re: 1.9と1.8で、delegateのインスタンスのクラス名の違う — Fujioka <fuj@...> 2008/08/27

藤岡です。

[#35998] Re: 1.9と1.8で、delegateのインスタンスのクラス名の違う — keiju@... (石塚圭樹) 2008/08/27

けいじゅ@いしつかです.

[#36066] Numeric#scalar? — Tadayoshi Funaba <tadf@...>

1.9 の Numeric#scalar? について、適当でないのでは (real? などのほうがい

24 messages 2008/08/31
[#36069] Re: Numeric#scalar? — Shin-ichiro HARA <sinara@...> 2008/08/31

原です。

[#36104] Re: Numeric#scalar? — Tadayoshi Funaba <tadf@...> 2008/09/02

> やはり、scalar? はずれているんじゃないかな。real? の方がいい

[#36122] Re: Numeric#scalar? — Shin-ichiro HARA <sinara@...> 2008/09/03

原です。

[#36133] Re: Numeric#scalar? — Tadayoshi Funaba <tadf@...> 2008/09/03

> ここで、scalar? を疑問視する理由を復習すると、たとえば、「複

[#36173] Re: Numeric#scalar? — Tadayoshi Funaba <tadf@...> 2008/09/05

1.9.1 までに時間がないので scalar? だけ何とかしたいと思っていましたが、

[#36183] Re: Numeric#scalar? — "Shugo Maeda" <shugo@...> 2008/09/06

前田です。

[#36186] Re: Numeric#scalar? — Shin-ichiro HARA <sinara@...> 2008/09/06

原です。

[ruby-dev:35983] Re: Refactoring of enumerating prime numbers

From: "Yugui (Yuki Sonoda)" <yugui@...>
Date: 2008-08-26 13:09:25 UTC
List: ruby-dev #35983
Yuguiです。

石塚圭樹 さんは書きました:
>>> 私もそうなのかなぁ? と思いつつも, では, 元のクラスの名前はどうするんだ? 
>>> と思ったりもしてます.
>> class << (Prime = Object.new); end で。

私が送ったコードも既存のPrime.newしているコードに配慮してはいますが、
互換性をより確実に提供するという意味ではPrimeがクラスで有り続けたほうが
良いかもしれません。

ただ、その意味では石塚さんの、Primeを完全にシングルトンパターンにしてし
まうのはPrime.newできないので困ると思います。



もう一度整理します。
1. 素数全体を表すEnumerableなオブジェクトは唯一であるべき(yugui)
   互換性のためにPrime.newできるのは仕方がないが、非推奨としたい
 => Primeを特異クラスを持つオブジェクトか、singletonパターン的なクラスに

2. 素数全体を表すものはインスタンスであるべき(石塚さん)
 => Primeがクラスというのはまずい。
    Primeへのメソッド呼び出しをPrimeのインスタンスへ委譲するならばありえる。

3. 素数列挙の途中の状態を保持する外部イテレータが必要
4. 疑似素数列を生成するGeneratorもほしい
   => Prime::Generator, Prime::Generator23, Prime::EratosthenesGenerator


Prime::*の定数スコープを提供するためにもPrimeは、私が書いたような
singletonなオブジェクトよりは、石塚さんのようなsingletonパターンのほうが
良さそうに思えます。

ただし、互換性のためにPrime.newも許容するようにしてみました。このバー
ジョンのprime.rbを添付します。

この他、
a) エラトステネスのふるいでGeneratorを書いてみたらとても速くなったので、
Prime::EratosthenesGeneratorを加えてあります。

      user     system      total        real
trial division
 17.060000  22.580000  39.640000 ( 39.556764)
eratosthenes
  2.270000   0.010000   2.280000 (  2.277945)


b) Prime.eachが上界をとるようにしてみました。そこに到達したら列挙を打ち
切ります。
c) Prime.eachの第2引数にgeneratorを指定できるようにしてみました。

d) Prime.eachとPrime.each.eachが同じオブジェクトであるために列挙状態を共
有してしまいます。generatorがselfではなくself.dupを返すようにしました。

e) Enumeratorに合わせて、Generatorにwith_indexとnextとrewindを足しました。


> * Prime::IncreaseSuperPrimeGenerator
>   上記2つのgeneratorの抽象スーパークラス
>   名前はいまいちなんですが, 昇順で, 素数集合のスーパーセットになる
>   generator ということろからとっています.
>   よい名前募集中

確かにこの名前には違和感がありますね。

PseudoPrimeGeneratorあたりではどうでしょうか。Generator23みたいに「疑
似」の精度が悪くても、逆に真にprimeであってもPseudoのサブセットにはなる
と思います。


-- 
Yugui <yugui@yugui.jp>
http://yugui.jp
私は私をDumpする

Attachments (2)

prime.rb (5.84 KB, text/x-ruby)
require "singleton"
require "forwardable"

class Integer

  def Integer.from_prime_division(pd)
    Prime.int_from_prime_division(pd)
  end
  
  def prime_division(generator = Prime::Generator23.new)
    Prime.prime_division(self, generator)
  end

  def prime?
    Prime.prime?(self)
  end

  def Integer.each_prime(ubound, &block)
    Prime.each(ubound, &block)
  end
end
  
class Prime
  include Enumerable
  @the_instance = Prime.new

  def initialize
    warn "Prime::new is obsolete. use Prime::instance or class methods of Prime."
  end

  class<<self
    extend Forwardable
    include Enumerable
    def instance; @the_instance end

    def method_added(method)
      #puts "method add: #{method}"
      (class<<self;self;end).def_delegator :instance, method
    end
  end

  def each(ubound = nil, generator = Generator.new, &block)
    generator.each(ubound, &block)
  end

  def prime?(value, generator = Prime::Generator23.new)
    for num in generator
      return false if value % num == 0
      return true if value > num * num
    end
  end

  def int_from_prime_division(pd)
    pd.inject(1){|value, (prime, index)|
      value *= prime**index
    }
  end

  def prime_division(value, generator= Prime::Generator23.new)
    raise ZeroDivisionError if self == 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 prime * prime  >= value
    end
    if value > 1
      pv.push [value, 1]
    end
    return pv
  end

  class IncreaseSuperPrimeGenerator
    include Enumerable

    def succ
      raise NotImplementedError, "need to define `succ'"
    end
    def next
      raise NotImplementedError, "need to define `next'"
    end
    def rewind
      raise NotImplementedError, "need to define `rewind'"
    end

    def each(ubound = nil, &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
    alias with_index each_with_index
  end
  ISPG = IncreaseSuperPrimeGenerator
  
  class Generator<ISPG
    def initialize
      @index = -1
    end
    
    def succ
      PrimeSet.instance[@index += 1]
    end
    def rewind
      initialize
    end
    alias next succ
  end

  class EratosthenesGenerator <ISPG
    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

  class Generator23<ISPG
    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

  class PrimeSet
    include Singleton

    def initialize
      # 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

    # Return the prime cache.
    def cache
      return @primes
    end
    alias primes cache
    alias primes_so_far cache

    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

  class EratosthenesSieve
    include Singleton

    def initialize
      # bitmap for odd prime numbers less than 256.
      # for an 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
prime_bench.rb (279 Bytes, text/x-ruby)
require 'prime.rb'
require 'benchmark'

max = 0x100000
Benchmark.bm do |x|
  x.report("trial division") { c = 0; Prime.each(max, Prime::Generator.new){|x| c+=1 }; p c} 
  x.report("eratosthenes")   { c = 0; Prime.each(max, Prime::EratosthenesGenerator.new){|x| c+=1 }; p c} 
end

In This Thread