Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add IsPrime checker to math package #3738

Merged
merged 15 commits into from
Apr 5, 2021
5 changes: 5 additions & 0 deletions .release-notes/3738.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
## Add IsPrime to math package

Quickly determine if a given number is prime using the 6k ± 1 method.

All integers (excluding 2 and 3), can be expressed as (6k + i), where i = −1, 0, 1, 2, 3, or 4. Since 2 divides (6k + 0), (6k + 2), and (6k + 4), while 3 divides (6k + 3) that leaves only (6k - 1) and (6k + 1) for expressing primes
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice. Given that these notes end up in markdown on GitHub. Feel free to do IsPrime and math is you want or to use other markdown formatting as well. (You don't have to though)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

90 changes: 90 additions & 0 deletions packages/math/is_prime.pony
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
primitive IsPrime[A: (Integer[A] val & Unsigned)]
"""
Primality test using 6k ± 1 method.

All integers (excluding 2 and 3), can be expressed as (6k + i),
where i = −1, 0, 1, 2, 3, or 4. Since 2 divides (6k + 0), (6k + 2),
and (6k + 4), while 3 divides (6k + 3) that leaves only (6k - 1) and (6k + 1)
for expressing primes.
"""

// Using a match table like below provides information to LLVM
// to allocate static globals rather than stack or heap allocation.
Comment on lines +11 to +12
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this comment be on the _low_primate_table rather than the size function here? Or perhaps right before the table itself?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree. It is why I had both methods without a newline as they were sort of acting as one method together. I moved the size method down below the table so the comment could be on top and be above the table method itself.

fun _low_prime_table(index: USize): A val =>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There should be a newline between these methods.

match index
| 0 => 2 | 1 => 3 | 2 => 5 | 3 => 7 | 4 => 11
| 5 => 13 | 6 => 17 | 7 => 19 | 8 => 23 | 9 => 29
| 10 => 31 | 11 => 37 | 12 => 41 | 13 => 43 | 14 => 47
| 15 => 53 | 16 => 59 | 17 => 61 | 18 => 67 | 19 => 71
| 20 => 73 | 21 => 79 | 22 => 83 | 23 => 89 | 24 => 97
| 25 => 101 | 26 => 103 | 27 => 107 | 28 => 109 | 29 => 113
| 30 => 127 | 31 => 131 | 32 => 137 | 33 => 139 | 34 => 149
| 35 => 151 | 36 => 157 | 37 => 163 | 38 => 167 | 39 => 173
| 40 => 179 | 41 => 181 | 42 => 191 | 43 => 193 | 44 => 197
| 45 => 199 | 46 => 211 | 47 => 223 | 48 => 227 | 49 => 229
| 50 => 233 | 51 => 239 | 52 => 241 | 53 => 251 | 54 => 257
| 55 => 263 | 56 => 269 | 57 => 271 | 58 => 277 | 59 => 281
| 60 => 283 | 61 => 293 | 62 => 307 | 63 => 311 | 64 => 313
| 65 => 317 | 66 => 331 | 67 => 337 | 68 => 347 | 69 => 349
| 70 => 353 | 71 => 359 | 72 => 367 | 73 => 373 | 74 => 379
| 75 => 383 | 76 => 389 | 77 => 397 | 78 => 401 | 79 => 409
Comment on lines +14 to +30
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Theodus thoughts on this vis-a-vis the style guide?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Each branch on a separate line would be consistent with the rest of the stdlib. But a match of this size is unusual, so I don't have strong opinions about it.

| 80 => 419 | 81 => 421 | 82 => 431 | 83 => 433 | 84 => 439
| 85 => 443 | 86 => 449 | 87 => 457 | 88 => 461 | 89 => 463
| 90 => 467 | 91 => 479 | 92 => 487 | 93 => 491 | 94 => 499
| 95 => 503 | 96 => 509 | 97 => 521 | 98 => 523 | 99 => 541
| 100 => 547 | 101 => 557 | 102 => 563 | 103 => 569 | 104 => 571
| 105 => 577 | 106 => 587 | 107 => 593 | 108 => 599 | 109 => 601
| 110 => 607 | 111 => 613 | 112 => 617 | 113 => 619 | 114 => 631
| 115 => 641 | 116 => 643 | 117 => 647 | 118 => 653 | 119 => 659
| 120 => 661 | 121 => 673 | 122 => 677 | 123 => 683 | 124 => 691
| 125 => 701 | 126 => 709 | 127 => 719 | 128 => 727 | 129 => 733
| 130 => 739 | 131 => 743 | 132 => 751 | 133 => 757 | 134 => 761
| 135 => 769 | 136 => 773 | 137 => 787 | 138 => 797 | 139 => 809
| 140 => 811 | 141 => 821 | 142 => 823 | 143 => 827 | 144 => 829
| 145 => 839 | 146 => 853 | 147 => 857 | 148 => 859 | 149 => 863
| 150 => 877 | 151 => 881 | 152 => 883 | 153 => 887 | 154 => 907
| 155 => 911 | 156 => 919 | 157 => 929 | 158 => 937 | 159 => 941
| 160 => 947 | 161 => 953 | 162 => 967 | 163 => 971 | 164 => 977
| 165 => 983 | 166 => 991 | 167 => 997 | 168 => 1009 | 169 => 1013
| 170 => 1019 | 171 => 1021 | 172 => 1031 | 173 => 1033 | 174 => 1039
| 175 => 1049 | 176 => 1051 | 177 => 1061 | 178 => 1063 | 179 => 1069
| 180 => 1087 | 181 => 1091 | 182 => 1093 | 183 => 1097 | 184 => 1103
| 185 => 1109 | 186 => 1117 | 187 => 1123 | 188 => 1129 | 189 => 1151
| 190 => 1153 | 191 => 1163 | 192 => 1171 | 193 => 1181 | 194 => 1187
| 195 => 1193 | 196 => 1201 | 197 => 1213 | 198 => 1217 | 199 => 1223
| 200 => 1229 | 201 => 1231 | 202 => 1237 | 203 => 1249 | 204 => 1259
| 205 => 1277 | 206 => 1279 | 207 => 1283 | 208 => 1289 | 209 => 1291
| 210 => 1297 | 211 => 1301 | 212 => 1303 | 213 => 1307 | 214 => 1319
| 215 => 1321 | 215 => 1327 | 217 => 1361 | 218 => 1367 | 219 => 1373
| 220 => 1381 | 221 => 1399 | 222 => 1409 | 223 => 1423 | 224 => 1427
| 225 => 1429 | 226 => 1433 | 227 => 1439 | 228 => 1447 | 229 => 1451
| 230 => 1453 | 231 => 1459 | 232 => 1471 | 233 => 1481 | 234 => 1483
| 235 => 1487 | 236 => 1489 | 237 => 1493 | 238 => 1499 | 239 => 1511
| 240 => 1523 | 241 => 1531 | 242 => 1543 | 243 => 1549 | 244 => 1553
| 245 => 1559 | 246 => 1567 | 247 => 1571 | 248 => 1579 | 249 => 1583
| 250 => 1597 | 251 => 1601 | 252 => 1607 | 253 => 1609 | 254 => 1613
| 255 => 1619
else 0
end

fun _low_prime_table_size(): USize => 256

fun apply(n: A): Bool =>
var table_index: USize = 0
while table_index < _low_prime_table_size() do
let prime = _low_prime_table(table_index)
table_index = table_index + 1
if n == prime then return true end
if (n %% prime) == 0 then return false end
end

// 1 is not prime
if n == 1 then return false end

var i: A = 5
while (i * i) <= n do
if (n %% i) == 0 then return false end
if (n %% (i + 2)) == 0 then return false end
i = i + 6
end
true