I recently wrote an entry on my blog regarding unit testing using prime numbers as an example.
When I wrote the entry, I wrote my code keeping in minding that proposal SE-0007 has been accepted for Swift 3.0. That is, C-style for loops will no longer be available in Swift as of 3.0, so I want to completely discontinue using them.
That is to say, where I might have written something like this:
for(int divisor = 7; divisor * divisor <= value; divisor += 30) {
I was instead stuck with some real ugliness in my prime loop.
func isPrime(value: Int) -> Bool {
if value < 2 { return false }
if value % 2 == 0 { return value == 2 }
if value % 3 == 0 { return value == 3 }
if value % 5 == 0 { return value == 5 }
if value == 7 { return true }
var divisor = 7
while divisor * divisor <= value {
if value % divisor == 0 { return false }
if value % (divisor + 4) == 0 { return false }
if value % (divisor + 6) == 0 { return false }
if value % (divisor + 10) == 0 { return false }
if value % (divisor + 12) == 0 { return false }
if value % (divisor + 16) == 0 { return false }
if value % (divisor + 22) == 0 { return false }
if value % (divisor + 24) == 0 { return false }
divisor += 30
}
return true
}
I am satisfied that this code works as I want. I am also satisfied that is runs extraordinarily fast.
What I do not like about this is the very round-about way I have to achieve the same behavior a C-style for loop would have given me. In particular, it is the termination point that concerns me. I could easily get the same loop steps with the stride function:
for divisor in 7.stride(through: value, by: 30) {
But this doesn't allow for the same early stopping point:
divisor * divisior <= value
And making the first line of the loop check this isn't much better:
for divisor in 7.stride(through: value, by: 30) { if divisor * divisor > value { break }
And the biggest problem with the while loop which I'd like reviewed is that the divisor variable has a scope larger than I'd like, and the update statement doesn't come until the very end of the while loop (a problem that becomes more complex if your loop has any continue statements in it anywhere that allow iterations to break out early and jump to the next iteration).
So, in the end, I want a very, very fast isPrime() checker (it should be at least as fast as the above code), but I'd like the ugliness of my while loop to be significantly cleaned up.
ifstatements? \$\endgroup\$for divisor in 7.stride(through: upperBound, by: 30)whereupperBoundis precomputed as the integer square root ofvalue. \$\endgroup\$