Skip to content

Commit

Permalink
Complete up to P41
Browse files Browse the repository at this point in the history
  • Loading branch information
Abhijit Sarkar committed Jan 5, 2024
1 parent de0e1f3 commit be445d0
Show file tree
Hide file tree
Showing 20 changed files with 322 additions and 11 deletions.
18 changes: 9 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,27 +62,27 @@

## Arithmetic

P31 (**) Determine whether a given integer number is prime.
[P31](src/main/scala/arithmetic/P31.scala) (**) Determine whether a given integer number is prime.

P32 (**) Determine the greatest common divisor of two positive integer numbers.
[P32](src/main/scala/arithmetic/P32.scala) (**) Determine the greatest common divisor of two positive integer numbers.

P33 (*) Determine whether two positive integer numbers are coprime.
[P33](src/main/scala/arithmetic/P33.scala) (*) Determine whether two positive integer numbers are coprime.

P34 (**) Calculate Euler’s totient function ϕ(m).
[P34](src/main/scala/arithmetic/P34.scala) (**) Calculate Euler’s totient function ϕ(m).

P35 (**) Determine the prime factors of a given positive integer.
[P35](src/main/scala/arithmetic/P35.scala) (**) Determine the prime factors of a given positive integer.

P36 (**) Determine the prime factors of a given positive integer (2).
[P36](src/main/scala/arithmetic/P36.scala) (**) Determine the prime factors of a given positive integer (2).

P37 (**) Calculate Euler’s totient function ϕ(m) (improved).

P38 (*) Compare the two methods of calculating Euler’s totient function.

P39 (*) A list of prime numbers.
[P39](src/main/scala/arithmetic/P39.scala) (*) A list of prime numbers.

P40 (**) Goldbach's conjecture.
[P40](src/main/scala/arithmetic/P40.scala) (**) Goldbach's conjecture.

P41 (**) A list of Goldbach compositions.
[P41](src/main/scala/arithmetic/P41.scala) (**) A list of Goldbach compositions.

## Logic and Codes

Expand Down
16 changes: 16 additions & 0 deletions src/main/scala/arithmetic/P31.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package arithmetic

// P31 (**) Determine whether a given integer number is prime.
// scala> 7.isPrime
// res0: Boolean = true

object P31:
def isPrime(n: Int): Boolean =
if n == 2 || n == 3
then true
else if n <= 1 || (n % 2) == 0 || (n % 3) == 0
then false
else
val i = Math.sqrt(n.toDouble).toInt
val prime = (j: Int) => (n % j) != 0 && (n % (j + 2)) != 0
(5 to i).forall(prime)
16 changes: 16 additions & 0 deletions src/main/scala/arithmetic/P32.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package arithmetic

// P32 (**) Determine the greatest common divisor of two positive integer
// numbers.
// Use Euclid's algorithm.
//
// scala> gcd(36, 63)
// res0: Int = 9

object P32:
def gcd(x: Int, y: Int): Int =
if y == 0
then x
else if x < y
then gcd(y, x)
else gcd(y, x % y)
11 changes: 11 additions & 0 deletions src/main/scala/arithmetic/P33.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package arithmetic

// P33 (*) Determine whether two positive integer numbers are coprime.
// Two numbers are coprime if their greatest common divisor equals 1.
//
// scala> 35.isCoprimeTo(64)
// res0: Boolean = true

object P33:
def isCoprime(x: Int, y: Int): Boolean =
P32.gcd(x, y) == 1
20 changes: 20 additions & 0 deletions src/main/scala/arithmetic/P34.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package arithmetic

// P34 (**) Calculate Euler's totient function phi(m).
// Euler's so-called totient function phi(m) is defined as the number of
// positive integers r (1 <= r < m) that are coprime to m. As a special
// case, phi(1) is defined to be 1.
//
// scala> 10.totient
// res0: Int = 4

object P34:
private val f = (x: Int) => 1 - 1 / x.toDouble

def totient(x: Int): Int =
val y = P35
.primeFactors(x)
.map(f)
.foldLeft(1.0d)(_ * _)

(x * y).toInt
26 changes: 26 additions & 0 deletions src/main/scala/arithmetic/P35.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package arithmetic

// P35 (**) Determine the prime factors of a given positive integer.
// Construct a flat list containing the prime factors in ascending order.
//
// scala> 315.primeFactors
// res0: List[Int] = List(3, 3, 5, 7)

