Data update

This commit is contained in:
Ingy döt Net 2026-04-30 12:34:36 -04:00
parent 4bb20c9b71
commit cbaf4c4b64
12390 changed files with 318560 additions and 27248 deletions

View file

@ -0,0 +1,36 @@
BEGIN # Legendre prime counting function - translation of EasyLang/Go non-memoised version #
PR read "primes.incl.a68" PR # include RC prime utilities #
OP PI = ( INT n )INT:
IF n < 2 THEN 0
ELIF n = 2 THEN 1
ELSE
INT root n = ENTIER sqrt( n );
[]INT primes = EXTRACTPRIMESUPTO root n FROMPRIMESIEVE PRIMESIEVE root n;
INT prime count = UPB primes;
PROC phi = ( INT x, a in )INT:
BEGIN
INT a := a in, sum := 0;
BOOL continue := TRUE;
WHILE a > 1 AND continue DO
INT pa = primes[ a ];
IF x <= pa THEN
continue := FALSE
ELSE
a -:= 1;
sum +:= phi( x OVER pa, a )
FI
OD;
IF continue THEN x - ( x OVER 2 ) - sum ELSE 1 FI
END;
phi( n, prime count ) + prime count - 1
FI;
FOR i FROM 0 TO 9 DO
INT n = 10 ^ i;
print( ( "10^", whole( i, 0 ), " ", whole( PI n, 0 ), newline ) )
OD
END

View file

@ -0,0 +1,62 @@
scope # Legendre prime counting function - translation of EasyLang/Go non-memoised version
# generate and return a register containing the primes up to sieveSize
local proc primeSieve( sieveSize :: number ) :: register
local sieve; create register sieve( sieveSize ); # "vector" to be sieved
sieve[ 1 ] := false;
for sPos from 2 to sieveSize do sieve[ sPos ] := true od;
# sieve the primes
for sPos from 2 to entier( sqrt( sieveSize ) ) do
if sieve[ sPos ] then
for p from sPos * sPos to sieveSize by sPos do
sieve[ p ] := false
od
fi
od;
return sieve
end;
# construct a sieve of primes up to the maximum we will need
local constant psRoot1e9 := primeSieve( sqrt 1e9 );
# returns a sequence of primes extracted from a prime sieve
local proc primesUpTo( n :: number, sieve :: register ) :: sequence
local result := seq(); # sequence of primes - initially empty
for sPos from 1 to n do
if sieve[ sPos ] then insert sPos into result fi
od;
return result
end;
local proc pix( n :: integer ) :: integer
local result := 0;
if n = 2 then result := 1
elif n > 2 then
local constant rootN := entier sqrt n;
local constant primes := primesUpTo( rootN, psRoot1e9 );
local constant primeCount := size primes;
local proc phi( x :: integer, aIn :: integer ) :: integer
local a, sum, found1 := aIn, 0, false;
while a > 1 and not found1 do
local constant pa := primes[ a ];
if x <= pa then
found1 := true
else
a -:= 1;
sum +:= phi( x \ pa, a )
fi
od;
return if found1 then 1 else x - ( x \ 2 ) - sum fi
end;
result := phi( n, primeCount ) + primeCount - 1
fi;
return result
end;
for i from 0 to 9 do
local n := 10 ^ i;
printf( "10^%d %d\n", i, pix( n ) )
od
epocs

View file

