## Thursday, 16 October 2014

### CFML: Gert points out a schoolboy error in my prime numbers generator logic

G'day:
I was messing around with using closure to mimic a generator the other day: "CFML: prime number generator UDF, and overhead of using inline function expressions". Gert had a look at it, and spotted a shortfall in my implementation. He's provided some code as well but I've not really looked at that yet, instead wanting to nut it out myself (part as a penance, part as an exercise).

Here's the original implementation:

``````function createPrimeNumberSequence(){
var primes = [];
var potential = 1;
var upperThresholdToCheck = false;

var everyHandler = function(prime){
if (potential mod prime != 0) return true;
if (prime > upperThresholdToCheck) return true;
return false;
}

return function(){
while(true) {
upperThresholdToCheck = sqr(++potential);
var potentialIsPrime = primes.every(everyHandler);
if (potentialIsPrime) {
primes.append(potential);
return potential;
}
}
};
}
``````

The key part is highlighted. Before reading on, see if you spot what I'm doing wrong.

Here's my logic (not - as it happens - the code's logic; my logic):
• we already have zero or more primes from potential previous calls to the function;
• to find the next prime, we incrementally check a potential value;
• we need to check the potential for prime factors. If it has any: it itself is not a prime;
• we need to check each prime up to and including its square root. If we have not found a factor by the time we get to its square root, it can't possibly have any prime factors.
• So we loop through `every()` prime. This is a slight misuse of `every()`, but we need an iteration method we can exit from it midway through, which one cannot do from the other array iteration methods.
• If the number isn't a factor of that prime, we need to check the next, so exit.
• If we're here and the current prime is beyond the square root threshold, then the potential is a prime, so return true;
• otherwise it's not a prime, so exit, returning false.
Written like that, the logic is fine. However I've ballsed up how `every()` works. There are two significant values one can return from the `every()` callback function:
• false: exit the whole loop (so: like `break`)
• true: exit the current iteration (so: like `continue`)

I stopped paying attention to what I'm doing, and am treating the return value from the callback as if it's the result of my question: is it a prime or not? This is not right. When I do the return true when processing reaches the square root threshold, I am returning true; which means "keep looping". Grumble. What a dick. You know what's worse? This isn't down to me previously not knowing how `every()` works: I knew all this full-well. I just wasn't thinking. I hate that.

I can't possibly conflate "exit the loop now" and "is it a prime?" in the one value from that callback. What I need to do is to set a variable to represent whether the potential is a prime or not, then leave the return value to do its job.

I was still getting the right results because the rest of the logic was OK, I was just doing an awful lot more work than necessary: always checking right to the end of the primes array.

Here's the fix for this:

``````function createPrimeNumberSequence(){
var primes = []
var potential = 1
var upperThresholdToCheck = false
var potentialIsPrime = false

var someHandler = function(prime){
if (potential mod prime == 0){
potentialIsPrime = false
return true
}
if (prime > upperThresholdToCheck) return true
return false
}

return function(){
while (true) {
upperThresholdToCheck = sqr(++potential)
potentialIsPrime = true
primes.some(someHandler)
if (potentialIsPrime) {
primes.append(potential)
return potential
}
}
}
}
``````

So in here I've done just a couple of things differently:

• I'm using `some()` not `every()`. Either would have worked, but as I feel that `some()` is more semantically correct here. I already know that I'll not even be checking every element of the collection; it'll just be some of them, so I'm using the best fit for the job.
• I'm using `potentialIsPrime` differently. I'm setting it within the callback once I know the answer. The answer can be determined in one of two ways:
1. the potential is found to have a prime factor: it's not a prime.
2. We get to the end of the primes we need to check: it is - therefore - a prime.
Note I have have to hoist its declaration into the main function, so the callback can enclose it for use.
If I now slide some execution metrics into each variation of the functions, I get this output:

### `Original Using for() loop`

`Loop iterated: 34048 timesExecution time: 27ms`

### ``` Original using every()```

``` Handler called: 516383 timesExecution time: 616ms```

``` ```

### ``` Updated using some()```

``` Handler called: 34048 timesExecution time: 425ms```

``` ```

Look how much extra bloody work my version was doing previous! No wonder it was so much slower! But still: it's way way slower than just using a loop.

Gert addresses this in his comment, but I'll get to that.

Oh, and checking against Gert's code: he's reached the same conclusion and uses `bExitedWithThreshold `much the same way as I am using `potentialIsPrime` in my version.

There is a further optimisation I can make to both versions though. Once that all prime number generator / calculator functions do but I initially refused to here. After the second iteration (having identified 2 and 3 as primes), I can thenceforth increment potential by two, instead of one. Why? Because no even numbers are primes, so people generally just assess odd numbers.

Why don't I like this? Because it's incomplete thinking. "Even numbers" are not special here. What we really mean is "multiples of 2". And why is 2 significant? Because it's a prime, and any multiple of it after the first one will definitely not be a prime. But 2 is not special in this regard. multiples of 3, likewise, intrinsically aren't prime, so after we find three we should increment by [a value which will not land us on either a multiple of 2 or 3]. Likewise after 5, we should increment by [a value which will not land us on either a multiple of 2, 3 or 5]. And so on. So to me, solutions which increment by 2 are using it as a magic number. Which is poor practice.

However. I also firmly believe that one should not hang on to dogma at the expense of being practical. Having reminded myself of that, I've pulled my head out of my arse and concluded that a better but not perfect solution is still a better one. And let's be realistic: this whole approach to identifying primes is not the optimal way of doing it anyhow.

OK, so I've modified both the loop and `some()` versions of this, in the same way:

``````function createPrimeNumberSequenceLoopImproved(){
var primes = 
var potential = 1

return function(){
while (true) {
potential += 2
var upperThresholdToCheck = sqr(potential)
var potentialIsPrime = true
for (var prime in primes){
if (potential mod prime == 0) {
potentialIsPrime = false
break;
}
if (prime > upperThresholdToCheck) break;
}
if (potentialIsPrime) {
primes.append(potential)
return primes[primes.len()-1]
}
}
}
}
``````

• If I'm gonna use magic numbers, then I'm gonna leverage that fact. I stipulate the first prime is 2.
• This means I don't have to have a conditional to determine the increment for potential: it can always be 2.
• A quirk of stipulating 2 as already being a prime, my calculations now actually work out the next prime. So I need to return the previous one in the array. I figure this is less overhead than having to work out how much to increment potential inside that while loop: after the first two turns, it's always gonna be 2, after all.

And the same updates have been made to the `some()` version:

``````function createPrimeNumberSequenceSomeImproved(){
var primes = 
var potential = 1
var upperThresholdToCheck = false
var potentialIsPrime = false

var someHandler = function(prime){
if (potential mod prime == 0){
potentialIsPrime = false
return true
}
if (prime > upperThresholdToCheck) return true
return false
}

return function(){
while (true) {
potential += 2
upperThresholdToCheck = sqr(potential)
potentialIsPrime = true
primes.some(someHandler)
if (potentialIsPrime) {
primes.append(potential)
return primes[primes.len()-1]
}
}
}
}
``````

Checking the metrics on this, I now get:

``` ```

### `Original Using for() loop`

`Loop iterated: 34048 timesExecution time: 27ms`

``` ```

### ``` Improved using for() loop```

``` Handler called: 30144 timesExecution time: 12ms```

``` Original using every() Handler called: 516383 timesExecution time: 616ms Updated using some() Handler called: 34048 timesExecution time: 425ms Improved using some() Handler called: 30144 timesExecution time: 224ms ```

We've knocked 10% of the iterations off here. I kinda expected it to be closer to a 50% improvement, and am not sure why it isn't. I'm sure it's obvious if I engage my brain.

The last thing that Gert said which is commentworthy:

In total with 1000 iteration there are a total of 34000 function calls. So IMHO comparing 34000 function calls with a simple for in statement is really like apples and pears. The calls of the functons are actually taking 90% of the total every time. The time inside the closure is only 10%.
Well: yes. This was entirely my point. I wasn't claiming the code inside the loop or the callback was faster or slower: I'd expect that to be the same. It's that the overhead of calling the callback is significant. As he says... 90% of the overhead of the work. This is a significant consideration when choosing a strategy.

If you're doing something that's under heavy load - like this sort of thing - I recommend not using the iteration functions (`some()`, `every()`, `map()`, `reduce()` etc), just use a vanilla loop. However in situations where there is not so much load, do use the iteration functions as they make the intent of the code much clearer. I don't actually think my code here is an example of that, TBH. In that the value I'm using from the `some()` code is not actually the function result (I am not actually checking if "some" of the array fulfils the criteria), I'm just leveraging its early-exit capabilities, I think this is actually a misuse of `some()`. The loop is better here. Even if it breaks my coding rule of a loop should generally act on the entire collection it's looping over. I guess there's some other iteration functionality I'm after here which more clearly describes how I'm processing the array. Hmmm.

Anyway, I need to update that thing on CFLib, I guess. Better crack on with that.

Cheers, Gert, for calling me out on this!

--