-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathprime.py
More file actions
193 lines (187 loc) · 6.5 KB
/
Copy pathprime.py
File metadata and controls
193 lines (187 loc) · 6.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
# prime.py: Prime number object for Python
#--
# Written by John W. Shipman (john@nmt.edu), New Mexico Tech
# Computer Center, Socorro, NM 87801
#--
# $Revision: 1.7 $
# $Date: 1997/06/05 23:59:04 $
#--
from math import *
class Prime:
""" Object for testing long integers for primality.
Tests a number n by dividing it by all primes <= sqrt(n).
Memoizes primes already found so that repeated use
does not pay the performance penalty.
Exports:
.factor ( n )
[ if n is a positive long integer ->
if n is prime ->
return None
else ->
return the smallest prime factor of n
]
.factorize ( n )
[ if n is a positive long integer ->
return a list of the prime factors of n
]
State/invariants:
._p == A list of known primes
INVARIANT: Excludes 1, and includes at least 2 and 3;
all members are prime and sorted in ascending order.
._pMax == Upper limit of self._p
INVARIANT: self._p is guaranteed to contain all
primes <= self._pMax.
Verified, June 1997, by Al Stavely.
"""
# - - - _ _ i n i t _ _ - - -
def __init__ ( self ):
self._p = [ 2L, 3L, 5L ]
self._pMax = 6L
# - - - f a c t o r - - -
def factor ( self, n ):
""" [ if n is a positive long integer ->
if n is prime ->
return None
else ->
return the smallest prime factor of n
in any case ->
self._p := self._p with all necessary primes
appended so that it contains all primes
in the range [2,floor(sqrt(n))]
self._pMax := max ( self._pMax, floor(sqrt(n)) )
]
"""
#-- 1 --
if n < 4L:
return None
#-- 2 --
#-[ limit := the largest integer <= floor(sqrt(n))
#-]
limit = long ( sqrt ( float ( n ) ) )
#-- 3 --
#-[ self._p := self._p with all necessary values
# added so that it contains all primes <= limit
#-] self._pMax := max ( self._pMax, limit )
#-]
self._fill ( limit )
#-- 4 --
#-[ if there is an element E of self._p such that
# (E<=limit) and (E divides n) ->
# return the smallest such element
# else -> I
#-]
for f in self._p:
#-- 4 body --
#-[ if f > limit ->
# break
# else if f divides n ->
# return f
# else -> I
#-]
if ( n % f ) == 0L:
return f
elif f >= limit:
break
#-- 5 --
return None
# - - - . _ f i l l - - -
def _fill ( self, limit ):
""" [ if limit is a positive long integer ->
if self._pMax >= limit -> I
else ->
self._p := self._p with all primes P added
such that (P <= limit)
self._pMax := limit
"""
#-- 1 --
if self._pMax >= limit:
return
#-- 2 --
#--
# Note: since the invariant guarantees that self._p
# contains at least 3, and since all primes greater than
# 3 are odd, our candidates are the odd numbers starting
# at 2 + the last element of self._p. We can't use a
# `for' loop here because xrange() doesn't handle longs.
#--
i = self._p[-1] + 2L
#-- 3 --
#-[ self._p := self._p with all primes P added
# such that (i <= P <= limit)
# i := <anything>
#-]
while i <= limit:
#-- 3 loop --
#-[ if i is prime ->
# self._p := self._p with i appended
# else -> I
# In any case ->
# i = i + 2L
#-]
if not self.factor ( i ):
self._p.append ( long(i) )
i = i + 2L
#-- 4 --
self._pMax = limit
# - - - . f a c t o r i z e - - -
def factorize ( self, n ):
""" [ if n is a positive long integer ->
return a list of the prime factors of n, excluding 1,
and including n iff n is prime
]
"""
#-- 1 --
#-[ if n is prime ->
# f0 := None
# else ->
# f0 := the smallest prime factor in n
#-]
n = long(n) # Permit calling with normal integers
f0 = self.factor ( n )
#-- 2 --
#-[ if f0 is None ->
# return [n]
# else ->
# result := [f0]
# residue := n / f0
#-]
if not f0:
return [n]
else:
result = [f0]
residue = n / f0
#-- 3 --
#-[ result := result with all prime factors of residue
# appended (except 1)
# residue := <anything>
#-]
while residue > 1:
#-- 3 loop --
#-[ if residue has a prime factor ->
# result := result with the smallest prime factor of
# residue appended
# residue := residue / (that smallest prime factor)
#-]
#-- 3.1 --
#-[ if residue has a prime factor ->
# f0 := that factor
# else ->
# f0 := None
#-]
f0 = self.factor ( residue )
#-- 3.2 --
#-[ if f0 is None ->
# result := result with residue appended
# residue := 1
# else ->
# result := result with f0 appended
# residue := residue / f0
#-]
if not f0:
result.append ( residue )
residue = 1
else:
result.append ( f0 )
residue = residue / f0
#-- 4 --
return result