Task: Legendre prime counting function

C: #include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <stdint.h>
#include <time.h>

const uint8_t masks[8] = {1, 2, 4, 8, 16, 32, 64, 128};

#define half(n) ((int64_t)((n) - 1) >> 1)

#define divide(nm, d) ((uint64_t)((double)nm / (double)d))

int64_t countPrimes(uint64_t n) {
    if (n < 9) return (n < 2) ? 0 : ((int64_t)n + 1) / 2;    
    uint64_t rtlmt = (uint64_t)sqrt((double)n);
    int64_t mxndx = (int64_t)((rtlmt - 1) / 2);
    int arrlen = (int)(mxndx + 1);
    uint32_t *smalls = malloc(arrlen * 4);
    uint32_t *roughs = malloc(arrlen * 4);
    int64_t *larges  = malloc(arrlen * 8);
    for (int i = 0; i < arrlen; ++i) {
        smalls[i] = (uint32_t)i;
        roughs[i] = (uint32_t)(i + i + 1);
        larges[i] = (int64_t)((n/(uint64_t)(i + i + 1) - 1) / 2);
    }
    int cullbuflen = (int)((mxndx + 8) / 8);
    uint8_t *cullbuf = calloc(cullbuflen, 1);
    int64_t nbps = 0;
    int rilmt = arrlen;
    for (int64_t i = 1; ; ++i) {
        int64_t sqri = (i + i) * (i + 1);
        if (sqri > mxndx) break;
        if (cullbuf[i >> 3] & masks[i & 7]) continue;
        cullbuf[i >> 3] |= masks[i & 7];
        uint64_t bp = (uint64_t)(i + i + 1);
        for (int64_t c = sqri; c < (int64_t)arrlen; c += (int64_t)bp) {
            cullbuf[c >> 3] |= masks[c & 7];
        }
        int nri = 0;
        for (int ori = 0; ori < rilmt; ++ori) {
            uint32_t r = roughs[ori];
            int64_t rci = (int64_t)(r >> 1);
            if (cullbuf[rci >> 3] & masks[rci & 7]) continue;
            uint64_t d = (uint64_t)r * bp;
            int64_t t = (d <= rtlmt) ? larges[(int64_t)smalls[d >> 1] - nbps] :
                                       (int64_t)smalls[half(divide(n, d))];
            larges[nri] = larges[ori] - t + nbps;
            roughs[nri] = r;
            nri++;
        }
        int64_t si = mxndx;
        for (uint64_t pm = (rtlmt/bp - 1) | 1; pm >= bp; pm -= 2) {
            uint32_t c = smalls[pm >> 1];
            uint64_t e = (pm * bp) >> 1;
            for ( ; si >= (int64_t)e; --si) smalls[si] -= c - (uint32_t)nbps;                           
        }
        rilmt = nri;
        nbps++;
    }
    int64_t ans = larges[0] + (int64_t)((rilmt + 2*(nbps - 1)) * (rilmt - 1) / 2);
    int ri, sri;
    for (ri = 1; ri < rilmt; ++ri) ans -= larges[ri];
    for (ri = 1; ; ++ri) {
        uint64_t p = (uint64_t)roughs[ri];
        uint64_t m = n / p;
        int ei = (int)smalls[half((uint64_t)m/p)] - nbps;
        if (ei <= ri) break;
        ans -= (int64_t)((ei - ri) * (nbps + ri - 1));
        for (sri = ri + 1; sri < ei + 1; ++sri) {
            ans += (int64_t)smalls[half(divide(m, (uint64_t)roughs[sri]))];
        }
    }
    free(smalls);
    free(roughs);
    free(larges);
    free(cullbuf);
    return ans + 1;
}

int main() {
    uint64_t n;
    int i;
    clock_t start = clock();
    for (i = 0, n = 1; i < 10; ++i, n *= 10) {
        printf("10^%d %ld\n", i, countPrimes(n));
    }
    clock_t end = clock();
    printf("\nTook %f seconds\n", (double) (end - start) / CLOCKS_PER_SEC);
    return 0;
}


C++: #include <cmath>
#include <iostream>
#include <vector>

std::vector<int> generate_primes(int limit) {
    std::vector<bool> sieve(limit >> 1, true);
    for (int p = 3, s = 9; s < limit; p += 2) {
        if (sieve[p >> 1]) {
            for (int q = s; q < limit; q += p << 1)
                sieve[q >> 1] = false;
        }
        s += (p + 1) << 2;
    }
    std::vector<int> primes;
    if (limit > 2)
        primes.push_back(2);
    for (int i = 1; i < sieve.size(); ++i) {
        if (sieve[i])
            primes.push_back((i << 1) + 1);
    }
    return primes;
}

class legendre_prime_counter {
public:
    explicit legendre_prime_counter(int limit);
    int prime_count(int n);
private:
    int phi(int x, int a);
    std::vector<int> primes;
};

legendre_prime_counter::legendre_prime_counter(int limit) :
    primes(generate_primes(static_cast<int>(std::sqrt(limit)))) {}

int legendre_prime_counter::prime_count(int n) {
    if (n < 2)
        return 0;
    int a = prime_count(static_cast<int>(std::sqrt(n)));
    return phi(n, a) + a - 1;
}

int legendre_prime_counter::phi(int x, int a) {
    if (a == 0)
        return x;
    if (a == 1)
        return x - (x >> 1);
    int pa = primes[a - 1];
    if (x <= pa)
        return 1;
    return phi(x, a - 1) - phi(x / pa, a - 1);
}

int main() {
    legendre_prime_counter counter(1000000000);
    for (int i = 0, n = 1; i < 10; ++i, n *= 10)
        std::cout << "10^" << i << "\t" << counter.prime_count(n) << '\n';
}