@ -0,0 +1,60 @@
// compile with --fast for maximum speed...
use Time;
proc countPrimes(lmt: uint(64)): int(64) {
if lmt < 9 { // when there are no odd primes less than square root...
if lmt < 3 { if lmt < 2 { return 0; } else { return 1; } }
return (lmt - (lmt >> 1)): int(64);
}
// Chapel doesn't have closures, so emulate them with a class...
class LegendrePi {
var n: uint(64);
var dom: domain(1);
var oprms: [dom] uint(32);
proc init(n: uint(64)) {
// first, an array of odd primes to the square root of n is generated...
this.n = n;
const sqrtn = sqrt(n: real(64)): int(64);
const rtlmt = (sqrtn - 3) / 2; this.dom = {0 .. rtlmt};
this.oprms = 0;
for i in 0 .. rtlmt do this.oprms[i] = (i + i + 3): uint(32);
var i = 0;
for i in (0 ..) { // cull the array
var ci = (i + i) * (i + 3) + 3; if ci > rtlmt { break; }
const bp = i + i + 3;
while (ci <= rtlmt) { this.oprms[ci] = 0; ci += bp; }
}
var psz = 0;
for ti in 0 .. rtlmt { // compress the odd primes array...
const tv = this.oprms[ti];
if tv != 0 { this.oprms[psz] = tv; psz += 1; }
}
this.dom = { 0 ..< psz };
}
proc phi(x: uint(64), a: int): int(64) {
if a <= 0 { return (x - (x >> 1)): int(64); } // take care of prime of 2
const na = a - 1; const p = this.oprms[na]: uint(64);
if x <= p { return 1: int(64); }
return phi(x, na) - phi(x / p, na);
}
proc this(): int(64) {
return phi(n, this.oprms.size) + this.oprms.size: int(64);
}
}
return (new LegendrePi(lmt))();
}
proc main() {
var timer: Timer;
timer.start();
for i in 0 .. 9 {
writeln("π(10**", i, ") = ", countPrimesx(10: uint(64) ** i));
}
timer.stop();
writeln("This took ", timer.elapsed(TimeUnits.milliseconds), " milliseconds.");
}

View file

@ -0,0 +1,78 @@
// tiny Phi Look Up for `a` of small degree...
const tinyPhiPrimes = [ 2, 3, 5, 7, 11, 13 ]; // degree six
const cC = tinyPhiPrimes.size - 1;
proc product(a: [] int): int {
var acc = 1; for v in a { acc *= v; }; return acc >> 1; }
const tinyPhiOddCirc = product(tinyPhiPrimes);
proc tot(a: [] int): int {
var acc = 1; for v in a { acc *= v - 1; }; return acc; }
const tinyPhiOddTot = tot(tinyPhiPrimes);
proc makeTinyLUT(ps: [] int, sz: int): [] uint(32) {
var arr: [0 .. sz - 1] uint(32) = 1;
for p in ps {
if p <= 2 { continue; }
arr[p >> 1] = 0;
for c in ((p * p) >> 1) ..< sz by p { arr[c] = 0; }
}
var acc = 0: uint(32);
for i in 0 ..< sz { acc += arr[i]; arr[i] = acc; }
return arr;
}
const tinyPhiLUT = makeTinyLUT(tinyPhiPrimes, tinyPhiOddCirc);
inline proc tinyPhi(x: uint(64)): int(64) {
const ndx = (x - 1) >> 1; const numtot = ndx / tinyPhiOddCirc: uint(64);
return (numtot * tinyPhiOddTot +
tinyPhiLUT[(ndx - numtot * tinyPhiOddCirc): int]): int(64);
}
proc countPrimes(lmt: uint(64)): int(64) {
if lmt < 169 { // below 169 whose sqrt is 13 is where TinyPhi doesn't work...
if lmt < 3 { if lmt < 2 { return 0; } else { return 1; } }
// adjust for the missing "degree" base primes
if lmt <= 13 {
return ((lmt - 1): int(64) >> 1) + (if (lmt < 9) then 1 else 0); }
return 5 + tinyPhiLUT[(lmt - 1): int >> 1]: int(64);
}
// Chapel doesn't have closures, so emulate them with a class...
class LegendrePi {
var n: uint(64);
var dom: domain(1);
var oprms: [dom] uint(32);
proc init(n: uint(64)) {
// first, an array of odd primes to the square root of n is generated...
this.n = n;
const sqrtn = sqrt(n: real(64)): int(64);
const rtlmt = (sqrtn - 3) / 2; this.dom = {0 .. rtlmt};
this.oprms = 0;
for i in 0 .. rtlmt do this.oprms[i] = (i + i + 3): uint(32);
var i = 0;
for i in (0 ..) { // cull the array
var ci = (i + i) * (i + 3) + 3; if ci > rtlmt { break; }
const bp = i + i + 3;
while (ci <= rtlmt) { this.oprms[ci] = 0; ci += bp; }
}
var psz = 0;
for ti in 0 .. rtlmt { // compress the odd primes array...
const tv = this.oprms[ti];
if tv != 0 { this.oprms[psz] = tv; psz += 1; }
}
this.dom = { 0 ..< psz };
}
proc lvl(pilmt: int, m: uint(64)): int(64) {
var acc = 0: int(64);
for pi in cC ..< pilmt {
const p = this.oprms[pi]: uint(64); const nm = m * p;
if this.n <= nm * p { return acc + (pilmt - pi); }
if pi > cC { acc -= this.lvl(pi, nm); }
const q = this.n / nm; acc += tinyPhi(q);
}
return acc;
}
proc this(): int(64) {
return tinyPhi(this.n) - this.lvl(this.oprms.size, 1)
+ this.oprms.size: int(64);
}
}
return (new LegendrePi(lmt))();
}

