Why do the following algorithms for Quadratic Primes perform so differently? I'm trying to solve for https://projecteuler.net/problem=27, and I have to optimize one part of the implementation from slow() to fast(). Why do they perform so differently? I'm guessing branch predictions, but I don't quite understand how they are different to the optimizer. The code is in javascript.
function primes(n) {
    const P = new Array(n).fill(1)
    P[0] = 0
    P[1] = 0
    for (let i = 2; i &lt;= n; i++) {
        for (let j = 2*i; j &lt;= n; j += i) {
            P[j] = 0
        }
    }
    return P
}
const P = primes(1_000_000)

function slow(a, b) {
    for (let i = 0; ; i++) {
        if (P[i*i+a*i+b] == 0) {
            return i - 1 // the reason why it's slow is probably because of the fork-away of return inside the loop.
        }
    }
}

function fast(a, b) {
    let i
    for (i = 0; P[i*i+a*i+b] == 1; i++) {}
    return i // so this optimization works as long as we only need 1 index value
}

function qp(n, algo = npc) {
    let max = 0
    let maxa, maxb
    for (let a = -n; a &lt;= n; a++) {
        for (let b = -n; b &lt;= n; b++) {
            // here's the trick. CPU can optimize if it can SOMEHOW predict the branch pattern, which probably goes all the way false.
            // if we write npa(), we are nesting another loop-branch within, and then CPU refuses to take a guess on the outer loop.
            const i = algo(a, b)
            if (i &gt; max) {
                max = i
                maxa = a
                maxb = b
            }
        }
    }
    return [maxa, maxb]
}

// pretty much that same:
fast(-61, 971)
slow(-61, 971)

// huge difference:
qp(200, fast)
qp(200, slow)

Here are some benchmarks in chromium:
     |   n |  time
slow | 100 |   165
     | 200 |  1090
     | 400 | 10176
fast | 100 |    12
     | 200 |    27
     | 400 |    99
Well, I finally find out I'm just writing bad code that results in too many computations.
The condition in slow() should be P[i*i+a*i+b] != 1 instead of P[..] == 0 because there are cases when the index is smaller than 0.