Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/functions/prime_pi.pyx
4069 views
1
"""
2
Counting Primes
3
4
AUTHORS:
5
* R. Andrew Ohana
6
* William Stein
7
8
TESTS::
9
10
sage: z = sage.functions.prime_pi.PrimePi()
11
sage: loads(dumps(z))
12
Function that counts the number of primes up to x
13
sage: loads(dumps(z)) == z
14
True
15
"""
16
17
#*****************************************************************************
18
# Copyright (C) 2009 R. Andrew Ohana <[email protected]>
19
# Copyright (C) 2009 William Stein <[email protected]>
20
#
21
# Distributed under the terms of the GNU General Public License (GPL)
22
# http://www.gnu.org/licenses/
23
#*****************************************************************************
24
25
include '../ext/cdefs.pxi'
26
include '../ext/stdsage.pxi'
27
include '../ext/interrupt.pxi'
28
29
from sage.rings.integer import Integer
30
from sage.rings.fast_arith import prime_range
31
import sage.plot.all
32
33
cdef extern from "math.h":
34
double sqrt(double)
35
double floor(double)
36
float sqrtf(float)
37
float floorf(float)
38
39
cdef inline long sqrt_longlong(long long N) except -1:
40
"""
41
Return the truncated integer part of the square root of N, i.e., the
42
floor of sqrt(N).
43
"""
44
# code from Bill Hart.
45
cdef long long m = <long> floor(sqrt(<double> N))
46
cdef long long res = m + ((m+1)*(m+1) <= N) # add 1 if too small.
47
res = res - (res*res > N) # subtract 1 if too big.
48
if res*res <= N and (res+1)*(res+1) > N:
49
return res
50
else:
51
raise RuntimeError, "there is a bug in prime_pi.pyx's sqrt_longlong (res=%s, N=%s). Please report!"%(res,N)
52
53
cdef inline long sqrt_long(long N) except -1:
54
"""
55
Return the truncated integer part of the square root of N, i.e., the
56
floor of sqrt(N).
57
"""
58
if sizeof(long) == 8:
59
return sqrt_longlong(N)
60
# code from Bill Hart.
61
cdef long m = <long> floorf(sqrtf(<float> N))
62
cdef long res = m + ((m+1)*(m+1) <= N) # add 1 if too small.
63
res = res - (res*res > N) # subtract 1 if too big.
64
if res*res <= N and (res+1)*(res+1) > N:
65
return res
66
else:
67
raise RuntimeError, "there is a bug in prime_pi.pyx's sqrt_long (res=%s, N=%s). Please report!"%(res,N)
68
69
70
cdef class PrimePi:
71
r"""
72
Return the number of primes $\leq x$.
73
74
EXAMPLES::
75
76
sage: prime_pi(7)
77
4
78
sage: prime_pi(100)
79
25
80
sage: prime_pi(1000)
81
168
82
sage: prime_pi(100000)
83
9592
84
sage: prime_pi(0.5)
85
0
86
sage: prime_pi(-10)
87
0
88
sage: prime_pi(500509)
89
41581
90
91
The following test is to verify that ticket #4670 has been essentially
92
resolved::
93
94
sage: prime_pi(10**10)
95
455052511
96
97
The prime_pi function allows for use of additional memory::
98
99
sage: prime_pi(500509, 8)
100
41581
101
102
The prime_pi function also has a special plotting method, so it plots
103
quickly and perfectly as a step function::
104
105
sage: P = plot(prime_pi, 50,100)
106
"""
107
def __repr__(self):
108
"""
109
EXAMPLES::
110
111
sage: prime_pi.__repr__()
112
'Function that counts the number of primes up to x'
113
"""
114
return 'Function that counts the number of primes up to x'
115
116
def __cmp__(self, other):
117
"""
118
EXAMPLES::
119
120
sage: P = sage.functions.prime_pi.PrimePi()
121
sage: P == prime_pi
122
True
123
sage: P != prime_pi
124
False
125
"""
126
if isinstance(other, PrimePi):
127
return 0
128
return cmp(type(self), type(other))
129
130
cdef long* primes
131
cdef long primeCount, maxPrime
132
133
def __call__(self, long long x, long mem_mult = 1):
134
r"""
135
EXAMPLES::
136
137
sage: prime_pi.__call__(7)
138
4
139
sage: prime_pi.__call__(100)
140
25
141
sage: prime_pi.__call__(1000)
142
168
143
sage: prime_pi.__call__(100000)
144
9592
145
sage: prime_pi.__call__(0.5)
146
0
147
sage: prime_pi.__call__(-10)
148
0
149
sage: prime_pi.__call__(500509)
150
41581
151
sage: prime_pi.__call__(500509, 8)
152
41581
153
154
TESTS:
155
156
Make sure we actually compute correct results::
157
158
sage: for n in (30..40): print prime_pi(2**n) # long time (22s on sage.math, 2011)
159
54400028
160
105097565
161
203280221
162
393615806
163
762939111
164
1480206279
165
2874398515
166
5586502348
167
10866266172
168
21151907950
169
41203088796
170
171
We know this implementation is broken at least on some 32-bit
172
systems for `2^{46}`, so we are capping the maximum allowed value::
173
174
sage: prime_pi(2^40+1)
175
Traceback (most recent call last):
176
...
177
NotImplementedError: computation of prime_pi() greater than 2^40 not implemented
178
179
"""
180
if mem_mult < 1:
181
raise ValueError, "mem_mult must be positive"
182
if x < 2:
183
return 0
184
if x > 1099511627776L:
185
raise NotImplementedError, "computation of prime_pi() greater than 2^40 not implemented"
186
x += x & 1
187
# m_max is the current sieving value, for prime counting - this value is sqrt(x)
188
cdef long m_max = sqrt_longlong(x) + 1
189
cdef long prime
190
cdef long i = 0
191
# mem_mult is the multiplier that determines how large a list of primes built
192
tempList = prime_range(mem_mult*m_max)
193
self.primeCount = len(tempList)
194
if self.primeCount > 1:
195
self.maxPrime = tempList[self.primeCount - 1]
196
self.primes = <long*> sage_malloc(self.primeCount*sizeof(long))
197
for prime in tempList:
198
self.primes[i] = prime
199
i += 1
200
sig_on()
201
s = Integer(self.prime_phi_large(x, m_max))
202
sig_off()
203
sage_free(self.primes)
204
return s
205
206
cdef long long prime_phi_large(self, long long N, long m_max = 0):
207
"""
208
Uses Legendre's Formula for computing pi(x). Both this and the prime_phi_small
209
methods are specialized versions of Legendre's Formula that takes advantage of
210
its recursive properties. Hans Riesel's Prime "Numbers and Computer Methods for
211
Factorization" discusses Legnedre's Formula, however there are many places
212
that discuss it as nearly every prime counting algorithm uses it.
213
"""
214
try:
215
return self.prime_phi_small(long(N), m_max)
216
except OverflowError:
217
pass
218
# m_max is the current sieving value
219
if m_max == 0:
220
m_max = sqrt_longlong(N) + 1
221
cdef long long sum = ( (N >> 1) - (N-4)/6 - (N-16)/10 + (N-16)/30 - (N-8)/14 \
222
+ (N-22)/42 + (N-106)/70 - (N-106)/210 + 2 )
223
cdef long prime = 11
224
cdef bint preTransition = True
225
cdef long long y
226
cdef long i
227
for i in range(4, self.primeCount):
228
if prime >= m_max: break
229
y = (N+prime-1)/(2*prime) << 1
230
if preTransition:
231
if prime*prime <= y:
232
sum -= self.prime_phi_large(y, prime) - i
233
else:
234
sum -= self.prime_phi_large(y) - i
235
preTransition = False
236
else:
237
sum -= self.prime_phi_large(y) - i
238
prime = self.primes[i + 1]
239
return sum
240
241
cdef long prime_phi_small(self, long N, long m_max = 0):
242
if N < 2:
243
return 0
244
N += N & 1
245
if N < 9:
246
return N >> 1
247
if N < 25:
248
return (N >> 1) - (N-4)/6
249
if N < 49:
250
return (N >> 1) - (N-4)/6 - (N-16)/10 + (N-16)/30
251
if N < 121:
252
return (N >> 1) - (N-4)/6 - (N-16)/10 + (N-16)/30 - (N-36)/14 + (N-22)/42
253
# m_max is the current sieving value
254
if m_max == 0:
255
if N < self.maxPrime:
256
return self.bisect(N) + 1
257
m_max = sqrt_long(N) + 1
258
cdef long sum = ( (N >> 1) - (N-4)/6 - (N-16)/10 + (N-16)/30 - (N-8)/14 \
259
+ (N-22)/42 + (N-106)/70 - (N-106)/210 + 2 )
260
cdef long prime = 11
261
cdef bint preTransition = True
262
cdef long x, i
263
for i in range(4, self.primeCount):
264
if prime >= m_max: break
265
x = N / prime
266
if preTransition:
267
if prime*prime <= x:
268
sum -= self.prime_phi_small(x, prime) - i
269
else:
270
sum -= self.prime_phi_small(x) - i
271
preTransition = False
272
else:
273
sum -= self.prime_phi_small(x) - i
274
prime = self.primes[i + 1]
275
return sum
276
277
cdef long bisect(self, long N):
278
cdef long size = self.primeCount >> 1
279
if N >> 2 < size:
280
size = N >> 2
281
cdef long position = size
282
cdef long prime
283
while size > 0:
284
prime = self.primes[position]
285
size >>= 1
286
if prime < N:
287
position += size
288
elif prime > N:
289
position -= size
290
else: break
291
if position < self.primeCount - 1:
292
prime = self.primes[position + 1]
293
while prime < N:
294
position += 1
295
prime = self.primes[position + 1]
296
prime = self.primes[position]
297
while prime > N:
298
position -= 1
299
prime = self.primes[position]
300
return position
301
302
def plot(self, xmin=0, xmax=100, vertical_lines=True, **kwds):
303
"""
304
Draw a plot of the prime counting function from xmin to xmax.
305
All additional arguments are passed on to the line command.
306
307
WARNING: we draw the plot of prime_pi as a stairstep function
308
with explicitly drawn vertical lines where the function
309
jumps. Technically there should not be any vertical lines, but
310
they make the graph look much better, so we include them.
311
Use the option ``vertical_lines=False`` to turn these off.
312
313
EXAMPLES::
314
315
sage: plot(prime_pi, 1, 100)
316
sage: prime_pi.plot(-2,50,thickness=2, vertical_lines=False)
317
"""
318
y = self(xmin)
319
v = [(xmin, y)]
320
for p in prime_range(xmin+1, xmax+1):
321
y += 1
322
v.append((p,y))
323
v.append((xmax,y))
324
from sage.plot.step import plot_step_function
325
return plot_step_function(v, vertical_lines=vertical_lines, **kwds)
326
327
#############
328
prime_pi = PrimePi()
329
330
331