object P35:
private val primes = LazyList.iterate(2) { n =>
Iterator
.from(n + 1)
.dropWhile(!P31.isPrime(_))
.next()
}

private def primeFactors(ll: LazyList[Int], x: Int): List[Int] =
if x <= 1
then Nil
else
val k = ll.head
if x > 1 && x % k == 0
then k :: primeFactors(ll, x / k)
else primeFactors(ll.tail, x)

def primeFactors(x: Int): List[Int] = primeFactors(primes, x)
18 changes: 18 additions & 0 deletions src/main/scala/arithmetic/P36.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package arithmetic

// P36 (**) Determine the prime factors of a given positive integer (2).
// Construct a list containing the prime factors and their multiplicity.
//
// scala> 315.primeFactorMultiplicity
// res0: List[(Int, Int)] = List((3,2), (5,1), (7,1))
//
// Alternately, use a Map for the result.
// scala> 315.primeFactorMultiplicity
// res0: Map[Int,Int] = Map(3 -> 2, 5 -> 1, 7 -> 1)

object P36:
def primeFactorMultiplicity(x: Int): Map[Int, Int] =
P35
.primeFactors(x)
.groupBy(identity)
.map((k, v) => (k, v.length))
32 changes: 32 additions & 0 deletions src/main/scala/arithmetic/P39.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package arithmetic

import math.Integral.Implicits.infixIntegralOps

// P39 (*) A list of prime numbers.
// Given a range of integers by its lower and upper limit, construct a list
// of all prime numbers in that range.
//
// scala> listPrimesinRange(7 to 31)
// res0: List[Int] = List(7, 11, 13, 17, 19, 23, 29, 31)

object P39:
def primesInRng(a: Int, b: Int): List[Int] =
val o = 3.max(a + (if a % 2 == 0 then 1 else 0))
val r = Math.sqrt(b.toDouble + 1).toInt
val composites =
(for
p <- (3 to r by 2)
q = p * p
s = 2 * p
(n, x) = (o - q) /% s
q2 =
if o <= q
then q
else q + (n + x.sign) * s
i <- q2 to b by s
yield i).toSet

val xs = (o to b by 2).filterNot(composites.contains).toList
if a < 3
then 2 :: xs
else xs
22 changes: 22 additions & 0 deletions src/main/scala/arithmetic/P40.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package arithmetic

// P40 (**) Goldbach's conjecture.
// Goldbach's conjecture says that every positive even number greater than 2
// is the sum of two prime numbers. E.g. 28 = 5 + 23. It is one of the
// most famous facts in number theory that has not been proved to be correct
// in the general case. It has been numerically confirmed up to very large
// numbers (much larger than Scala's Int can represent). Write a function
// to find the two prime numbers that sum up to a given even integer.
//
// scala> 28.goldbach
// res0: (Int, Int) = (5,23)

object P40:
// This implementation isn't very efficient because the primes are generated
// eagerly. It works much better in Haskell where list is lazy.
def goldbach(n: Int): (Int, Int) =
P39
.primesInRng(2, n - 2)
.collect:
case x if P31.isPrime(n - x) => (x, n - x)
.head
34 changes: 34 additions & 0 deletions src/main/scala/arithmetic/P41.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package arithmetic

// P41 (**) A list of Goldbach compositions.
// Given a range of integers by its lower and upper limit, print a list of
// all even numbers and their Goldbach composition.
//
// scala> printGoldbachList(9 to 20)
// 10 = 3 + 7
// 12 = 5 + 7
// 14 = 3 + 11
// 16 = 3 + 13
// 18 = 5 + 13
// 20 = 3 + 17
//
// In most cases, if an even number is written as the sum of two prime
// numbers, one of them is very small. Very rarely, the primes are both
// bigger than, say, 50. Try to find out how many such cases there are in
// the range 2..3000.
//
// Example (minimum value of 50 for the primes):
// scala> printGoldbachListLimited(1 to 2000, 50)
// 992 = 73 + 919
// 1382 = 61 + 1321
// 1856 = 67 + 1789
// 1928 = 61 + 1867

object P41:
// This implementation isn't very efficient because the primes are generated
// eagerly. It works much better in Haskell where list is lazy.
def goldbachList(a: Int, b: Int): Map[Int, (Int, Int)] =
(a to b)
.collect:
case x if x % 2 == 0 => (x, P40.goldbach(x))
.toMap
4 changes: 2 additions & 2 deletions src/main/scala/list/P28.scala
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,5 @@ object P28:
l.sortBy(_.length)

