primes-utils 2.3.0 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|