Bash Count Semi Primes
count_semi_primes() {
local _n=$1
local -n _pArr="$2"
local -n _qArr="$3"
local -n _outArr="$4"
local -a _is_prime _semi _cum
local _i _k _idx
for ((_i = 0; _i <= _n; _i++)); do _is_prime[_i]=1; _semi[_i]=0; done
for ((_i = 2; _i * _i <= _n; _i++)); do
if (( _is_prime[_i] )); then
for ((_k = _i * _i; _k <= _n; _k += _i)); do
_is_prime[_k]=0
done
fi
done
for ((_k = 2; _k * _k <= _n; _k++)); do
if (( _is_prime[_k] )); then
for ((_i = 2; _i * _k <= _n; _i++)); do
if (( _is_prime[_i] )); then
_semi[_k * _i]=1
fi
done
fi
done
_cum[0]=${_semi[0]}
for ((_i = 1; _i <= _n; _i++)); do
_cum[_i]=$(( _cum[_i-1] + _semi[_i] ))
done
_outArr=()
for _idx in "${!_pArr[@]}"; do
local _lo=${_pArr[$_idx]}
local _hi=${_qArr[$_idx]}
_outArr[_idx]=$(( _cum[_hi] - _cum[_lo-1] ))
done
}
This precomputes semiprimes and prefix sums so each range query becomes a quick subtraction.