View file

@ -0,0 +1,66 @@
const masks = for i in 0 .. 7 do (1 << i): uint(8); // faster bit twiddling
proc countPrimes(lmt: uint(64)): int(64) {
if lmt < 3 { if lmt < 2 { return 0; } else { return 1; } } // odds only!
inline proc half(x: int): int { return (x - 1) >> 1; } // convenience function
inline proc divide(nm: uint(64), d: uint(64)): int {
return (nm: real(64) / d: real(64)): int; } // floating point div faster
const sqrtn = sqrt(lmt: real(64)): uint(64);
const mxndx = (sqrtn - 1): int / 2;
const dom = {0 .. mxndx}; const csz = (mxndx + 8) / 8;
var smalls = for i in dom do i: uint(32);
var roughs = for i in dom do (i + i + 1): uint(32);
var larges = for i in dom do ((lmt / (i + i + 1)) - 1) >> 1;
var cullbuf: [0 ..< csz] uint(8);
// partial sieve loop, adjusting larges/smalls, compressing larges/roughs...
var nobps = 0; var rilmt = mxndx;
for bp in 3: uint(64) .. by 2 {
const i = (bp >> 1): int; const sqri = (i + i) * (i + 1);
if sqri > mxndx { break; } // up to quad root of counting range
if (cullbuf[i >> 3] & masks[i & 7]) != 0 { continue; } // loop not prime
cullbuf[i >> 3] |= masks[i & 7]; // cull bp itself as not a rough
for ci in sqri .. mxndx by bp { // do partial sieving pass for `bp`...
cullbuf[ci >> 3] |= masks[ci & 7]; } // cull all multiples of `bp`
// now adjust `larges` for latest partial sieve pass...
var ori = 0; // compress input rough index to output one
for iri in 0 .. rilmt {
const r = roughs[iri]: uint(64); const rci = (r >> 1): int;
if (cullbuf[rci >> 3] & masks[rci & 7]) != 0 {
continue; } // skip culled roughs in last partial sieving pass
const d = bp: uint(64) * r;
larges[ori] = larges[iri] -
(if d <= sqrtn then
larges[smalls[(d >> 1): int] - nobps]
else smalls[half(divide(lmt, d))]: uint(64)) + nobps;
roughs[ori] = r: uint(32); ori += 1;
}
var si = mxndx; // and adjust `smalls` for latest partial sieve pass...
for bpm in bp .. (sqrtn / bp - 1) | 1 by -2 {
const c = smalls[(bpm >> 1): int] - nobps: uint(32);
const e = ((bpm * bp) >> 1): int;
while si >= e { smalls[si] -= c; si -= 1; }
}
nobps += 1; rilmt = ori - 1;
}
var ans = larges[0]; // answer from larges, adjusting for over subtraction...
for i in 1 .. rilmt { ans -= larges[i]; } // combine!
ans += (rilmt + 1 + 2 * (nobps - 1)) * rilmt / 2; // adjust!
// add final adjustment for pairs of current roughs to cube root of range...
for ri in (1 ..) { // break when reaches cube root of counting range...
const p = roughs[ri]: uint(64); const q = lmt / p;
const ei = smalls[half(divide(q, p))]: int - nobps;
if ei <= ri { break; } // break here when no more pairs!
for ori in ri + 1 .. ei { // for all pairs never the same prime!
ans += smalls[half(divide(q, roughs[ori]))]: int(64); }
// adjust for over subtractions above...
ans -= (ei - ri): uint(64) * (nobps: uint(64) + ri: uint(64) - 1);
}
return ans: int(64) + 1; // add one for only even prime of two!
}

