All Downloads are FREE. Search and download functionalities are using the official Maven repository.

spire.math.prime.Siever.scala Maven / Gradle / Ivy

The newest version!
package spire
package math.prime

import spire.math.SafeLong

import SieveUtil._

/**
 * Segmented Stream of Eratosthenes implementation
 *
 * This section really needs some good comments.
 *
 * Some future optimizations:
 *
 * 0. Consider an option to use multiple threads
 * 1. Faster heap/priority queue
 * 2. Tune chunkSize
 * 3. Use Long internally until we have to switch to SafeLong.
 * 4. Compress the amount of space our heaps take up.
 * 5. Read more efficient segmented sieves to get other ideas.
 * 6. Try using a delta-encoded prime log
 *
 * Obviously we are trying to be a bit more flexible than a
 * traditional prime finder that knows ahead of time what range it
 * will be operating over, which will hurt performance a bit. Also,
 * it's not written in C/assembly. So it will probably never be truly
 * competitive, but I'd like us to do as well as possible.
 */

/**
 * The Siever manages the segmented sieve process.
 *
 * At any given time, it holds onto a single sieve segment. Thus, the
 * siever should be used for a single lookup or traversal.
 *
 * Sievers are built using 'chunkSize' and 'cutoff' parameters. These
 * are passed along to any sieve segments they create. When possible,
 * it's probably better to use methods on the companion object, which
 * will instantiate a Siever for you with reasonable parameters.
 */
case class Siever(chunkSize: Int, cutoff: SafeLong) {
  require(chunkSize % 480 == 0, "chunkSize must be a multiple of 480")

  val arr = BitSet.alloc(chunkSize)
  var start: SafeLong = SafeLong(0)
  var limit: SafeLong = start + chunkSize
  val fastq: FastFactors = FastFactors.empty
  val slowq: FactorHeap = new FactorHeap
  var sieve: SieveSegment = SieveSegment(start, arr, cutoff)
  sieve.init(fastq, slowq)

  def largestBelow(n: SafeLong): SafeLong = {
    if (n < 3) throw new IllegalArgumentException("invalid argument: %s" format n)
    if (n == 3) return SafeLong(2)

    var i = 3
    var k = n - 1
    var last = SafeLong(2)
    while (true) {
      val primes = sieve.primes
      val len = primes.length
      if (n - start < len) {
        var i = 1
        val goal = (n - start).toInt
        while (i < goal) {
          if (primes(i)) last = start + i
          i += 2
        }
        return last
      } else {
        var i = len - 1
        while (1 <= i && !primes(i)) i -= 2
        if (1 <= i) last = start + i
      }
      initNextSieve()
      i = 1
    }
    return SafeLong(0) // impossible
  }

  def nth(n: Long): SafeLong = {
    if (n == 1) return SafeLong(2)
    var i = 3
    var k = n - 1
    while (true) {
      val primes = sieve.primes
      val len = primes.length
      while (i < len) {
        if (primes(i)) {
          k -= 1
          if (k < 1) return sieve.start + i
        }
        i += 2
      }
      initNextSieve()
      i = 1
    }
    return SafeLong(0) // impossible
  }

  private def initNextSieve(): Unit = {
    start += chunkSize
    limit += chunkSize
    val csq = cutoff ** 2
    if (limit >= csq) sys.error("too big: %s > %s (%s)" format (limit, csq, cutoff))
    arr.clear()
    sieve = SieveSegment(start, arr, cutoff)
    sieve.init(fastq, slowq)
  }

  def nextAfter(n: SafeLong): SafeLong = {
    var nn = sieve.nextAfter(n)
    while (nn == -1L) {
      initNextSieve()
      nn = sieve.nextAfter(start - 1)
    }
    nn
  }

  def streamAfter(p0: SafeLong): Stream[SafeLong] = {
    val p = nextAfter(p0)
    p #:: streamAfter(p)
  }

  def arrayAt(p: SafeLong, size: Int): Array[SafeLong] = {
    val arr = new Array[SafeLong](size)
    def loop(i: Int, p: SafeLong): Unit =
      if (i < arr.length) {
        arr(i) = p
        loop(i + 1, nextAfter(p))
      }
    loop(0, p)
    arr
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy