Erlang Count Semi Primes
-module(count_semi_primes).
-export([count_semi_primes/3]).
count_semi_primes(N, P, Q) ->
IsPrime = sieve(N),
Flags = mark_semiprimes(N, IsPrime),
Prefix = prefix_cumulative(N, Flags),
[array:get(Qi, Prefix) - array:get(Pi - 1, Prefix) || {Pi, Qi} <- lists:zip(P, Q)].
sieve(N) ->
Arr0 = array:new(N + 1, {default, true}),
Arr1 = array:set(0, false, Arr0),
Arr2 = case N >= 1 of
true -> array:set(1, false, Arr1);
false -> Arr1
end,
sieve(2, N, Arr2).
sieve(I, N, Arr) when I * I > N ->
Arr;
sieve(I, N, Arr) ->
Arr1 = case array:get(I, Arr) of
true -> mark_multiples(I * I, I, N, Arr);
false -> Arr
end,
sieve(I + 1, N, Arr1).
mark_multiples(K, _Step, N, Arr) when K > N ->
Arr;
mark_multiples(K, Step, N, Arr) ->
mark_multiples(K + Step, Step, N, array:set(K, false, Arr)).
mark_semiprimes(N, IsPrime) ->
Flags0 = array:new(N + 1, {default, 0}),
mark_k(2, N, IsPrime, Flags0).
mark_k(K, N, _IsPrime, Flags) when K * K > N ->
Flags;
mark_k(K, N, IsPrime, Flags) ->
Flags1 = case array:get(K, IsPrime) of
true -> mark_i(2, K, N, IsPrime, Flags);
false -> Flags
end,
mark_k(K + 1, N, IsPrime, Flags1).
mark_i(I, K, N, _IsPrime, Flags) when I * K > N ->
Flags;
mark_i(I, K, N, IsPrime, Flags) ->
Flags1 = case array:get(I, IsPrime) of
true -> array:set(K * I, 1, Flags);
false -> Flags
end,
mark_i(I + 1, K, N, IsPrime, Flags1).
prefix_cumulative(N, Flags) ->
{_, Prefix} = lists:foldl(fun(I, {Prev, Acc}) ->
Cur = Prev + array:get(I, Flags),
{Cur, array:set(I, Cur, Acc)}
end, {0, Flags}, lists:seq(1, N)),
Prefix.
This precomputes semiprimes and prefix sums so each range query becomes a quick subtraction.