Legendre prime counting function: Difference between revisions
Content added Content deleted
(Added C) |
GordonBGood (talk | contribs) (→{{header|Vlang}}: correction to increase precision to extend range...) |
||
Line 3,099: | Line 3,099: | ||
[inline] |
[inline] |
||
fn half(n |
fn half(n u64) i64 { return i64((n - 1) >>> 1) } // convenience function! |
||
[inline] // floating point divide faster than integer divide! |
[inline] // floating point divide faster than integer divide! |
||
fn divide(nm u64, d u64) |
fn divide(nm u64, d u64) u64 { return u64(f64(nm) / f64(d)) } |
||
[direct_array_access] |
[direct_array_access] |
||
fn count_primes_to(n u64) i64 { |
fn count_primes_to(n u64) i64 { |
||
if n < u64(3) { return if n < i64(2) { i64(0) } else { i64(1) } } |
if n < u64(3) { return if n < i64(2) { i64(0) } else { i64(1) } } |
||
rtlmt := |
rtlmt := u64(sqrt(f64(n))) |
||
mxndx := (rtlmt - 1) / 2 |
mxndx := i64((rtlmt - 1) / 2) |
||
arrlen := mxndx + 1 |
arrlen := int(mxndx + 1) |
||
mut smalls := []u32{ len: arrlen, cap: arrlen, init: u32(it) } |
mut smalls := []u32{ len: arrlen, cap: arrlen, init: u32(it) } |
||
mut roughs := []u32{ len: arrlen, cap: arrlen, init: u32(it + it + 1) } |
mut roughs := []u32{ len: arrlen, cap: arrlen, init: u32(it + it + 1) } |
||
mut larges := []i64{ len: arrlen, cap: arrlen, |
mut larges := []i64{ len: arrlen, cap: arrlen, |
||
init: i64(((n / u64(it + it + 1) - 1) / 2)) } |
init: i64(((n / u64(it + it + 1) - 1) / 2)) } |
||
cullbuflen := (mxndx + 8) / 8 |
cullbuflen := int((mxndx + 8) / 8) |
||
mut cullbuf := []u8{len: cullbuflen, cap: cullbuflen, init: u8(0)} |
mut cullbuf := []u8{len: cullbuflen, cap: cullbuflen, init: u8(0)} |
||
mut nbps := 0 // do partial sieving for each odd base prime to quad root... |
mut nbps := i64(0) // do partial sieving for each odd base prime to quad root... |
||
mut rilmt := arrlen // number of roughs start with full size! |
mut rilmt := arrlen // number of roughs start with full size! |
||
for i := 1; ; i++ { // start with 3; breaks when partial sieving done... |
for i := i64(1); ; i++ { // start with 3; breaks when partial sieving done... |
||
sqri := (i + i) * (i + 1) |
sqri := (i + i) * (i + 1) |
||
if sqri > mxndx { break } // breaks here! |
if sqri > mxndx { break } // breaks here! |
||
if (cullbuf[i >> 3] & masks[i & 7]) != u8(0) { continue } // not prime! |
if (cullbuf[i >>> 3] & masks[i & 7]) != u8(0) { continue } // not prime! |
||
cullbuf[i >> 3] |= masks[i & 7] // cull bp rep! |
cullbuf[i >>> 3] |= masks[i & 7] // cull bp rep! |
||
bp := i + i + 1 // partial sieve by bp... |
bp := u64(i + i + 1) // partial sieve by bp... |
||
for c := sqri; c < arrlen; c += bp { cullbuf[c >> 3] |= masks[c & 7] } |
for c := sqri; c < arrlen; c += i64(bp) { cullbuf[c >>> 3] |= masks[c & 7] } |
||
mut nri := 0 // transfer from `ori` to `nri` indexes: |
mut nri := 0 // transfer from `ori` to `nri` indexes: |
||
for ori in 0 .. rilmt { // update `roughs` and `larges` for partial sieve... |
for ori in 0 .. rilmt { // update `roughs` and `larges` for partial sieve... |
||
r := roughs[ori] |
|||
rci := i64(r >>> 1) // skip recently culled in last partial sieve... |
|||
if (cullbuf[ |
if (cullbuf[rci >>> 3] & masks[rci & 7]) != u8(0) { continue } |
||
d := |
d := u64(r) * u64(bp) |
||
larges[nri] = larges[ori] - |
larges[nri] = larges[ori] - |
||
(if d <= rtlmt { larges[ |
(if d <= rtlmt { larges[i64(smalls[d >>> 1]) - nbps] } |
||
else { i64(smalls[half(divide(n, |
else { i64(smalls[half(divide(n, d))]) }) |
||
+ |
+ nbps // adjust for over subtraction of base primes! |
||
roughs[nri] = |
roughs[nri] = r // compress for culled `larges` and `roughs`! |
||
nri++ // advance output `roughs` index! |
nri++ // advance output `roughs` index! |
||
} |
} |
||
Line 3,142: | Line 3,142: | ||
mut si := mxndx // update `smalls` for partial sieve... |
mut si := mxndx // update `smalls` for partial sieve... |
||
for pm := ((rtlmt / bp) - 1) | 1; pm >= bp; pm -= 2 { |
for pm := ((rtlmt / bp) - 1) | 1; pm >= bp; pm -= 2 { |
||
c := smalls[pm >> 1] |
c := smalls[pm >>> 1] |
||
e := (pm * bp) >> 1 |
e := (pm * bp) >>> 1 |
||
for ; si >= e; si-- { smalls[si] -= (c - u32(nbps)) } |
for ; si >= e; si-- { smalls[si] -= (c - u32(nbps)) } |
||
} |
} |
||
Line 3,159: | Line 3,159: | ||
p := u64(roughs[ri]) |
p := u64(roughs[ri]) |
||
m := n / p |
m := n / p |
||
ei := int(smalls[half( |
ei := int(smalls[half(u64(m / p))]) - nbps |
||
if ei <= ri { break } // break out when only multiple equal to `p` |
if ei <= ri { break } // break out when only multiple equal to `p` |
||
ans -= i64((ei - ri) * (nbps + ri - 1)) // adjust for over addition below! |
ans -= i64((ei - ri) * (nbps + ri - 1)) // adjust for over addition below! |
||
Line 3,189: | Line 3,189: | ||
This took 2 milliseconds.</pre> |
This took 2 milliseconds.</pre> |
||
The above code is about as fast as the same algorithm in the fastest of languages such as C/C++/Nim due to the greatly reduced computational complexity of O(n**(3/4)/((log n)**2)); as shown it is run on an Intel i5-6500 (3.6 GHz single-thread boosted). The above code can |
The above code is about as fast as the same algorithm in the fastest of languages such as C/C++/Nim due to the greatly reduced computational complexity of O(n**(3/4)/((log n)**2)); it can compute the number of primes to 1e11 in about 22 milliseconds on the same machine as shown where it is run on an Intel i5-6500 (3.6 GHz single-thread boosted). The above code can compute the number of primes to 1e16 in about a minute, although there is a precision/accuracy problem for counting ranges above about 9e15 due to the speed-up optimization of using floating point division operations (precise only to 53-bits, which is about this limit). |
||
=={{header|Wren}}== |
=={{header|Wren}}== |