C, 0.026119 s (12 मार्च 2016)
#include <math.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#define cache_size 16384
#define Phi_prec_max (47 * a)
#define bit(k) (1ULL << ((k) & 63))
#define word(k) sieve[(k) >> 6]
#define sbit(k) ((word(k >> 1) >> (k >> 1)) & 1)
#define ones(k) (~0ULL >> (64 - (k)))
#define m2(k) ((k + 1) / 2)
#define max(a, b) ((a) > (b) ? (a) : (b))
#define min(a, b) ((a) < (b) ? (a) : (b))
#define ns(t) (1000000000 * t.tv_sec + t.tv_nsec)
#define popcnt __builtin_popcountll
#define mask_build(i, p, o, m) mask |= m << i, i += o, i -= p * (i >= p)
#define Phi_prec_bytes ((m2(Phi_prec_max) + 1) * sizeof(int16_t))
#define Phi_prec(i, j) Phi_prec_pointer[(j) * (m2(Phi_prec_max) + 1) + (i)]
#define Phi_6_next ((i / 1155) * 480 + Phi_5[i % 1155] - Phi_5[(i + 6) / 13])
#define Phi_6_upd_1() t = Phi_6_next, i += 1, *(l++) = t
#define Phi_6_upd_2() t = Phi_6_next, i += 2, *(l++) = t, *(l++) = t
#define Phi_6_upd_3() t = Phi_6_next, i += 3, *(l++) = t, *(l++) = t, *(l++) = t
typedef unsigned __int128 uint128_t;
struct timespec then, now;
uint64_t a, primes[4648] = { 2, 3, 5, 7, 11, 13, 17, 19 }, *primes_fastdiv;
uint16_t *Phi_6, *Phi_prec_pointer;
inline uint64_t Phi_6_mod(uint64_t y)
{
if (y < 30030)
return Phi_6[m2(y)];
else
return (y / 30030) * 5760 + Phi_6[m2(y % 30030)];
}
inline uint64_t fastdiv(uint64_t dividend, uint64_t fast_divisor)
{
return ((uint128_t) dividend * fast_divisor) >> 64;
}
uint64_t Phi(uint64_t y, uint64_t c)
{
uint64_t *d = primes_fastdiv, i = 0, r = Phi_6_mod(y), t = y / 17;
r -= Phi_6_mod(t), t = y / 19;
while (i < c && t > Phi_prec_max) r -= Phi(t, i++), t = fastdiv(y, *(d++));
while (i < c && t) r -= Phi_prec(m2(t), i++), t = fastdiv(y, *(d++));
return r;
}
uint64_t Phi_small(uint64_t y, uint64_t c)
{
if (!c--) return y;
return Phi_small(y, c) - Phi_small(y / primes[c], c);
}
uint64_t pi_small(uint64_t y)
{
uint64_t i, r = 0;
for (i = 0; i < 8; i++) r += (primes[i] <= y);
for (i = 21; i <= y; i += 2)
r += i % 3 && i % 5 && i % 7 && i % 11 && i % 13 && i % 17 && i % 19;
return r;
}
int output(int result)
{
clock_gettime(CLOCK_REALTIME, &now);
printf("pi(x) = %9d real time:%9ld ns\n", result , ns(now) - ns(then));
return 0;
}
int main(int argc, char *argv[])
{
uint64_t b, i, j, k, limit, mask, P2, *p, start, t = 8, x = atoi(argv[1]);
uint64_t root2 = sqrt(x), root3 = pow(x, 1./3), top = x / root3 + 1;
uint64_t halftop = m2(top), *sieve, sieve_length = (halftop + 63) / 64;
uint64_t i3 = 1, i5 = 2, i7 = 3, i11 = 5, i13 = 6, i17 = 8, i19 = 9;
uint16_t Phi_3[] = { 0, 1, 1, 1, 2, 2, 3, 4, 4, 5, 6, 6, 7, 7, 7, 8 };
uint16_t *l, *m, Phi_4[106], Phi_5[1156];
clock_gettime(CLOCK_REALTIME, &then);
sieve = malloc(sieve_length * sizeof(int64_t));
if (x < 529) return output(pi_small(x));
for (i = 0; i < sieve_length; i++)
{
mask = 0;
mask_build( i3, 3, 2, 0x9249249249249249ULL);
mask_build( i5, 5, 1, 0x1084210842108421ULL);
mask_build( i7, 7, 6, 0x8102040810204081ULL);
mask_build(i11, 11, 2, 0x0080100200400801ULL);
mask_build(i13, 13, 1, 0x0010008004002001ULL);
mask_build(i17, 17, 4, 0x0008000400020001ULL);
mask_build(i19, 19, 12, 0x0200004000080001ULL);
sieve[i] = ~mask;
}
limit = min(halftop, 8 * cache_size);
for (i = 21; i < root3; i += 2)
if (sbit(i))
for (primes[t++] = i, j = i * i / 2; j < limit; j += i)
word(j) &= ~bit(j);
a = t;
for (i = root3 | 1; i < root2 + 1; i += 2)
if (sbit(i)) primes[t++] = i;
b = t;
while (limit < halftop)
{
start = 2 * limit + 1, limit = min(halftop, limit + 8 * cache_size);
for (p = &primes[8]; p < &primes[a]; p++)
for (j = max(start / *p | 1, *p) * *p / 2; j < limit; j += *p)
word(j) &= ~bit(j);
}
P2 = (a - b) * (a + b - 1) / 2;
for (i = m2(root2); b --> a; P2 += t, i = limit)
{
limit = m2(x / primes[b]), j = limit & ~63;
if (i < j)
{
t += popcnt((word(i)) >> (i & 63)), i = (i | 63) + 1;
while (i < j) t += popcnt(word(i)), i += 64;
if (i < limit) t += popcnt(word(i) & ones(limit - i));
}
else if (i < limit) t += popcnt((word(i) >> (i & 63)) & ones(limit - i));
}
if (a < 7) return output(Phi_small(x, a) + a - 1 - P2);
a -= 7, Phi_6 = malloc(a * Phi_prec_bytes + 15016 * sizeof(int16_t));
Phi_prec_pointer = &Phi_6[15016];
for (i = 0; i <= 105; i++)
Phi_4[i] = (i / 15) * 8 + Phi_3[i % 15] - Phi_3[(i + 3) / 7];
for (i = 0; i <= 1155; i++)
Phi_5[i] = (i / 105) * 48 + Phi_4[i % 105] - Phi_4[(i + 5) / 11];
for (i = 1, l = Phi_6, *l++ = 0; i <= 15015; )
{
Phi_6_upd_3(); Phi_6_upd_2(); Phi_6_upd_1(); Phi_6_upd_2();
Phi_6_upd_1(); Phi_6_upd_2(); Phi_6_upd_3(); Phi_6_upd_1();
}
for (i = 0; i <= m2(Phi_prec_max); i++)
Phi_prec(i, 0) = Phi_6[i] - Phi_6[(i + 8) / 17];
for (j = 1, p = &primes[7]; j < a; j++, p++)
{
i = 1, memcpy(&Phi_prec(0, j), &Phi_prec(0, j - 1), Phi_prec_bytes);
l = &Phi_prec(*p / 2 + 1, j), m = &Phi_prec(m2(Phi_prec_max), j) - *p;
while (l <= m)
for (k = 0, t = Phi_prec(i++, j - 1); k < *p; k++) *(l++) -= t;
t = Phi_prec(i++, j - 1);
while (l <= m + *p) *(l++) -= t;
}
primes_fastdiv = malloc(a * sizeof(int64_t));
for (i = 0, p = &primes[8]; i < a; i++, p++)
{
t = 96 - __builtin_clzll(*p);
primes_fastdiv[i] = (bit(t) / *p + 1) << (64 - t);
}
return output(Phi(x, a) + a + 6 - P2);
}
यह Meissel-Lehmer विधि का उपयोग करता है ।
समय
अपनी मशीन पर, मुझे संयुक्त परीक्षण मामलों के लिए लगभग 5.7 मिलीसेकंड मिल रहा है । यह 1867 मेगाहर्ट्ज पर DDR3 रैम के साथ एक इंटेल कोर i7-3770 पर है, जो ओपनएसयूएसई 13.2 पर चल रहा है।
$ ./timepi '-march=native -O3' pi 1000
pi(x) = 93875448 real time: 2774958 ns
pi(x) = 66990613 real time: 2158491 ns
pi(x) = 62366021 real time: 2023441 ns
pi(x) = 34286170 real time: 1233158 ns
pi(x) = 5751639 real time: 384284 ns
pi(x) = 2465109 real time: 239783 ns
pi(x) = 1557132 real time: 196248 ns
pi(x) = 4339 real time: 60597 ns
0.00572879 s
क्योंकि प्रसरण बहुत अधिक हो गया है , मैं अनौपचारिक रन समय के लिए कार्यक्रम के भीतर से समय का उपयोग कर रहा हूं। यह वह स्क्रिप्ट है जो संयुक्त रन समय के औसत की गणना करती है।
#!/bin/bash
all() { for j in ${a[@]}; do ./$1 $j; done; }
gcc -Wall $1 -lm -o $2 $2.c
a=(1907000000 1337000000 1240000000 660000000 99820000 40550000 24850000 41500)
all $2
r=$(seq 1 $3)
for i in $r; do all $2; done > times
awk -v it=$3 '{ sum += $6 } END { print "\n" sum / (1e9 * it) " s" }' times
rm times
आधिकारिक समय
यह समय स्कोर मामलों को 1000 गुना करने के लिए है।
real 0m28.006s
user 0m15.703s
sys 0m14.319s
यह काम किस प्रकार करता है
सूत्र
आज्ञा देना एक सकारात्मक पूर्णांक है।एक्स
प्रत्येक सकारात्मक पूर्णांक निम्न स्थितियों में से एक को पूरी तरह से संतुष्ट करता है।n ≤ x
एन = 1
पी [ 1 , 3 √n एक अभाज्य संख्या , में विभाजित है ।पी[ १ , एक्स--√3]
पी क्यू ( 3 √n = p क्ष , जहां और (जरूरी नहीं कि अलग-अलग हों) में प्रमुख संख्याएँ हैं ।पीक्ष( x)--√3, एक्स2--√3)
n > 3 √n अभाज्य है औरn > x--√3
Let primes की संख्या को निरूपित करता है जैसे कि । कर रहे हैं संख्या कि चौथी श्रेणी में आते हैं।पी पी ≤ y π ( x ) - π ( 3 √π( y)पीप ≤ यπ( x ) - π( x)--√3)
चलो धनात्मक पूर्णांक की राशि निरूपित मीटर ≤ y कि वास्तव में का एक उत्पाद है k पहले के बीच में नहीं रूढ़ अंक ग रूढ़ अंक। कर रहे हैं पी 2 ( एक्स , π ( 3 √पीक( y, सी )म ≤ यकसीतीसरी श्रेणी में आने वाली संख्या।पी2( x , π( x)--√3) )
अंत में, चलो धनात्मक पूर्णांक की राशि निरूपित कश्मीर ≤ y है कि पहले के coprime हैं ग रूढ़ अंक। कर रहे हैं एक्स - φ ( एक्स , π ( 3 √ϕ ( y), सी )के ≤ यसीसंख्याएँ जो दूसरी श्रेणी में आती हैं।एक्स - φ ( एक्स , π( x)--√3) )
चूंकि सभी श्रेणियों में नंबर हैं ,एक्स
1 + एक्स - φ ( एक्स , π( x)--√3) ) + पी2( x , π( x)--√3) ) + π( x ) - π( x)--√3) = एक्स
और इसीलिए,
π( X ) = φ ( एक्स , π( x)--√3) ) + π( x)--√3) - 1 - पी2( x , π( x)--√3) )
अगर यह आवश्यक है कि तीसरी श्रेणी में नंबर एक अद्वितीय प्रतिनिधित्व और इसलिए पी ≤ √p ≤ क्ष । इस तरह, अभाज्य संख्या की उत्पादपीऔरक्यूतीसरी श्रेणी में है यदि और केवल यदि 3 √पी ≤ एक्स--√पीक्ष , इसलिएπ(x) हैंएक्स--√3< p ≤ q≤ xपीके लिए संभावित मानक्षका एक निश्चित मूल्य के लिएपी, औरपी2(एक्स,π(3√π( x)पी) - π( p ) + 1क्षपी, जहांपीकश्मीरको दर्शाता हैकश्मीरवेंअभाज्य संख्या।पी2( x , π( x)--√3) ) = ∑π( x)√3) < कश्मीर ≤ π( x)√)( π( x)पीक) - π( पीक) + 1 )पीककवें
अंत में, हर सकारात्मक पूर्णांक कि है नहीं पहले coprime ग रूढ़ अंक के रूप में अद्वितीय फैशन में व्यक्त किया जा सकता n = पी कश्मीर च , जहां पी कश्मीर का सबसे कम प्रधानमंत्री कारक है n । इस तरह, कश्मीर ≤ सी , और च पहले coprime है कश्मीर - 1 का अभाज्य संख्या।n ≤ यसीn = पीकचपीकnके ≤ सीचके - १
ϕ ( y), सी ) = वाई- ∑1 ≤ के ≤ सीϕ ( y)पीक, के - 1 )ग = ०ϕ ( y), 0 ) = वाई
π( x )π( x)2--√3)
कलन विधि
हमें गणना करनी होगीπ( x)पी)पीएक्स--√3x2−−√3
[1,x−−√]π(x−−√3)π(x−−√)xpkk(π(x−−√3),π(x−−√)]
∑π(x√3)<k≤π(x√)(−π(pk)+1)π(x√3)−π(x√))(π(x√3)+π(x√)−12P2(x,π(x−−√3))
ϕ2cϕ(y,c)
ϕ(0,c)=0cϕ(y,c)=y−∑1≤k≤c,pk≤yϕ(ypk,k−1)2⋅109
yc′ϕϕ(y,c)=ϕ(y,c′)−∑c′<k≤c,pk≤yϕ(ypk,k−1)ϕ(y,c′)c′y
mc=∏1≤k≤cpkϕ(mc,c)=φ(mc)[1,mc]p1,⋯,pcmcgcd(z+mc,mc)=gcd(z,mc)ϕ(y,c)=ϕ(⌊ymc⌋mc,c)+ϕ(y
चूँकि Euler का कुल कार्य गुणक है, , और हमारे पास है सभी लिए प्राप्त करने का एक आसान तरीका केवल में उन लिए मानों को precomputing करके ।φ(mc)=∏1≤k≤cφ(pk)=∏1≤k≤c(pk−1)ϕ(y,c)yy[0,mc)
इसके अलावा, अगर हम सेट , हम प्राप्त , लेहमर के पेपर से मूल परिभाषा। यह हमें precompute लिए एक सरल तरीका देता है के मूल्यों में वृद्धि के लिए ।c′=c−1ϕ(y,c)=ϕ(y,c−1)−ϕ(ypc,c−1)ϕ(y,c)c
Precomputing के लिए इसके अलावा की एक निश्चित, कम मूल्य के लिए , हम भी इसके बारे में कम मूल्यों के लिए precompute करेंगे , प्रत्यावर्तन एक निश्चित सीमा से नीचे गिरने के बाद कम काटने।ϕ(y,c)cy
कार्यान्वयन
पिछले अनुभाग में कोड के अधिकांश भाग शामिल हैं। एक शेष, महत्वपूर्ण विवरण यह है कि फ़ंक्शन में विभाजन कैसे Phi
किए जाते हैं।
चूंकि कंप्यूटिंग केवल पहले प्राइम नंबर से विभाजित करने की आवश्यकता है , हम इसके बजाय फ़ंक्शन का उपयोग कर सकते हैं । बल्कि सिर्फ एक विभाजित की तुलना में एक प्रमुख द्वारा , हम गुणा द्वारा बजाय और ठीक हो के रूप में । X64 पर पूर्णांक गुणन कैसे लागू किया जाता है, इस कारण से विभाजित करने की आवश्यकता नहीं है; के उच्च 64 बिट्स अपने स्वयं के रजिस्टर में संग्रहीत किए हैं।ϕπ(x−−√3)fastdiv
ypydp≈264pyp 264dpydpy264264dpy
ध्यान दें कि इस विधि के लिए को करने की आवश्यकता होती है , जो सीधे गणना करने से अधिक तेज़ नहीं है । हालाँकि, जब से हमें एक ही primes को बार-बार विभाजित करना पड़ता है और विभाजन गुणन की तुलना में बहुत धीमा है, इसके परिणामस्वरूप एक महत्वपूर्ण गति-अप होता है। इस एल्गोरिथ्म पर और अधिक विवरण, साथ ही एक औपचारिक प्रमाण, डिवीजन में इनवैलेंट इंटेगर द्वारा गुणन का उपयोग करके पाया जा सकता है ।यdpyp