View file

@ -0,0 +1,34 @@
global primes[] .
proc mkprimes n .
len sieve[] n
max = sqrt n
for d = 2 to max : if sieve[d] = 0
for i = d * d step d to n
sieve[i] = 1
.
.
primes[] = [ ]
for i = 2 to n
if sieve[i] = 0 : primes[] &= i
.
.
fastfunc phi x a .
while a > 1
pa = primes[a]
if x <= pa : return 1
sum += phi (x div pa) (a - 1)
a -= 1
.
return x - (x div 2) - sum
.
func pix n .
if n < 2 : return 0
if n = 2 : return 1
mkprimes floor sqrt n
a = len primes[]
return phi n a + a - 1
.
for i = 0 to 9
n = pow 10 i
print "10^" & i & " " & pix n
.

View file

@ -0,0 +1,63 @@
(do ;;; Legendre prime counting function - translation of EasyLang
; generate and return a table containing the primes up to sieve-size
(fn prime-sieve [sieve-size]
(var sieve {})
(tset sieve 1 false)
(for [s-pos 2 sieve-size] (tset sieve s-pos true))
(for [s-pos 2 (math.floor (math.sqrt sieve-size))]
(when (. sieve s-pos)
(for [p (* s-pos s-pos) sieve-size s-pos] (tset sieve p false))
)
)
sieve
)
; construct a sieve of primes up to the maximum we will need
(var ps-root-1e9 (prime-sieve (math.sqrt 1e9)))
; returns a table of primes extracted from a prime sieve
(fn primes-up-to [n sieve]
(local result {})
(for [s-pos 1 n]
(when (. sieve s-pos) (table.insert result s-pos))
)
result
)
(fn legendre-pi [n]
(if (< n 2) 0
(= n 2) 1
;else
(do (local root-n (math.floor (math.sqrt n)))
(local primes (primes-up-to root-n ps-root-1e9))
(local prime-count (length primes))
(fn phi [x a-in]
(var (a sum found-1) (values a-in 0 false))
(while (and (> a 1) (not found-1))
(local pa (. primes a))
(if (<= x pa)
(set found-1 true)
;else
(do (set a (- a 1))
(set sum (+ sum (phi (// x pa) a)))
)
)
)
(if found-1
1
;else
(- x (// x 2 ) sum)
)
)
(- (+ (phi n prime-count) prime-count) 1)
)
)
)
(for [i 0 9]
(print (string.format "10^%d %d" i (legendre-pi (^ 10 i))))
)
)

View file

@ -0,0 +1,62 @@
do -- Legendre prime counting function - translation of EasyLang
-- generate and return a table containing the primes up to sieveSize
local function primeSieve( sieveSize )
local sieve = {}
sieve[ 1 ] = false
for sPos = 2, sieveSize do sieve[ sPos ] = true end
-- sieve the primes
for sPos = 2, math.floor( math.sqrt( sieveSize ) ) do
if sieve[ sPos ] then
for p = sPos * sPos, sieveSize, sPos do
sieve[ p ] = false
end
end
end
return sieve
end
-- construct a sieve of primes up to the maximum we will need
local psRoot1e9 = primeSieve( math.sqrt( 1e9 ) )
-- returns a table of primes extracted from a prime sieve
local function primesUpTo( n, sieve )
local result = {}
for sPos = 1, n do
if sieve[ sPos ] then table.insert( result, sPos ) end
end
return result
end
local function pi( n )
local result = 0
if n == 2 then result = 1
elseif n > 2 then
local rootN = math.floor( math.sqrt( n ) )
local primes = primesUpTo( rootN, psRoot1e9 )
local primeCount = # primes
local function phi( x, aIn )
local a, sum, found1 = aIn, 0, false
while a > 1 and not found1 do
local pa = primes[ a ]
if x <= pa then
found1 = true
else
a = a - 1
sum = sum + phi( x // pa, a )
end
end
return found1 and 1 or x - ( x // 2 ) - sum
end
result = phi( n, primeCount ) + primeCount - 1
end
return result
end
for i = 0, 9 do
local n = math.floor( 10 ^ i )
print( "10^"..i.." "..pi( n ) )
end
end

View file

@ -0,0 +1,56 @@
MODULE LegendrePi; (* Legendre prime counting function *)
(* - translation of EasyLang/Go non-memoised version *)
IMPORT Primes, Math, Out;
CONST maxPrime = 32000; (* somewhat more than sqrt( 1e9 ) *)
VAR primeSieve : ARRAY maxPrime OF BOOLEAN;
primeList : ARRAY maxPrime OF INTEGER;
PROCEDURE pi( n : INTEGER ) : INTEGER;
VAR rootN, result : INTEGER;
PROCEDURE phi( x, aIn : INTEGER; primes : ARRAY OF INTEGER ) : INTEGER;
VAR a, sum, pa, count : INTEGER;
found1 : BOOLEAN;
BEGIN
a := aIn;
sum := 0;
found1 := FALSE;
WHILE ( a > 1 ) & ~ found1 DO
pa := primes[ a ];
IF x <= pa THEN
found1 := TRUE
ELSE
DEC( a );
INC( sum, phi( x DIV pa, a, primes ) )
END
END;
IF found1 THEN count := 1 ELSE count := x - ( x DIV 2 ) - sum END
RETURN count
END phi;
BEGIN
IF n < 2 THEN result := 0
ELSIF n = 2 THEN result := 1
ELSE
rootN := FLOOR( Math.sqrt( FLT( n ) ) );
Primes.extractUpTo( rootN, primeList, primeSieve );
result := phi( n, primeList[ 0 ], primeList ) + primeList[ 0 ] - 1
END
RETURN result
END pi;
PROCEDURE showPiForPowersOfTen;
VAR i, n : INTEGER;
BEGIN
n := 1;
FOR i := 0 TO 9 DO
Out.String( "10^" );Out.Int( i, 0 );Out.String( " " );Out.Int( pi( n ), 0 );Out.Ln;
n := n * 10
END
END showPiForPowersOfTen;
BEGIN
Primes.sieve( primeSieve );
showPiForPowersOfTen
END LegendrePi.

View file

@ -0,0 +1,36 @@
do -- Legendre prime counting function - translation of EasyLang/Go non-memoised version
local int = require( "int" ) -- RC Pluto integer library, inc. prime utilities
local function pi( n : number ) : number
local result = 0
if n == 2 then result = 1
elseif n > 2 then
local rootN = math.floor( math.sqrt( n ) )
local primes = int.primes( rootN )
local pCount = # primes
local function phi( x : number, aIn : number ) : number
local a, sum, found1 = aIn, 0, false
while a > 1 and not found1 do
local pa = primes[ a ]
if x <= pa then
found1 = true
else
a -= 1
sum += phi( x // pa, a )
end
end
return if found1 then 1 else x - ( x // 2 ) - sum end
end
result = phi( n, pCount ) + pCount - 1
end
return result
end
for i = 0, 9 do
local n = math.floor( 10 ^ i )
print( $"10^{i} {pi( n )}" )
end
end

View file

@ -0,0 +1,30 @@
from bitarray.util import gen_primes
from math import isqrt
from functools import cache
from time import perf_counter
def countPrimes(limit):
if limit < 2: return 0
rtlmtsz = isqrt(limit) + 1
sieve = gen_primes(rtlmtsz)
baseprms = [ pi for pi in range(rtlmtsz) if sieve[pi] ]
nbps = len(baseprms)
@cache
def phi(x, a): # termination condition means x and a can never be zero
rslt = x
for na in range(a - 1, -1, -1): # loop takes care of a zero termination!
pna = baseprms[na]
if pna * pna > x: rslt -= 1; continue # termination before x is zero
if na: rslt -= phi(x // pna, na) # lessening recursion depth
else: rslt -= x // pna
return rslt
return phi(limit, nbps) + nbps - 1
start = perf_counter()
for exp in range(10):
print(f'10**{exp}: ', countPrimes(10**exp))
stop = perf_counter()
print(f"This took {(stop - start) * 1000:.0f} milliseconds.")

View file

@ -0,0 +1,96 @@
from math import isqrt
from time import perf_counter
# numops = 0 # FOR TELEMETRY!!!!!
def countPrimes(limit):
# global numops; numops = 0 # FOR TELEMETRY!!!!!
# can't odd sieve for limit less than 3
if limit < 3: return (0 if limit < 2 else 1)
# `>> ` is used throughout for `// 2` for efficiency...
# INITIALIZATION...
rtlmt = isqrt(limit); rtlmtsz = (rtlmt + 1) // 2
# note that roughs list starts at (and keeps) one to match the algorithm
# though one is not a prime, but it is important in computation of pi and
# that the roughs and pis lists are processed in sync...
# roughs list of numbers culled of multiples of two here...
roughs = [ i + i + 1 for i in range(rtlmtsz) ] # odds only; now two multiples!
# phis for current roughs, thus init'ed to phip2 of each rough's pi;
# these are the "stack" values for a recursive solution...
phis = [ (limit // r + 1) // 2 for r in roughs ] # plus 1 for phi form!
# List used to reference the "compressed" index of the pis list...
phindxs = [ i for i in range(rtlmtsz) ] # plus one to get phis!
# MAIN PARTIAL SIEVING LOOP...
numbps = 0; rsz = rtlmtsz; bp = roughs[1] # starts with bp of 3
while bp * bp <= rtlmt:
# mark all roughs culled in this base prime partial sieving pass...
roughs[1] = 0 # make phi by eliminating bp as well!
for cp in range(bp * bp, rtlmt, bp + bp): # cull points
cpi = phindxs[cp >> 1]
if roughs[cpi] == cp: roughs[cpi] = 0 # only if not alreay eliminated
# MAIN INNER PROCESSING-SPLITTING LOOP...
roi = 0
for rii in range(rsz):
m = roughs[rii]
if not m: continue # skip marked!
mbp = m * bp # odd product due to all roughs are odd!
# crutial pis list updating based on size of `qbp` whether
# less than or equal to or above `rtlmt`...
# if mbp > rtlmt: numops += 1 # FOR TELEMETRY!!!!!
phis[roi] = phis[rii] - \
( phis[phindxs[mbp >> 1]] if mbp <= rtlmt
# add one to make it phi form!...
else phindxs[(limit // mbp - 1) >> 1] + 1 )
roughs[roi] = m; roi += 1
# update phindxs list to reflect new state of roughs; the only remaining
# valid phindx values are those corresponding to current roughs...
maxndxsz = rtlmtsz
for ri in range(roi - 1, 0, -1):
strti = roughs[ri] >> 1
phindxs[strti:maxndxsz] = [ri] * (maxndxsz - strti); maxndxsz = strti
bp = roughs[1]; rsz = roi; numbps += 1
phi = phis[0] - sum(phis[1:rsz]) # accumulate result from pis
# CALCULATION OF CONTRIBUTION DUE TO LARGE UNIQUE PRIME PAIRS...
# All roughs values above one are now odd primes and above limit**(1/4) and
# thus all products of unique pairs of these primes are odd and need to be
# added (evens add; odds subtract - inclusion/exclusion principle)
# as phi's to the result...
phi += (rsz - 2) * (rsz - 1) // 2 # add all the "one"'s pairs calc may need!
for p1i in range(1, rsz - 1):
p1 = roughs[p1i]; qp1 = limit // p1
endndx = phindxs[(qp1 // p1 - 1) >> 1]
if endndx <= p1i: break
for p2i in range(p1i + 1, endndx + 1):
# numops += 1 # FOR TELEMETRY!!!!!
phi += phindxs[(qp1 // roughs[p2i] - 1) >> 1]
phi -= (endndx - p1i) * (p1i - 1) # efficient to remove what's not needed!
numrtprms = numbps + rsz; return phi + numrtprms - 1
# USAGE...
for i in range(10): print(f"π(10**{i}) = {countPrimes(10**i):,}")
count = countPrimes(limit := 100_000_000_000) # get CPU up to speed!
start = perf_counter()
count = countPrimes(limit := 100_000_000_000)
stop = perf_counter()
# print(f"number of operations: {numops:,}") # RESULT OF TELEMETRY!!!!!
print(f"\r\nFound {count:,} primes up to {limit:,}")
print(f"The above calculation took {stop - start:.3f} seconds.")

View file

@ -1,4 +1,4 @@
-- 23 Aug 2025
-- 21 Feb 2026
include Setting
say 'LEGENDRE PRIME COUNTER (NO MEMOIZATION)'
@ -13,7 +13,7 @@ end
exit
Pie:
procedure expose prim.
procedure expose Prim. Memo.
arg xx
if xx < 3 then
return 0+(xx=2)
@ -21,13 +21,14 @@ n = Primes(Isqrt(xx))
return Phi(xx,n)+n-1
Phi:
procedure expose prim.
procedure expose Prim.
arg xx,yy
if yy < 2 then
return xx-(xx%2)*(yy=1)
p = prim.yy
p = Prim.yy
if xx <= p then
return 1
return Phi(xx,yy-1)-Phi(xx%p,yy-1)
-- Primes; Isqrt
include Math

View file

@ -1,4 +1,4 @@
-- 23 Aug 2025
-- 21 Feb 2026
include Setting
say 'LEGENDRE PRIME COUNTER (WITH MEMOIZATION)'
@ -13,25 +13,26 @@ end
exit
Pie:
procedure expose prim. work.
procedure expose Prim. Work. Memo.
arg xx
if xx < 3 then
return 0+(xx=2)
n = Primes(Isqrt(xx))
work. = 0
Work. = 0
return Phi(xx,n)+n-1
Phi:
procedure expose prim. work.
procedure expose Prim. Work.
arg xx,yy
if yy < 2 then
return xx-(xx%2)*(yy=1)
p = prim.yy
p = Prim.yy
if xx <= p then
return 1
if work.xx.yy > 0 then
return work.xx.yy
work.xx.yy = Phi(xx,yy-1)-Phi(xx%p,yy-1)
return work.xx.yy
if Work.xx.yy > 0 then
return Work.xx.yy
Work.xx.yy = Phi(xx,yy-1)-Phi(xx%p,yy-1)
return Work.xx.yy
-- Primes; Isqrt
include Math

View file

@ -1,4 +1,4 @@
-- 23 Aug 2025
-- 21 Feb 2026
include Setting
say 'LEGENDRE PRIME COUNTER (SIEVING)'
@ -12,4 +12,5 @@ do n = 0 to 8
end
exit
-- Primes
include Math

View file

@ -0,0 +1,82 @@
// can compile with: v -cflags -march=native -cflags -O3 -prod MagicCount.v
import time
import math { sqrt }
const masks = [ u8(1), 2, 4, 8, 16, 32, 64, 128 ] // faster than bit twiddling!
@[inline]
fn half(n u64) i64 { return i64((n - 1) >>> 1) } // convenience function!
@[inline] // floating point divide faster than integer divide!
fn divide(nm u64, d u64) u64 { return u64(f64(nm) / f64(d)) }
@[direct_array_access]
fn count_primes_to(n u64) i64 {
if n < u64(9) { return if n < i64(2) { i64(0) } else { i64((n + 1) / 2) } }
rtlmt := u64(sqrt(f64(n)))
mxndx := i64((rtlmt - 1) / 2)
arrlen := int(mxndx + 1)
mut smalls := []u32{ len: arrlen, cap: arrlen, init: u32(index) }
mut roughs := []u32{ len: arrlen, cap: arrlen, init: u32(index + index + 1) }
mut larges := []i64{ len: arrlen, cap: arrlen,
init: i64(((n / u64(index + index + 1) - 1) / 2)) }
cullbuflen := int((mxndx + 8) / 8)
mut cullbuf := []u8{len: cullbuflen, cap: cullbuflen, init: u8(0)}
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!
// start with 3; breaks when partial sieving done...
for i := i64(1); ; i++ {
sqri := (i + i) * (i + 1)
if sqri > mxndx { break } // breaks here!
if (cullbuf[i >>> 3] & masks[i & 7]) != u8(0) { continue } // not prime!
cullbuf[i >>> 3] |= masks[i & 7] // cull bp rep!
bp := u64(i + i + 1) // partial sieve by bp...
for c := sqri; c < arrlen; c += i64(bp) { cullbuf[c >>> 3] |= masks[c & 7] }
mut nri := 0 // transfer from `ori` to `nri` indexes:
// update `roughs` and `larges` for partial sieve...
for ori in 0 .. rilmt {
r := roughs[ori]
rci := i64(r >>> 1) // skip recently culled in last partial sieve...
if (cullbuf[rci >>> 3] & masks[rci & 7]) != u8(0) { continue }
d := u64(r) * u64(bp)
larges[nri] = larges[ori] -
(if d <= rtlmt { larges[i64(smalls[d >>> 1]) - nbps] }
else { i64(smalls[half(divide(n, d))]) })
+ nbps // adjust for over subtraction of base primes!
roughs[nri] = r // compress for culled `larges` and `roughs`!
nri++ // advance output `roughs` index!
}
mut si := mxndx // update `smalls` for partial sieve...
for pm := ((rtlmt / bp) - 1) | 1; pm >= bp; pm -= 2 {
c := smalls[pm >>> 1]
e := (pm * bp) >>> 1
for ; si >= e; si-- { smalls[si] -= (c - u32(nbps)) }
}
rilmt = nri // new rough size limit!
nbps++ // for one partial sieve base prime pass!
}
// combine results so far; adjust for over subtraction of base prime count...
mut ans := larges[0] + i64(((rilmt + 2 * (nbps - 1)) * (rilmt - 1) / 2))
for ri in 1 .. rilmt { ans -= larges[ri] } // combine results so far!
// add quotient for product of pairs of primes, quad root to cube root...
// break controlled below
for ri := 1; ; ri++ {
p := u64(roughs[ri])
m := n / p
ei := int(smalls[half(u64(m / p))]) - nbps
if ei <= ri { break } // break out when only multiple equal to `p`
ans -= i64((ei - ri) * (nbps + ri - 1)) // adjust for over addition below!
// add for products of 1st and 2nd primes...
for sri in ri + 1 .. ei + 1 {
ans += i64(smalls[half(divide(m, u64(roughs[sri])))]) }
}
return ans + 1 // add one for only even prime of two!
}
start_time := time.now()
mut pow := u64(1)
for i in 0 .. 10 {
println("π(10**$i) = ${count_primes_to(pow)}")
pow *= 10 }
duration := (time.now() - start_time).milliseconds()
println("This took $duration milliseconds.")