निमरोड: ~ 38,667 (580,000,000 / 15,000)
यह उत्तर एक बहुत ही सरल दृष्टिकोण का उपयोग करता है। कोड एक साधारण प्राइम नंबर छलनी को नियोजित करता है जो कि प्रत्येक स्लॉट में सबसे छोटी प्राइम पॉवर को कंपोजिट नंबरों (प्राइम्स के लिए शून्य) में स्टोर करता है, फिर उसी रेंज में टोटिएंट फंक्शन के निर्माण के लिए डायनामिक प्रोग्रामिंग का उपयोग करता है, फिर नतीजे बताता है। कार्यक्रम लगभग हर समय छलनी का निर्माण करता है, फिर समय के एक अंश में कुल कार्य की गणना करता है। ऐसा लगता है कि यह एक कुशल छलनी का निर्माण करने के लिए नीचे आता है (मामूली मोड़ के साथ कि किसी को परिणाम से समग्र संख्या के लिए एक प्रमुख कारक निकालने में सक्षम होना पड़ता है और एक उचित स्तर पर स्मृति उपयोग रखना पड़ता है)।
अपडेट: मेमोरी फुटप्रिंट को कम करके और कैश व्यवहार में सुधार करके बेहतर प्रदर्शन। 5% -10% अधिक प्रदर्शन को निचोड़ना संभव है, लेकिन कोड जटिलता में वृद्धि इसके लायक नहीं है। अंततः, यह एल्गोरिथ्म मुख्य रूप से सीपीयू के वॉन न्यूमैन टोंटी का अभ्यास करता है, और बहुत कम एल्गोरिदमिक मोड़ हैं जो इसके आसपास हो सकते हैं।
C ++ कोड के सभी अनुकूलन के साथ संकलित होने का मतलब नहीं था क्योंकि किसी और ने ऐसा नहीं किया था, साथ ही प्रदर्शन विभाजक को भी अपडेट किया। :)
अपडेट 2: बेहतर मेमोरी एक्सेस के लिए ऑप्टिमाइज्ड छलनी ऑपरेशन। अब मेम्ची () (~ 5% स्पीडअप) के माध्यम से थोक में छोटे अपराधों को संभालना और बड़े primes (~ 10% स्पीडअप) को छोड़ते समय 2, 3, और 5 के गुणक को छोड़ देना।
सी ++ कोड: 9.9 सेकंड (जी ++ 4.9 के साथ)
निमरोड कोड: 9.9 सेकंड (-d: रिलीज़, gcc 4.9 बैकएंड)
proc handleSmallPrimes(sieve: var openarray[int32], m: int) =
# Small primes are handled as a special case through what is ideally
# the system's highly optimized memcpy() routine.
let k = 2*3*5*7*11*13*17
var sp = newSeq[int32](k div 2)
for i in [3,5,7,11,13,17]:
for j in countup(i, k, 2*i):
sp[j div 2] = int32(i)
for i in countup(0, sieve.high, len(sp)):
if i + len(sp) <= len(sieve):
copyMem(addr(sieve[i]), addr(sp[0]), sizeof(int32)*len(sp))
else:
copyMem(addr(sieve[i]), addr(sp[0]), sizeof(int32)*(len(sieve)-i))
# Fixing up the numbers for values that are actually prime.
for i in [3,5,7,11,13,17]:
sieve[i div 2] = 0
proc constructSieve(m: int): seq[int32] =
result = newSeq[int32](m div 2 + 1)
handleSmallPrimes(result, m)
var i = 19
# Having handled small primes, we only consider candidates for
# composite numbers that are relatively prime with 31. This cuts
# their number almost in half.
let steps = [ 1, 7, 11, 13, 17, 19, 23, 29, 31 ]
var isteps: array[8, int]
while i * i <= m:
if result[i div 2] == 0:
for j in 0..7: isteps[j] = i*(steps[j+1]-steps[j])
var k = 1 # second entry in "steps mod 30" list.
var j = 7*i
while j <= m:
result[j div 2] = int32(i)
j += isteps[k]
k = (k + 1) and 7 # "mod 30" list has eight elements.
i += 2
proc calculateAndSumTotients(sieve: var openarray[int32], n: int): int =
result = 1
for i in 2'i32..int32(n):
var tot: int32
if (i and 1) == 0:
var m = i div 2
var pp: int32 = 2
while (m and 1) == 0:
pp *= 2
m = m div 2
if m == 1:
tot = pp div 2
else:
tot = (pp div 2) * sieve[m div 2]
elif sieve[i div 2] == 0: # prime?
tot = i - 1
sieve[i div 2] = tot
else:
# find and extract the first prime power pp.
# It's relatively prime with i/pp.
var p = sieve[i div 2]
var m = i div p
var pp = p
while m mod p == 0 and m != p:
pp *= p
m = m div p
if m == p: # is i a prime power?
tot = pp*(p-1)
else:
tot = sieve[pp div 2] * sieve[m div 2]
sieve[i div 2] = tot
result += tot
proc main(n: int) =
var sieve = constructSieve(n)
let totSum = calculateAndSumTotients(sieve, n)
echo totSum
main(580_000_000)