primes-utils 2.3.0 → 2.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +2 -1
- data/README.md +23 -4
- data/lib/primes/utils.rb +118 -122
- data/lib/primes/utils/version.rb +1 -1
- data/primes-utils.gemspec +1 -1
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 72ccd5984ebd121f01d0846f5e6cd178fd7b007e
|
4
|
+
data.tar.gz: 6a484343ab2c7b047f382d4b104119c9888a5779
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ee5446beb5818aaee204b7ea525ab97e5c52e47be2f9e739594a54cc9863a8a4dacbaf074219ea8e634c098bac32d33d4f879c8c81f60770a79df27c5b11f63c
|
7
|
+
data.tar.gz: 655f6c271d60b538597c861733f48e36683cb61b72cf577d0c9f53a0e0f7498767dc49b964c64599bf3d775d4ae6ca4c814e12035601724fee6261ed3036829a
|
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -101,6 +101,9 @@ n=10**100; (n-250).primesmr(n+250) => []
|
|
101
101
|
prms.size => 6
|
102
102
|
prms => [1000003, 1000033, 1000037, 1000039, 1000081, 1000099]
|
103
103
|
-10.primes -50 => [11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47]
|
104
|
+
n=10**20; n.primes n+n -> ERROR1: range size too big for available memory. => nil
|
105
|
+
n=10**20; n.primes 100 -> ERROR2: end_num too big for available memory. => nil
|
106
|
+
n=10**8; (25*n).primes -> ERROR3: not enough memory to store all primes in output array. => nil
|
104
107
|
0.primesf => []
|
105
108
|
1.primesmr => []
|
106
109
|
```
|
@@ -120,6 +123,9 @@ Also see `Error Handling`.
|
|
120
123
|
100000.primescntf 100500 => 40
|
121
124
|
n=10**400; (n-500).primescntmr(n+500) => 1
|
122
125
|
-10.primescnt -50 => 11
|
126
|
+
n=10**20; n.primescnt n+n -> ERROR1: range size too big for available memory. => nil
|
127
|
+
n=10**20; n.primescnt 100 -> ERROR2: end_num too big for available memory. => nil
|
128
|
+
n=10**8; (25*n).primescnt => 121443371
|
123
129
|
0.primescntf => 0
|
124
130
|
1.primescntmr => 0
|
125
131
|
```
|
@@ -138,6 +144,7 @@ Also see `Error Handling`.
|
|
138
144
|
2000000.nthprime 11 => 32452843
|
139
145
|
-500000.nthprime => 7368787
|
140
146
|
1122951705.nthprime => 25741879847
|
147
|
+
n = 10**11; n.primenth -> ERROR1: range size too big for available memory. => nil
|
141
148
|
0.nthprime => 0
|
142
149
|
1.primenth => 2
|
143
150
|
```
|
@@ -152,14 +159,20 @@ Use as `x.primes_utils` where x is any `class Integer` value.
|
|
152
159
|
```
|
153
160
|
|
154
161
|
## Error Handling
|
155
|
-
Starting with 2.2.0, error handling has been implemented to gracefully
|
162
|
+
Starting with 2.2.0, error handling has been implemented to gracefully fail when array creation requires more memory than available.
|
156
163
|
This occurs when the range size, or end_num, need arrays greater than the amount of avalable memory. The first case shows the message
|
157
164
|
`ERROR1: range size too big for available memory.` and the second case `ERROR2: end_num too big for available memory.`
|
158
|
-
The affected methods are `
|
159
|
-
`nthprime|primenth` also displays the error message `<
|
160
|
-
(
|
165
|
+
The affected methods are `primes`, and `primescnt`, and possibly `nthprime|primenth`.
|
166
|
+
`nthprime|primenth` also displays the error message `<pcnt> not enough primes, approx nth too small.`
|
167
|
+
(`<pcnt>` is computed count of primes) when the computed approx_nth value < nth value (though this should never happen by design).
|
168
|
+
With 2.4.0 error handling was added to `primes` that catches the error and displays message `ERROR3: not enough memory to store all primes in output array.`.
|
161
169
|
For all errors, the return value for each method is `nil`.
|
162
170
|
|
171
|
+
There is also the rare possibility you could get a `NoMemoryError: failed to allocate memory` for the methods
|
172
|
+
`primesf` and `primesmr` if their list of numerated primes is bigger than the amount of available system memory needed to store them.
|
173
|
+
If those methods are used as designed these errors won't occur, so the extra code isn't justified for them.
|
174
|
+
If they occur you will know why now.
|
175
|
+
|
163
176
|
This behavior is referenced to MRI Ruby.
|
164
177
|
|
165
178
|
## Coding Implementations
|
@@ -178,6 +191,12 @@ All the `primes-utils` methods are `instance_methods` for `class Integer`.
|
|
178
191
|
|
179
192
|
## History
|
180
193
|
```
|
194
|
+
2.4.0 – fixed error in algorithm when ks resgroup ≤ sqrt(end_num) resgroup; algorithm now split
|
195
|
+
arrays when start_num > sqrt(end_num) in sozcore2, whose code also signficantly optimized,
|
196
|
+
with API change adding pcs2start value to output parameters to use in primenth, which changed
|
197
|
+
to use it; ruby idiom code opt for set_start_value; consolidated pcs_to_num | pcs_to_start_num
|
198
|
+
functions into one new pcs_to_num, with associated changes in sozcore1|2; primes|cnt also
|
199
|
+
significantly faster resulting from sozcore2 changes; massive code cleanups all-arround
|
181
200
|
2.3.0 – primescnt now finds primes upto some integer much faster, and for much larger integers
|
182
201
|
increased index nth primes to over 2 billionth; used in nthprime|primenth and primescnt
|
183
202
|
2.2.0 – for sozcore2: refactored to include more common code; changed output api; added memory
|
data/lib/primes/utils.rb
CHANGED
@@ -37,8 +37,8 @@ module Primes
|
|
37
37
|
# Find primes within a number range: end_num - start_num
|
38
38
|
# Uses 'prime?' to check primality of prime candidates in range
|
39
39
|
sozdata = sozcore1(self, start_num, true) # true for primes
|
40
|
-
return sozdata[1] if !sozdata[0] # if sozdata[0] false
|
41
40
|
pcs_in_range, r, mod, modk, rescnt, residues, primes = sozdata
|
41
|
+
|
42
42
|
pcs_in_range.times do # find primes from this num pcs in range
|
43
43
|
prime = modk + residues[r]
|
44
44
|
primes << prime if prime.prime?
|
@@ -51,7 +51,6 @@ module Primes
|
|
51
51
|
# Count primes within a number range: end_num - start_num
|
52
52
|
# Uses 'prime?' to check primality of prime candidates in range
|
53
53
|
sozdata = sozcore1(self, start_num, false) # false for primescnt
|
54
|
-
return sozdata[1] if !sozdata[0] # if sozdata[0] false
|
55
54
|
pcs_in_range, r, mod, modk, rescnt, residues, primescnt = sozdata
|
56
55
|
|
57
56
|
pcs_in_range.times do # count primes from this num pcs in range
|
@@ -76,7 +75,7 @@ module Primes
|
|
76
75
|
47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103,
|
77
76
|
107, 109, 113, 127, 131, 137, 139, 149, 151, 157,163,
|
78
77
|
167, 173, 179, 181, 191, 193, 197, 199, 211].include? n
|
79
|
-
return false
|
78
|
+
return false unless residues.include?(n%mod) and n > 1
|
80
79
|
|
81
80
|
sqrtN = Math.sqrt(n).to_i
|
82
81
|
p=11 # first test prime pj
|
@@ -101,18 +100,18 @@ module Primes
|
|
101
100
|
|
102
101
|
def factors(p=13)
|
103
102
|
# Return prime factors of n in form [[p1,e1],[p2,e2]..[pn,en]]
|
104
|
-
# Uses
|
103
|
+
# Uses P13 SP PG as default Prime Generator
|
105
104
|
seeds = [2, 3, 5, 7, 11, 13, 17, 19]
|
106
|
-
p = 13
|
105
|
+
p = 13 unless seeds.include? p
|
107
106
|
|
108
107
|
primes = seeds[0..seeds.index(p)]
|
109
|
-
|
108
|
+
mod = primes.reduce(:*) # modulus: modPn = 2*3*5*7*..*Pn
|
110
109
|
residues, rescnt = make_residues_rescnt(mod)
|
111
110
|
|
112
111
|
n = self.abs # number to factor
|
113
112
|
factors = [] # init empty factors array
|
114
113
|
|
115
|
-
return [] if n
|
114
|
+
return [] if n < 2
|
116
115
|
return [[n,1]] if primes.include? n
|
117
116
|
primes.each {|p| while n%p == 0; factors << p; n /= p end }
|
118
117
|
|
@@ -136,10 +135,9 @@ module Primes
|
|
136
135
|
alias prime_division factors
|
137
136
|
|
138
137
|
def primenth(p=7)
|
139
|
-
# Return value of nth prime
|
140
|
-
# Uses sozP7 Sieve of Zakiya (SoZ) as default Prime Generator
|
138
|
+
# Return value of nth prime; P7 is default SP Prime Generator
|
141
139
|
seeds = [2, 3, 5, 7, 11, 13]
|
142
|
-
p = 7
|
140
|
+
p = 7 unless seeds.include? p
|
143
141
|
|
144
142
|
n = self.abs # the desired nth prime
|
145
143
|
return n != 0 ? seeds[n-1] : 0 if n <= seeds.size
|
@@ -149,8 +147,8 @@ module Primes
|
|
149
147
|
|
150
148
|
num = approximate_nth(n) # close approx to nth >= real nth
|
151
149
|
primes = seeds[0..seeds.index(p)]
|
152
|
-
|
153
|
-
prms, m,
|
150
|
+
mod = primes.reduce(:*) # create modulus of SP PG
|
151
|
+
prms, m, modk, residues, rescnt, pcs2start, * = sozcore2(num, start_num, mod)
|
154
152
|
return if prms == nil # exit gracefully if sozcore2 mem error
|
155
153
|
|
156
154
|
# starting at start_num's location, find nth prime within given range
|
@@ -158,7 +156,7 @@ module Primes
|
|
158
156
|
pcnt = prmcnt + prms[m..-1].count(1) # number of primes upto nth approx
|
159
157
|
return puts "#{pcnt} not enough primes, approx nth too small." if pcnt < n
|
160
158
|
while prmcnt < n; prmcnt +=1 if prms[m] == 1; m +=1 end
|
161
|
-
k, r = (m +
|
159
|
+
k, r = (m + pcs2start).divmod rescnt
|
162
160
|
mod*k + residues[r]
|
163
161
|
end
|
164
162
|
|
@@ -166,23 +164,25 @@ module Primes
|
|
166
164
|
|
167
165
|
def primes(start_num=0)
|
168
166
|
# Find primes between a number range: end_num - start_num
|
169
|
-
#
|
167
|
+
# Adaptively selects Strictly Prime (SP) Prime Generator
|
170
168
|
num = self.abs; start_num = start_num.abs
|
171
169
|
num, start_num = start_num, num if start_num > num
|
172
170
|
|
173
|
-
primes =
|
174
|
-
plast = primes.last # last prime in primes
|
175
|
-
return primes.select {|p| p >= start_num && p <= num} if num <= plast
|
171
|
+
primes, mod = select_pg(num, start_num) # adaptively select PG
|
176
172
|
|
177
|
-
prms, m,
|
173
|
+
prms, m, modk, residues, rescnt, *, maxprms, r = sozcore2(num, start_num, mod)
|
178
174
|
return if prms == nil # exit gracefully if sozcore2 mem error
|
179
175
|
|
180
|
-
#
|
181
|
-
primes =
|
182
|
-
while m < maxprms
|
183
|
-
|
176
|
+
# init 'primes' w/any excluded primes in range then extract primes from prms
|
177
|
+
primes = primes.select {|p| p >= start_num && p <= num}
|
178
|
+
while m < maxprms # find primes from sieved pcs in prms for range
|
179
|
+
begin
|
180
|
+
primes << modk + residues[r] if prms[m] == 1
|
181
|
+
rescue Exception
|
182
|
+
return puts "ERROR3: not enough memory to store all primes in output array."
|
183
|
+
end
|
184
184
|
r +=1; if r > rescnt; r=1; modk +=mod end
|
185
|
-
|
185
|
+
m +=1
|
186
186
|
end
|
187
187
|
primes
|
188
188
|
end
|
@@ -193,22 +193,19 @@ module Primes
|
|
193
193
|
num = self.abs; start_num = start_num.abs
|
194
194
|
num, start_num = start_num, num if start_num > num
|
195
195
|
|
196
|
-
|
197
|
-
plast = seeds.last # last prime in seeds
|
198
|
-
return seeds.select {|p| p >= start_num && p <= num}.size if num <= plast
|
199
|
-
|
200
|
-
if start_num == 0
|
196
|
+
if start_num < 3 # for all primes upto num
|
201
197
|
start_num, nth, nthflag = set_start_value(num,false)
|
202
|
-
return nth
|
198
|
+
return nth unless nthflag # output nth's number if n a ref nth prime
|
203
199
|
end
|
204
200
|
|
205
|
-
primes = nthflag ? [2,3,5,7] : [2,3,5] #
|
206
|
-
|
201
|
+
primes = nthflag ? [2,3,5,7] : [2,3,5] # use P7 upto an N; P5 for a range
|
202
|
+
mod = primes.reduce(:*)
|
203
|
+
prms, m, * = sozcore2(num, start_num, mod)
|
207
204
|
return if prms == nil # exit gracefully if sozcore2 mem error
|
208
205
|
|
209
|
-
#
|
210
|
-
prmcnt =
|
211
|
-
prmcnt = nth
|
206
|
+
# init prmcnt for any excluded primes in range then count primes in prms
|
207
|
+
prmcnt = primes.select {|p| p >= start_num && p <= num}.size
|
208
|
+
prmcnt = nth-1 if nthflag && nth > 0 # nflag is nil or true
|
212
209
|
prmcnt + prms[m..-1].count(1)
|
213
210
|
end
|
214
211
|
|
@@ -220,8 +217,8 @@ module Primes
|
|
220
217
|
require 'openssl'
|
221
218
|
def primemr?(k=20) # increase k for more reliability
|
222
219
|
n = self.abs
|
223
|
-
return true if
|
224
|
-
return false
|
220
|
+
return true if [2,3].include? n
|
221
|
+
return false unless [1,5].include?(n%6) and n > 1
|
225
222
|
|
226
223
|
d = n - 1
|
227
224
|
s = 0
|
@@ -244,8 +241,8 @@ module Primes
|
|
244
241
|
# Find primes within a number range: end_num - start_num
|
245
242
|
# Uses 'primemr' to check primality of prime candidates in range
|
246
243
|
sozdata = sozcore1(self, start_num, true) # true for primes
|
247
|
-
return sozdata[1] if !sozdata[0] # if sozdata[0] false
|
248
244
|
pcs_in_range, r, mod, modk, rescnt, residues, primes = sozdata
|
245
|
+
|
249
246
|
pcs_in_range.times do # find primes from this num pcs in range
|
250
247
|
prime = modk + residues[r]
|
251
248
|
primes << prime if prime.primemr?
|
@@ -258,7 +255,6 @@ module Primes
|
|
258
255
|
# Count primes within a number range: end_num - start_num
|
259
256
|
# Uses 'primemr' to check primality of prime candidates in range
|
260
257
|
sozdata = sozcore1(self, start_num, false) # false for primescnt
|
261
|
-
return sozdata[1] if !sozdata[0] # if sozdata[0] false
|
262
258
|
pcs_in_range, r, mod, modk, rescnt, residues, primescnt = sozdata
|
263
259
|
|
264
260
|
pcs_in_range.times do # count primes from this num pcs in range
|
@@ -280,115 +276,105 @@ module Primes
|
|
280
276
|
|
281
277
|
private
|
282
278
|
def make_residues_rescnt(mod)
|
283
|
-
residues=[1]; 3.step(mod,2) {|
|
279
|
+
residues=[1]; 3.step(mod,2) {|r| residues << r if mod.gcd(r) == 1}
|
284
280
|
residues << mod+1
|
285
281
|
[residues, residues.size-1] # return residues array and rescnt
|
286
282
|
end
|
287
283
|
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
def pcs_to_start_num(start_num, mod, rescnt, residues)
|
296
|
-
k = (start_num-2).abs/mod # start_num's residue group value
|
297
|
-
modk = mod*k # start_num's mod group value
|
298
|
-
m = rescnt*k # number of pcs upto kth resgroup
|
299
|
-
r = 1 # find r,m for first pc >= start_num
|
300
|
-
while modk + residues[r] < start_num; r +=1 end
|
301
|
-
[m+r-1, r, modk] # parameters for 1st pc >= start_num
|
284
|
+
# lte= true: first output element is number pcs <= num
|
285
|
+
# lte=false: num pcs <, residue index, and resgroup value, for (start_)num pc
|
286
|
+
def pcs_to_num(num,mod,rescnt,residues,lte)
|
287
|
+
num -=1; lte ? (num |=1; k=num.abs/mod) : k = (num-1).abs/mod
|
288
|
+
modk = mod*k; r=1
|
289
|
+
r +=1 while num >= modk+residues[r]
|
290
|
+
[rescnt*k + r-1, r, modk] # [num pcs, r index, num modulus]
|
302
291
|
end
|
303
292
|
|
293
|
+
# Use default SP Prime Generator to parametize the pcs within a range
|
294
|
+
# inputs: end_num|start_num of range; method_flag to numerate|count primes
|
295
|
+
# outputs: maxpcs-m - number of pcs in the range
|
296
|
+
# r - residue index value for start_num pc of range
|
297
|
+
# mod - mod value for PG
|
298
|
+
# modk - base value for start_num's resgroup
|
299
|
+
# rescnt - number of residues for PG
|
300
|
+
# residues - array of residues plus mod+1 for PG
|
301
|
+
# primes array|primes.size - primes array or size based on method_flag
|
304
302
|
def sozcore1(num, start_num, method_flag)
|
305
|
-
# Uses the P13 Strictly Prime (SP) Prime Generator
|
306
303
|
num = num.abs; start_num = start_num.abs
|
307
304
|
num, start_num = start_num, num if start_num > num
|
308
305
|
|
309
|
-
primes = [2,3,5,7,11,13] #
|
310
|
-
plast = primes.last # last prime in primes
|
311
|
-
if num <= plast
|
312
|
-
primes = primes.select {|p| p >= start_num && p <= num}
|
313
|
-
return [false, method_flag ? primes : primes.size]
|
314
|
-
end
|
306
|
+
primes = [2,3,5,7,11,13] # excluded primes for P13 default SP PG
|
315
307
|
mod = primes.reduce(:*) # P13 modulus: 2*3*5*7*11*13 = 30030
|
316
308
|
residues, rescnt = make_residues_rescnt(mod)
|
317
|
-
maxpcs = pcs_to_num(num,
|
309
|
+
maxpcs,* = pcs_to_num(num,mod,rescnt,residues,true) # num pcs <= end_num
|
318
310
|
|
319
|
-
#
|
320
|
-
primes =
|
321
|
-
m, r, modk = pcs_to_start_num(start_num, mod, rescnt, residues)
|
311
|
+
# init 'primes' w/any excluded primes in the range, or [] if none
|
312
|
+
primes = primes.select {|p| p >= start_num && p <= num}
|
322
313
|
|
314
|
+
# compute parameters for start_num pc, then create output parameters array
|
315
|
+
m, r, modk = pcs_to_num(start_num, mod, rescnt, residues, false)
|
323
316
|
[maxpcs-m, r, mod, modk, rescnt, residues, method_flag ? primes : primes.size]
|
324
317
|
end
|
325
318
|
|
326
|
-
# Perform SoZ
|
327
|
-
# inputs: end_num and start_num of range
|
319
|
+
# Perform SoZ with given Prime Generator and return array of parameters
|
320
|
+
# inputs: end_num and start_num of range and mod value for PG
|
328
321
|
# outputs: prms - binary (0,1) array of pcs within a range or to end_num
|
329
|
-
# m -
|
330
|
-
#
|
331
|
-
# modk - mod*ks; mod value for ks, start_num's resgroup
|
322
|
+
# m - num of pcs in prms < start_num; so prms[m] = start_num
|
323
|
+
# modks - mod value for start_num's resgroup
|
332
324
|
# residues - array of residues plus mod+1 for PG
|
333
|
-
# rescnt - number of residues
|
334
|
-
#
|
335
|
-
#
|
336
|
-
|
337
|
-
def sozcore2(num, start_num,
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
325
|
+
# rescnt - number of residues for PG
|
326
|
+
# pcs2start- number of pcs < start_num pc
|
327
|
+
# maxprms - number of pcs to find primes from; prms array size
|
328
|
+
# rs - residue index location for first pc >= start_num
|
329
|
+
def sozcore2(num, start_num, mod)
|
330
|
+
residues, rescnt = make_residues_rescnt(mod) # parameters for the PG
|
331
|
+
maxprms,* = pcs_to_num(num,mod,rescnt,residues,true) # num pcs <= end_num
|
332
|
+
|
333
|
+
# for start_num pc, find num pcs <, residue index, and resgroup mod value
|
334
|
+
pcs2start, rs, modks = pcs_to_num(start_num, mod, rescnt, residues, false)
|
335
|
+
|
342
336
|
sqrtN = Math.sqrt(num).to_i # sqrt of end_num (end of range)
|
343
|
-
pcs2sqrtN = pcs_to_num(sqrtN,mod,rescnt,residues) # num
|
344
|
-
|
345
|
-
|
346
|
-
maxpcs = maxprms #
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
end
|
358
|
-
prms=Array.new(maxpcs,1) # for primes upto sqrtN and end_num if ks=0
|
359
|
-
rescue # for not enough memory error for prms
|
360
|
-
return puts "ERROR2: end_num too big for available memory."
|
361
|
-
end # method return value is `nil` upon error
|
362
|
-
|
363
|
-
# hash of residues offsets to compute nonprimes positions in prms
|
337
|
+
pcs2sqrtN,* = pcs_to_num(sqrtN,mod,rescnt,residues,true) # num pcs <= sqrtN
|
338
|
+
|
339
|
+
split_arrays = start_num > sqrtN # flag, true if two arrays used for sieve
|
340
|
+
maxpcs = maxprms # init array size for all pcs to end_num
|
341
|
+
if split_arrays # if start_num > sqrtN create two arrays
|
342
|
+
maxpcs = pcs2sqrtN # number of pcs|array size, for pcs <= sqrtN
|
343
|
+
max_range = maxprms-pcs2start # number of pcs in range start_num to end_num
|
344
|
+
prms_range = array_check(max_range,1) # array to represent pcs in range
|
345
|
+
return puts "ERROR1: range size too big for available memory." unless prms_range
|
346
|
+
end
|
347
|
+
prms = array_check(maxpcs,1) # array for pcs upto sqrtN, or end_num
|
348
|
+
return puts "ERROR2: end_num too big for available memory." unless prms
|
349
|
+
|
350
|
+
# residues offsets to compute a pcs address in its resgroup in prms
|
364
351
|
pos =[]; rescnt.times {|i| pos[residues[i]] = i-1}
|
365
352
|
|
366
353
|
# Sieve of Zakiya (SoZ) to eliminate nonprimes from prms and prms_range
|
367
354
|
modk,r,k=0,0,0
|
368
355
|
pcs2sqrtN.times do |i| # sieve primes from pcs upto sqrt(end_num)
|
369
356
|
r +=1; if r > rescnt; r=1; modk +=mod; k +=1 end
|
370
|
-
|
371
|
-
|
372
|
-
prime = modk +
|
373
|
-
prmstep = prime * rescnt
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
nonprm = (k*(prime + ri) +
|
357
|
+
next unless prms[i] == 1 # when a prime location found
|
358
|
+
prm_r = residues[r] # its residue value is saved
|
359
|
+
prime = modk + prm_r # its value is numerated
|
360
|
+
prmstep = prime * rescnt # its primestep computed
|
361
|
+
kcon = k * prmstep # its inner loop constant computed
|
362
|
+
residues[1..-1].each do |ri|# now perform sieve with it
|
363
|
+
# convert (prime * (modk + ri)) pc value to its address in prms
|
364
|
+
# computed as nonprm = (k*(prime + ri) + kn)*rescnt + pos[rr]
|
365
|
+
kn,rr = (prm_r * ri).divmod mod # residues product res[group|track]
|
366
|
+
nonprm =kcon + (k*ri + kn)*rescnt + pos[rr] # 1st prime multiple address with ri
|
378
367
|
while nonprm < maxpcs; prms[nonprm]=0; nonprm +=prmstep end
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
368
|
+
if split_arrays # when start_num > sqrtN
|
369
|
+
nonprm = (pcs2start - nonprm)%prmstep # (start_num - last multiple) pcs
|
370
|
+
nonprm = prmstep - nonprm if nonprm != 0 # location in range, or beyond
|
371
|
+
while nonprm < max_range; prms_range[nonprm]=0; nonprm += prmstep end
|
372
|
+
end
|
384
373
|
end
|
385
374
|
end
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
while modk + residues[r] < start_num; r +=1 end # r in ks >= start_num
|
390
|
-
|
391
|
-
[prms, m=r-1, mod, modk, residues, rescnt, maxprms, r] # parameter output
|
375
|
+
# determine prms array parameters and starting location value m for start_num
|
376
|
+
split_arrays ? (prms = prms_range; maxprms = max_range; m=0) : m=pcs2start
|
377
|
+
[prms, m, modks, residues, rescnt, pcs2start, maxprms, rs] # parameters output
|
392
378
|
end
|
393
379
|
|
394
380
|
def approximate_nth(n) # approximate nthprime value >= real value
|
@@ -397,14 +383,14 @@ module Primes
|
|
397
383
|
(n*(Math.log(n)+a)+3).to_i # use nth approximation as end_num of range
|
398
384
|
end
|
399
385
|
|
400
|
-
def set_start_value(n, hshflag) # find largest index nthprime|val <=
|
386
|
+
def set_start_value(n, hshflag) # find largest index nthprime|val <= n
|
401
387
|
if hshflag
|
402
388
|
return [nths[n], 0, true] if nths.has_key? n # if n is key in nths table
|
403
|
-
|
389
|
+
nth = nths.keys.sort.reverse.detect {|k| k < n} # find largest indexed key < n
|
404
390
|
[nth ? nths[nth] : 0, nth ||= n+1, false] # [start_num, nth, false]
|
405
391
|
else
|
406
392
|
return [0,nths.key(n),false] if nths.has_value? n # if n is value in nths table
|
407
|
-
|
393
|
+
v=val= nths.values.sort.reverse.detect {|v| v < n} # find largest indexed val < n
|
408
394
|
[v ||= 0, val ? nths.key(val) : 0, true] # [start_num, nth, true]
|
409
395
|
end
|
410
396
|
end
|
@@ -467,9 +453,19 @@ module Primes
|
|
467
453
|
1987500000=>46748693981, 2000000000=>47055833459, 2012500000=>47363059687
|
468
454
|
}
|
469
455
|
end
|
456
|
+
|
457
|
+
def select_pg(num, start_num) # adaptively select PG
|
458
|
+
primes = [2, 3, 5]
|
459
|
+
primes = num > 10**8 ? [2,3,5,7,11] : [2,3,5,7] if start_num < 3
|
460
|
+
[primes, primes.reduce(:*)] # [excluded primes, mod] for PG
|
461
|
+
end
|
462
|
+
|
463
|
+
def array_check(n,v) # catch out-of-memory errors on array creation
|
464
|
+
begin Array.new(n,v) rescue return end # return an array or nil
|
465
|
+
end
|
470
466
|
end
|
471
467
|
end
|
472
468
|
|
473
469
|
class Integer; include Primes::Utils end
|
474
|
-
|
470
|
+
|
475
471
|
puts "Available methods are: #{0.primes_utils}" # display methods upon loading
|
data/lib/primes/utils/version.rb
CHANGED
data/primes-utils.gemspec
CHANGED
@@ -10,7 +10,7 @@ Gem::Specification.new do |spec|
|
|
10
10
|
spec.email = ["jzakiya@gmail.com"]
|
11
11
|
|
12
12
|
spec.summary = %q{suite of extremely fast utility methods for testing and generating primes}
|
13
|
-
spec.description = %q{Methods: prime?, primemr?, primes, primesf, primesmr, primescnt, primescntf, primescntmr, primenth|nthprime, factors|prime_division}
|
13
|
+
spec.description = %q{Methods: prime?, primemr?, primes, primesf, primesmr, primescnt, primescntf, primescntmr, primenth|nthprime, factors|prime_division, primes_utils}
|
14
14
|
spec.homepage = "https://github.com/jzakiya/primes-utils"
|
15
15
|
|
16
16
|
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: primes-utils
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jabari Zakiya
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-10-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -39,7 +39,7 @@ dependencies:
|
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '10.0'
|
41
41
|
description: 'Methods: prime?, primemr?, primes, primesf, primesmr, primescnt, primescntf,
|
42
|
-
primescntmr, primenth|nthprime, factors|prime_division'
|
42
|
+
primescntmr, primenth|nthprime, factors|prime_division, primes_utils'
|
43
43
|
email:
|
44
44
|
- jzakiya@gmail.com
|
45
45
|
executables: []
|
@@ -76,7 +76,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
76
76
|
version: '0'
|
77
77
|
requirements: []
|
78
78
|
rubyforge_project:
|
79
|
-
rubygems_version: 2.4.
|
79
|
+
rubygems_version: 2.4.8
|
80
80
|
signing_key:
|
81
81
|
specification_version: 4
|
82
82
|
summary: suite of extremely fast utility methods for testing and generating primes
|