6

I wrote this code to find the prime numbers less than the given number i in scala.

def findPrime(i : Int) : List[Int] = i match {
    case 2 => List(2)
    case _ => {
    val primeList = findPrime(i-1)
    if(isPrime(i, primeList)) i :: primeList else primeList
    }
}

def isPrime(num : Int, prePrimes : List[Int]) : Boolean = prePrimes.forall(num % _ != 0)    

But, I got a feeling the findPrime function, especially this part:

case _ => {
    val primeList = findPrime(i-1)
    if(isPrime(i, primeList)) i :: primeList else primeList
}

is not quite in the functional style.

I am still learning functional programming. Can anyone please help me improve this code to make it more functional.

Many thanks.

Will Ness
  • 62,652
  • 8
  • 86
  • 167
Kevin
  • 5,192
  • 14
  • 56
  • 82
  • It doesn't matter if you're programming functionally or imperatively, you will want to use the real Sieve (as stated in an answer) to find primes, unless you are doing this with numbers less than ten thousand or something... – ninjagecko Mar 14 '12 at 23:27

10 Answers10

20

Here's a functional implementation of the Sieve of Eratosthenes, as presented in Odersky's "Functional Programming Principles in Scala" Coursera course :

  // Sieving integral numbers
  def sieve(s: Stream[Int]): Stream[Int] = {
    s.head #:: sieve(s.tail.filter(_ % s.head != 0))
  }

  // All primes as a lazy sequence
  val primes = sieve(Stream.from(2))

  // Dumping the first five primes
  print(primes.take(5).toList) // List(2, 3, 5, 7, 11)
Rahel Lüthy
  • 5,957
  • 3
  • 32
  • 48
  • 2
    Not sure if I'm doing something wrong, but this seems to run out of memory really quickly. – Daryl Teo Dec 18 '12 at 08:50
  • 1
    No, not your fault, this sieve implementation is only suitable for small lists (memory requirement of `O(n)` if I remember correctly). – Rahel Lüthy Dec 19 '12 at 09:36
  • 4
    this a.k.a. Turner's sieve, "unfaithful" sieve, or *never-to-be-actually-used* "suboptimal trial division" sieve. see [e.g. this](http://stackoverflow.com/questions/20985539/scala-erastothenes-is-there-a-straightforward-way-to-replace-a-stream-with-an/20991776#comment31606932_20986428) for a simple yet reasonable alternative code. :) – Will Ness Jan 26 '14 at 18:44
11

The style looks fine to me. Although the Sieve of Eratosthenes is a very efficient way to find prime numbers, your approach works well too, since you are only testing for division against known primes. You need to watch out however--your recursive function is not tail recursive. A tail recursive function does not modify the result of the recursive call--in your example you prepend to the result of the recursive call. This means that you will have a long call stack and so findPrime will not work for large i. Here is a tail-recursive solution.

def primesUnder(n: Int): List[Int] = {
  require(n >= 2)

  def rec(i: Int, primes: List[Int]): List[Int] = {
    if (i >= n) primes
    else if (prime(i, primes)) rec(i + 1, i :: primes)
    else rec(i + 1, primes)
  }

  rec(2, List()).reverse
}

def prime(num: Int, factors: List[Int]): Boolean = factors.forall(num % _ != 0)

This solution isn't prettier--it's more of a detail to get your solution to work for large arguments. Since the list is built up backwards to take advantage of fast prepends, the list needs to be reversed. As an alternative, you could use an Array, Vector or a ListBuffer to append the results. With the Array, however, you would need to estimate how much memory to allocate for it. Fortunately we know that pi(n) is about equal to n / ln(n) so you can choose a reasonable size. Array and ListBuffer are also a mutable data types, which goes again your desire for functional style.

Update: to get good performance out of the Sieve of Eratosthenes I think you'll need to store data in a native array, which also goes against your desire for style in functional programming. There might be a creative functional implementation though!