def lsortFreq[A](l: List[List[A]]): List[List[A]] =
val ls = l.map(_.length)
l.sortBy(xs => ls.count(_ == xs.length))
val ls = l.foldLeft(Map.empty[Int, Int])((acc, xs) => acc.updatedWith(xs.length)(_.map(_ + 1).orElse(Some(1))))
l.sortBy(xs => ls(xs.length))
20 changes: 20 additions & 0 deletions src/test/scala/arithmetic/P31Suite.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package arithmetic

import munit.FunSuite

class P31Suite extends FunSuite:

test("determine whether a given integer is prime"):
val data = List(
(1, false),
(2, true),
(3, true),
(4, false),
(5, true),
(6, false),
(7, true),
(11, true)
)
data.foreach { (n, prime) =>
assertEquals(P31.isPrime(n), prime, s"n=${n}")
}
11 changes: 11 additions & 0 deletions src/test/scala/arithmetic/P32Suite.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package arithmetic

import munit.FunSuite

class P32Suite extends FunSuite:

test("determine the greatest common divisor of two positive integers"):
assertEquals(P32.gcd(36, 63), 9)
assertEquals(P32.gcd(63, 36), 9)
assertEquals(P32.gcd(125, 81), 1)
assertEquals(P32.gcd(221, 559), 13)
9 changes: 9 additions & 0 deletions src/test/scala/arithmetic/P33Suite.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package arithmetic

import munit.FunSuite

class P33Suite extends FunSuite:

test("determine whether two positive integer numbers are coprime"):
assertEquals(P33.isCoprime(35, 64), true)
assertEquals(P33.isCoprime(1173, 1547), false)
8 changes: 8 additions & 0 deletions src/test/scala/arithmetic/P34Suite.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package arithmetic

import munit.FunSuite

class P34Suite extends FunSuite:

test("calculate Euler's totient function phi"):
assertEquals(P34.totient(10), 4)
19 changes: 19 additions & 0 deletions src/test/scala/arithmetic/P35Suite.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package arithmetic

import munit.FunSuite

class P35Suite extends FunSuite:

test("determine the prime factors of a given positive integer"):
val data = List(
(1, Nil),
(2, List(2)),
(9, List(3, 3)),
(8, List(2, 2, 2)),
(12, List(2, 2, 3)),
(315, List(3, 3, 5, 7)),
(901255, List(5, 17, 23, 461))
)
data.foreach { (n, pf) =>
assertEquals(P35.primeFactors(n), pf)
}
8 changes: 8 additions & 0 deletions src/test/scala/arithmetic/P36Suite.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package arithmetic

import munit.FunSuite

class P36Suite extends FunSuite:

test("construct a list containing the prime factors and their multiplicity for a given integer"):
assertEquals(P36.primeFactorMultiplicity(315), Map(3 -> 2, 5 -> 1, 7 -> 1))
14 changes: 14 additions & 0 deletions src/test/scala/arithmetic/P39Suite.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package arithmetic

import munit.FunSuite

class P39Suite extends FunSuite:

test("construct a list of all prime numbers within a given range"):
val obtained = P39.primesInRng(7, 31)
val expected = List(7, 11, 13, 17, 19, 23, 29, 31)
assertEquals(obtained, expected)

val obtained1 = P39.primesInRng(10, 20)
val expected1 = List(11, 13, 17, 19)
assertEquals(obtained1, expected1)
10 changes: 10 additions & 0 deletions src/test/scala/arithmetic/P40Suite.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package arithmetic

import munit.FunSuite

class P40Suite extends FunSuite:

test("find the two prime numbers that sum up to a given even integer"):
val obtained = P40.goldbach(28)
val expected = (5, 23)
assertEquals(obtained, expected)
17 changes: 17 additions & 0 deletions src/test/scala/arithmetic/P41Suite.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package arithmetic

import munit.FunSuite

class P41Suite extends FunSuite:

test("find the Goldbach compositions of all even numbers within a given range"):
val obtained = P41.goldbachList(9, 20)
val expected = Map(
10 -> (3, 7),
12 -> (5, 7),
14 -> (3, 11),
16 -> (3, 13),
18 -> (5, 13),
20 -> (3, 17)
)
assertEquals(obtained, expected)

0 comments on commit be445d0

Please sign in to comment.