Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
100.00% |
38 / 38 |
|
100.00% |
5 / 5 |
CRAP | |
100.00% |
1 / 1 |
Integer | |
100.00% |
38 / 38 |
|
100.00% |
5 / 5 |
19 | |
100.00% |
1 / 1 |
__construct | n/a |
0 / 0 |
n/a |
0 / 0 |
1 | |||||
isInteger | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
trialFactorization | |
100.00% |
13 / 13 |
|
100.00% |
1 / 1 |
6 | |||
pollardsRho | |
100.00% |
7 / 7 |
|
100.00% |
1 / 1 |
4 | |||
greatestCommonDivisor | |
100.00% |
7 / 7 |
|
100.00% |
1 / 1 |
3 | |||
fermatFactor | |
100.00% |
10 / 10 |
|
100.00% |
1 / 1 |
4 |
1 | <?php |
2 | /** |
3 | * Jingga |
4 | * |
5 | * PHP Version 8.1 |
6 | * |
7 | * @package phpOMS\Math\Number |
8 | * @copyright Dennis Eichhorn |
9 | * @license OMS License 2.0 |
10 | * @version 1.0.0 |
11 | * @link https://jingga.app |
12 | */ |
13 | declare(strict_types=1); |
14 | |
15 | namespace phpOMS\Math\Number; |
16 | |
17 | /** |
18 | * Integer class |
19 | * |
20 | * @package phpOMS\Math\Number |
21 | * @license OMS License 2.0 |
22 | * @link https://jingga.app |
23 | * @since 1.0.0 |
24 | */ |
25 | final class Integer |
26 | { |
27 | /** |
28 | * Constructor. |
29 | * |
30 | * @since 1.0.0 |
31 | * @codeCoverageIgnore |
32 | */ |
33 | private function __construct() |
34 | { |
35 | } |
36 | |
37 | /** |
38 | * Is integer. |
39 | * |
40 | * @param mixed $value Value to test |
41 | * |
42 | * @return bool |
43 | * |
44 | * @since 1.0.0 |
45 | */ |
46 | public static function isInteger(mixed $value) : bool |
47 | { |
48 | return \is_int($value); |
49 | } |
50 | |
51 | /** |
52 | * Trial factorization. |
53 | * |
54 | * @param int $value Integer to factorize |
55 | * |
56 | * @return array<int|float> |
57 | * |
58 | * @since 1.0.0 |
59 | */ |
60 | public static function trialFactorization(int $value) : array |
61 | { |
62 | if ($value < 2) { |
63 | return []; |
64 | } |
65 | |
66 | $factors = []; |
67 | $primes = Prime::sieveOfEratosthenes((int) $value ** 0.5); |
68 | |
69 | foreach ($primes as $prime) { |
70 | if ($prime * $prime > $value) { |
71 | break; |
72 | } |
73 | |
74 | while ($value % $prime === 0) { |
75 | $factors[] = $prime; |
76 | $value /= $prime; |
77 | } |
78 | } |
79 | |
80 | if ($value > 1) { |
81 | $factors[] = $value; |
82 | } |
83 | |
84 | return $factors; |
85 | } |
86 | |
87 | /** |
88 | * Pollard's Rho. |
89 | * |
90 | * Integer factorization algorithm |
91 | * |
92 | * @param int $n Integer to factorize |
93 | * @param int $x Used for g(x) = (x^2 + 1) mod n |
94 | * @param int $factor Period for repetition |
95 | * @param int $cycleSize Cycle size |
96 | * @param int $y Fixed value for g(x) = g(y) mod p |
97 | * |
98 | * @return int |
99 | * |
100 | * @since 1.0.0 |
101 | */ |
102 | public static function pollardsRho(int $n, int $x = 2, int $factor = 1, int $cycleSize = 2, int $y = 2) : int |
103 | { |
104 | while ($factor === 1) { |
105 | for ($i = 1; $i < $cycleSize && $factor <= 1; ++$i) { |
106 | $x = ($x * $x + 1) % $n; |
107 | $factor = self::greatestCommonDivisor($x - $y, $n); |
108 | } |
109 | |
110 | $cycleSize *= 2; |
111 | $y = $x; |
112 | } |
113 | |
114 | return $factor; |
115 | } |
116 | |
117 | /** |
118 | * Greatest common diviser. |
119 | * |
120 | * @param int $n Number one |
121 | * @param int $m Number two |
122 | * |
123 | * @return int |
124 | * |
125 | * @since 1.0.0 |
126 | */ |
127 | public static function greatestCommonDivisor(int $n, int $m) : int |
128 | { |
129 | $n = \abs($n); |
130 | $m = \abs($m); |
131 | |
132 | while ($n !== $m) { |
133 | if ($n > $m) { |
134 | $n -= $m; |
135 | } else { |
136 | $m -= $n; |
137 | } |
138 | } |
139 | |
140 | return $m; |
141 | } |
142 | |
143 | /** |
144 | * Fermat factorization of odd integers. |
145 | * |
146 | * @param int $value Integer to factorize |
147 | * @param int $limit Max amount of iterations |
148 | * |
149 | * @return int[] |
150 | * |
151 | * @throws \InvalidArgumentException This exception is thrown if the value is not odd |
152 | * |
153 | * @since 1.0.0 |
154 | */ |
155 | public static function fermatFactor(int $value, int $limit = 1000000) : array |
156 | { |
157 | if (($value % 2) === 0) { |
158 | throw new \InvalidArgumentException('Only odd integers are allowed'); |
159 | } |
160 | |
161 | $a = (int) \ceil(\sqrt($value)); |
162 | $b2 = ($a * $a - $value); |
163 | $i = 1; |
164 | |
165 | while (!Numbers::isSquare($b2) && $i < $limit) { |
166 | ++$i; |
167 | ++$a; |
168 | $b2 = ($a * $a - $value); |
169 | } |
170 | |
171 | return [(int) \round($a - \sqrt($b2)), (int) \round($a + \sqrt($b2))]; |
172 | } |
173 | } |