Update: oops! Missed it! This approach works well too if you only divide by primes less than the square root of the number you are testing! I missed this, and unfortunately it's not easy to adjust my solution to do this because I'm storing the primes backwards.

Update: here's a very non-functional solution that at least only checks up to the square root.

rnative, you could use an Array, Vector or a ListBuffer to append the results. With the Array, however, you would need to estimate how much memory to allocate for it. Fortunately we know that pi(n) is about equal to n / ln(n) so you can choose a reasonable size. Array and ListBuffer are also a mutable data types, which goes again your desire for functional style.

Update: to get good performance out of the Sieve of Eratosthenes I think you'll need to store data in a native array, which also goes against your desire for style in functional programming. There might be a creative functional implementation though!

Update: oops! Missed it! This approach works well too if you only divide by primes less than the square root of the number you are testing! I missed this, and unfortunately it's not easy to adjust my solution to do this because I'm storing the primes backwards.

Update: here's a very non-functional solution that at least only checks up to the square root.

import scala.collection.mutable.ListBuffer

def primesUnder(n: Int): List[Int] = {
  require(n >= 2)

  val primes = ListBuffer(2)
  for (i <- 3 to n) {
    if (prime(i, primes.iterator)) {
      primes += i
    }
  }

  primes.toList
}

// factors must be in sorted order
def prime(num: Int, factors: Iterator[Int]): Boolean = 
  factors.takeWhile(_ <= math.sqrt(num).toInt) forall(num % _ != 0)

Or I could use Vectors with my original approach. Vectors are probably not the best solution because they don't have the fasted O(1) even though it's amortized O(1).

schmmd
  • 15,302
  • 16
  • 53
  • 99
  • Instead of a recursive function, or a mutable list in the second case, you should probably use a `foldLeft` to make the most "functional looking" implementation possible, and please the FP-patrol!... – dividebyzero Aug 29 '15 at 01:45
7

As schmmd mentions, you want it to be tail recursive, and you also want it to be lazy. Fortunately there is a perfect data-structure for this: Stream.

This is a very efficient prime calculator implemented as a Stream, with a few optimisations:

object Prime {
  def is(i: Long): Boolean =
    if (i == 2) true
    else if ((i & 1) == 0) false // efficient div by 2
    else prime(i)

  def primes: Stream[Long] = 2 #:: prime3

  private val prime3: Stream[Long] = {
    @annotation.tailrec
    def nextPrime(i: Long): Long =
      if (prime(i)) i else nextPrime(i + 2) // tail

    def next(i: Long): Stream[Long] =
      i #:: next(nextPrime(i + 2))

    3 #:: next(5)

  }

    // assumes not even, check evenness before calling - perf note: must pass partially applied >= method
  def prime(i: Long): Boolean =
    prime3 takeWhile (math.sqrt(i).>= _) forall { i % _ != 0 }
}

Prime.is is the prime check predicate, and Prime.primes returns a Stream of all prime numbers. prime3 is where the Stream is computed, using the prime predicate to check for all prime divisors less than the square root of i.

Onema
  • 6,423
  • 11
  • 61
  • 97
Jed Wesley-Smith
  • 4,516
  • 16
  • 20
4
  /**
   * @return Bitset p such that p(x) is true iff x is prime
   */
  def sieveOfEratosthenes(n: Int) = {
    val isPrime = mutable.BitSet(2 to n: _*)
    for (p <- 2 to Math.sqrt(n) if isPrime(p)) {
      isPrime --= p*p to n by p
    }
    isPrime.toImmutable
  }
pathikrit
  • 29,060
  • 33
  • 127
  • 206
1

@mfa has mentioned using a Sieve of Eratosthenes - SoE and @Luigi Plinge has mentioned that this should be done using functional code, so @netzwerg has posted a non-SoE version; here, I post a "almost" functional version of the SoE using completely immutable state except for the contents of a mutable BitSet (mutable rather than immutable for performance) that I posted as an answer to another question:

object SoE {
  def makeSoE_Primes(top: Int): Iterator[Int] = {
    val topndx = (top - 3) / 2
    val nonprms = new scala.collection.mutable.BitSet(topndx + 1)
    def cullp(i: Int) = {
      import scala.annotation.tailrec; val p = i + i + 3
      @tailrec def cull(c: Int): Unit = if (c <= topndx) { nonprms += c; cull(c + p) }
      cull((p * p - 3) >>> 1)
    }
    (0 to (Math.sqrt(top).toInt - 3) >>> 1).filterNot { nonprms }.foreach { cullp }
    Iterator.single(2) ++ (0 to topndx).filterNot { nonprms }.map { i: Int => i + i + 3 }
  }
}
Community
  • 1
  • 1
GordonBGood
  • 3,017
  • 30
  • 38
1

How about this.

def getPrimeUnder(n: Int) = {
  require(n >= 2)
  val ol = 3 to n by 2 toList // oddList
  def pn(ol: List[Int], pl: List[Int]): List[Int] = ol match {
    case Nil => pl
    case _ if pl.exists(ol.head % _ == 0) => pn(ol.tail, pl)
    case _ => pn(ol.tail, ol.head :: pl)
  }
  pn(ol, List(2)).reverse
}

It's pretty fast for me, in my mac, to get all prime under 100k, its take around 2.5 sec.

madooc
  • 89
  • 5
1

A sieve method is your best bet for small lists of numbers (up to 10-100 million or so). see: Sieve of Eratosthenes

Even if you want to find much larger numbers, you can use the list you generate with this method as divisors for testing numbers up to n^2, where n is the limit of your list.

mfa
  • 4,932
  • 2
  • 21
  • 28
0

A scalar fp approach

// returns the list of primes below `number`
def primes(number: Int): List[Int] = {
    number match {
        case a
        if (a <= 3) => (1 to a).toList
        case x => (1 to x - 1).filter(b => isPrime(b)).toList
    }
}

// checks if a number is prime
def isPrime(number: Int): Boolean = {
    number match {
        case 1 => true
        case x => Nil == {
            2 to math.sqrt(number).toInt filter(y => x % y == 0)
        }
    }
}
Justice O.
  • 1,033
  • 10
  • 19
0
def primeNumber(range: Int): Unit ={
    val primeNumbers: immutable.IndexedSeq[AnyVal] =
      for (number :Int <- 2 to range) yield {
        val isPrime = !Range(2, Math.sqrt(number).toInt).exists(x => number % x == 0)
        if(isPrime)  number
      }
    for(prime <- primeNumbers) println(prime)
  }
StaceyGirl
  • 6,826
  • 12
  • 33
  • 59
Navin Gelot
  • 1,030
  • 2
  • 10
  • 26
-1
object Primes {
  private lazy val notDivisibleBy2: Stream[Long] = 3L #:: notDivisibleBy2.map(_ + 2)
  private lazy val notDivisibleBy2Or3: Stream[Long] = notDivisibleBy2
      .grouped(3)
      .map(_.slice(1, 3))
      .flatten
      .toStream
  private lazy val notDivisibleBy2Or3Or5: Stream[Long] = notDivisibleBy2Or3
      .grouped(10)
      .map { g =>
        g.slice(1, 7) ++ g.slice(8, 10)
      }
      .flatten
      .toStream

  lazy val primes: Stream[Long] = 2L #::
      notDivisibleBy2.head #::
      notDivisibleBy2Or3.head #::
      notDivisibleBy2Or3Or5.filter { i =>
        i < 49 || primes.takeWhile(_ <= Math.sqrt(i).toLong).forall(i % _ != 0)
      }

  def apply(n: Long): Stream[Long] = primes.takeWhile(_ <= n)

  def getPrimeUnder(n: Long): Long = Primes(n).last
}
Noel Yap
  • 15,499
  • 17
  • 77
  • 123