PHP 8.2.31
Preview: prime.rb Size: 13.98 KB
/proc/thread-self/root/opt/alt/ruby20/lib64/ruby/2.0.0/prime.rb

#
# = 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
#
# Prime is Enumerable:
#
#   Prime.first 5 # => [2, 3, 5, 7, 11]
#
# == 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.
# Furthermore, 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

  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 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
  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 <tt>[[p_1, e_1], [p_2, e_2], ...., [p_n, e_n]]</tt>, 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
    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.
    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_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

    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
      super
    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
      super
    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

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

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

    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<<k)
        end
      end
      @tables << new_table.freeze
    end
  end

  # Provides a +Prime+ object with compatibility to Ruby 1.8 when instantiated via +Prime+.+new+.
  module OldCompatibility
    # Returns the next prime number and forwards internal pointer.
    def succ
      @generator.succ
    end
    alias next succ

    # Overwrites Prime#each.
    #
    # Iterates the given block over all prime numbers. Note that enumeration
    # starts from the current position of internal pointer, not rewound.
    def each(&block)
      return @generator.dup unless block_given?
      loop do
        yield succ
      end
    end
  end
end

Directory Contents

Dirs: 30 × Files: 78

Name Size Perms Modified Actions
cgi DIR
- drwxr-xr-x 2024-03-03 22:43:33
Edit Download
date DIR
- drwxr-xr-x 2024-03-03 22:43:33
Edit Download
digest DIR
- drwxr-xr-x 2024-03-03 22:43:33
Edit Download
dl DIR
- drwxr-xr-x 2024-03-03 22:43:33
Edit Download
drb DIR
- drwxr-xr-x 2024-03-03 22:43:33
Edit Download
fiddle DIR
- drwxr-xr-x 2024-03-03 22:43:33
Edit Download
irb DIR
- drwxr-xr-x 2024-03-03 22:43:33
Edit Download
json DIR
- drwxr-xr-x 2024-03-03 22:43:37
Edit Download
matrix DIR
- drwxr-xr-x 2024-03-03 22:43:33
Edit Download
net DIR
- drwxr-xr-x 2024-03-03 22:43:33
Edit Download
openssl DIR
- drwxr-xr-x 2024-03-03 22:43:33
Edit Download
optparse DIR
- drwxr-xr-x 2024-03-03 22:43:33
Edit Download
psych DIR
- drwxr-xr-x 2024-03-03 22:43:38
Edit Download
racc DIR
- drwxr-xr-x 2024-03-03 22:43:33
Edit Download
rake DIR
- drwxr-xr-x 2024-03-03 22:53:08
Edit Download
rbconfig DIR
- drwxr-xr-x 2024-03-03 22:43:42
Edit Download
rdoc DIR
- drwxr-xr-x 2024-03-03 22:43:41
Edit Download
rexml DIR
- drwxr-xr-x 2024-03-03 22:43:33
Edit Download
rinda DIR
- drwxr-xr-x 2024-03-03 22:43:33
Edit Download
ripper DIR
- drwxr-xr-x 2024-03-03 22:43:33
Edit Download
rss DIR
- drwxr-xr-x 2024-03-03 22:43:33
Edit Download
rubygems DIR
- drwxr-xr-x 2024-03-03 22:43:42
Edit Download
shell DIR
- drwxr-xr-x 2024-03-03 22:43:33
Edit Download
syslog DIR
- drwxr-xr-x 2024-03-03 22:43:33
Edit Download
test DIR
- drwxr-xr-x 2024-03-03 22:43:33
Edit Download
uri DIR
- drwxr-xr-x 2024-03-03 22:43:33
Edit Download
webrick DIR
- drwxr-xr-x 2024-03-03 22:43:33
Edit Download
- drwxr-xr-x 2024-03-03 22:43:38
Edit Download
xmlrpc DIR
- drwxr-xr-x 2024-03-03 22:43:33
Edit Download
yaml DIR
- drwxr-xr-x 2024-03-03 22:43:33
Edit Download
3.31 KB lrw-r--r-- 2013-02-24 05:06:42
Edit Download
2.63 KB lrw-r--r-- 2009-10-02 10:45:39
Edit Download
17.94 KB lrw-r--r-- 2012-07-18 03:56:58
Edit Download
9.39 KB lrw-r--r-- 2012-11-30 05:06:45
Edit Download
7.22 KB lrw-r--r-- 2011-07-23 12:14:43
Edit Download
380 B lrw-r--r-- 2009-08-16 15:34:35
Edit Download
81.32 KB lrw-r--r-- 2014-09-17 05:56:35
Edit Download
946 B lrw-r--r-- 2023-07-26 14:09:00
Edit Download
28.90 KB lrw-r--r-- 2013-02-02 05:04:54
Edit Download
9.78 KB lrw-r--r-- 2014-04-30 07:45:49
Edit Download
2.24 KB lrw-r--r-- 2023-07-26 14:09:00
Edit Download
280 B lrw-r--r-- 2023-07-26 14:09:00
Edit Download
19 B lrw-r--r-- 2009-10-02 10:45:39
Edit Download
3.80 KB lrw-r--r-- 2011-05-19 00:07:25
Edit Download
6.44 KB lrw-r--r-- 2013-02-04 02:50:20
Edit Download
26.08 KB lrw-r--r-- 2014-09-03 04:42:39
Edit Download
2.14 KB lrw-r--r-- 2023-07-26 14:09:00
Edit Download
1.25 KB lrw-r--r-- 2023-07-26 14:09:00
Edit Download
46.35 KB lrw-r--r-- 2014-10-16 07:23:46
Edit Download
2.08 KB lrw-r--r-- 2012-09-20 07:14:54
Edit Download
7.56 KB lrw-r--r-- 2013-01-04 02:52:54
Edit Download
15.38 KB lrw-r--r-- 2013-12-24 15:46:01
Edit Download
8.86 KB lrw-r--r-- 2014-07-07 03:55:25
Edit Download
26.17 KB lrw-r--r-- 2013-02-23 04:03:59
Edit Download
20.03 KB lrw-r--r-- 2013-02-05 15:57:19
Edit Download
1.74 KB lrw-r--r-- 2023-07-26 14:09:00
Edit Download
5.74 KB lrw-r--r-- 2023-07-26 14:09:00
Edit Download
20.96 KB lrw-r--r-- 2013-07-13 15:16:09
Edit Download
6.52 KB lrw-r--r-- 2011-08-26 22:22:37
Edit Download
45.02 KB lrw-r--r-- 2013-02-05 05:43:36
Edit Download
78.19 KB lrw-r--r-- 2023-07-26 14:06:15
Edit Download
6.93 KB lrw-r--r-- 2012-11-16 16:55:29
Edit Download
2.00 KB lrw-r--r-- 2013-02-24 04:49:04
Edit Download
5.71 KB lrw-r--r-- 2012-08-21 13:03:30
Edit Download
23.66 KB lrw-r--r-- 2014-02-16 17:02:51
Edit Download
21.17 KB lrw-r--r-- 2013-01-13 04:40:15
Edit Download
528 B lrw-r--r-- 2023-07-26 14:09:00
Edit Download
51.27 KB lrw-r--r-- 2014-02-19 16:38:03
Edit Download
7.64 KB lrw-r--r-- 2012-10-28 21:20:10
Edit Download
15.30 KB lrw-r--r-- 2023-07-26 14:09:00
Edit Download
13.14 KB lrw-r--r-- 2012-08-15 11:50:01
Edit Download
9.63 KB lrw-r--r-- 2011-08-02 15:25:59
Edit Download
13.98 KB lrw-r--r-- 2013-01-13 05:07:08
Edit Download
205 B lrw-r--r-- 2009-10-02 10:45:39
Edit Download
4.29 KB lrw-r--r-- 2013-02-03 00:38:46
Edit Download
14.85 KB lrw-r--r-- 2012-11-11 04:23:04
Edit Download
9.90 KB lrw-r--r-- 2023-07-26 14:09:00
Edit Download
2.07 KB lrw-r--r-- 2012-11-29 19:16:46
Edit Download
308 B lrw-r--r-- 2009-09-24 00:42:23
Edit Download
4.88 KB lrw-r--r-- 2013-02-19 05:06:36
Edit Download
1.73 KB lrw-r--r-- 2013-04-03 17:27:19
Edit Download
61.45 KB lrw-r--r-- 2015-06-01 15:13:01
Edit Download
2.53 KB lrw-r--r-- 2023-07-26 14:09:00
Edit Download
2.84 KB lrw-r--r-- 2011-05-11 10:22:16
Edit Download
27.53 KB lrw-r--r-- 2023-07-26 14:06:15
Edit Download
23.52 KB lrw-r--r-- 2011-11-05 07:37:47
Edit Download
8.56 KB lrw-r--r-- 2012-09-13 13:01:23
Edit Download
17.32 KB lrw-r--r-- 2012-11-24 18:51:45
Edit Download
10.30 KB lrw-r--r-- 2012-12-05 02:55:07
Edit Download
5.94 KB lrw-r--r-- 2012-11-09 06:28:00
Edit Download
4.02 KB lrw-r--r-- 2011-05-18 14:09:38
Edit Download
25.76 KB lrw-r--r-- 2023-07-26 14:09:00
Edit Download
7.26 KB lrw-r--r-- 2012-12-23 10:18:58
Edit Download
10.15 KB lrw-r--r-- 2013-10-09 16:11:16
Edit Download
6.94 KB lrw-r--r-- 2014-02-09 16:07:41
Edit Download
3.38 KB lrw-r--r-- 2011-06-29 03:09:34
Edit Download
21.09 KB lrw-r--r-- 2013-10-09 15:07:45
Edit Download
3.16 KB lrw-r--r-- 2013-04-14 15:20:33
Edit Download
4.15 KB lrw-r--r-- 2012-12-12 12:40:51
Edit Download
6.54 KB lrw-r--r-- 2013-02-04 17:59:52
Edit Download
6.79 KB lrw-r--r-- 2009-03-06 04:23:05
Edit Download
268 B lrw-r--r-- 2009-10-02 10:45:39
Edit Download
8.34 KB lrw-r--r-- 2012-08-03 08:23:18
Edit Download
3.07 KB lrw-r--r-- 2011-05-13 20:03:21
Edit Download
3.23 KB lrw-r--r-- 2012-12-02 07:57:45
Edit Download
6.70 KB lrw-r--r-- 2012-11-07 06:49:57
Edit Download
8.49 KB lrw-r--r-- 2012-09-13 02:24:08
Edit Download
2.30 KB lrw-r--r-- 2013-05-19 19:01:43
Edit Download

If ZipArchive is unavailable, a .tar will be created (no compression).