-
Notifications
You must be signed in to change notification settings - Fork 2
/
IntegerMath.scala
154 lines (129 loc) · 4.37 KB
/
IntegerMath.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
package integerOperations
import utils.InputException
import utils.ExceptionMessages._
import IntegerGenerators._
import IntegerProperties._
import scala.util.{Failure, Success, Try}
/**
* Contains functions, that use more specific math or algorithms.
*
* Purity project by Daniil Tekunov.
*/
class IntegerMath(val firstInt: Int) {
import IntegerMath._
/**
* Checks, if a number is free of squares.
*
* https://en.wikipedia.org/wiki/Square-free_integer
*/
def isFreeOfSquares: Boolean = {
if (firstInt <= 1) throw new InputException(NegativeInput)
else (for {cur <- firstInt.generateSquares if firstInt % cur == 0} yield true).isEmpty
}
/**
* Checks, if an Int is a Carmichael number.
*
* https://en.wikipedia.org/wiki/Carmichael_number
*/
def isCarmichael: Boolean = {
if (firstInt <= 1) throw new InputException(NegativeInput)
else if (firstInt.isFreeOfSquares && firstInt.isOdd) {
val curFactorisation: List[Int] = firstInt.generatePrimeDivisors.filter {cur => cur != firstInt}
(for {cur <- curFactorisation if (firstInt - 1) % (cur - 1) == 0} yield true).length == curFactorisation.length &&
curFactorisation.nonEmpty
}
else false
}
/**
* Checks, if an Int is a Lucas-Carmichael number.
*
* https://en.wikipedia.org/wiki/Lucas–Carmichael_number
*/
def isLucas_Carmichael: Boolean = {
if (firstInt <= 1) throw new InputException(NegativeInput)
else if (firstInt.isFreeOfSquares && firstInt.isOdd) {
val curFactorisation: List[Int] = firstInt.generatePrimeDivisors.filter {cur => cur != firstInt}
(for {cur <- curFactorisation if (firstInt + 1) % (cur + 1) == 0} yield true).length == curFactorisation.length &&
curFactorisation.nonEmpty
}
else false
}
/**
* Checks, if an Int is a Fibonacci number.
*
* https://en.wikipedia.org/wiki/Fibonacci_number
*/
def isFibonacci: Boolean = {
if (firstInt < 0) throw new InputException(NegativeInput)
else firstInt.generateFibonacci.contains(firstInt)
}
/**
* Generates Catalan number with `firstInt` index.
*
* https://en.wikipedia.org/wiki/Catalan_number
*/
def nthCatalan: Int = Try(nthCatalanLogic(firstInt)) match {
case Success(something) => something
case Failure(ex) => throw new InputException(ex.toString)
}
/**
* Sub-function for nthCatalan
*/
private def nthCatalanLogic(input: Int): Int = {
if (input <= 1) 1
else (0 until input).map(i => nthCatalanLogic(i) * nthCatalanLogic(input - i - 1)).sum
}
/**
* Realisation of a binary 'N' power of an Int.
*
* https://en.wikipedia.org/wiki/Exponentiation_by_squaring
*
* Works with O(log(n)) speed.
*/
def binaryPower(n: Int): Int = Try(binaryPowerLogic(firstInt, n)) match {
case Success(something) => something
case Failure(ex) => throw new InputException(ex.toString)
}
/**
* Sub-function for binaryPower
*/
private def binaryPowerLogic(cur: Int, n: Int): Int = {
if (n == 0) 1
else if (n % 2 == 1) binaryPowerLogic(cur, n - 1) * cur
else binaryPowerLogic(cur, n / 2) * binaryPowerLogic(cur, n / 2)
}
/**
* Checks, whether the number is a Zuckerman number
*
* http://www.numbersaplenty.com/set/Zuckerman_number/
*/
def isZuckerman: Boolean =
(firstInt.compositionOfDigits > 0) && (firstInt % firstInt.compositionOfDigits == 0) && (firstInt > 0)
/**
* Checks, whether the number is a Harshad number
*
* https://en.wikipedia.org/wiki/Harshad_number
*/
def isHarshad: Boolean = (firstInt == 0) || (firstInt % firstInt.sumOfDigits == 0) && (firstInt > 0)
/**
* Extended version of the Euclid's algorithm for gcd
*
* https://e-maxx.ru/algo/extended_euclid_algorithm
*/
def gcdExtendedWith(secondInt: Int): (Int, Int) = Try(gcdExtendedLogic(firstInt, secondInt)) match {
case Success(something) => (something._2, something._3)
case Failure(ex) => throw new InputException(ex.toString)
}
/**
* Sub-function for gcdExtended.
*/
private def gcdExtendedLogic(first: Int, second: Int): (Int, Int, Int) = second match {
case 0 => (firstInt, 1, 0)
case _ =>
val (d, x, y) = gcdExtendedLogic(second, first % second)
(d, y, x - y * (first / second))
}
}
object IntegerMath {
implicit def intToMathImplicit(a: Int): IntegerMath = new IntegerMath(a)
}