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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ff3c9d871e492288cbbfac6beb023fd765f9bf8e
4
- data.tar.gz: 976926b10063c0fc58ea29b33765b800c937727f
3
+ metadata.gz: 72ccd5984ebd121f01d0846f5e6cd178fd7b007e
4
+ data.tar.gz: 6a484343ab2c7b047f382d4b104119c9888a5779
5
5
  SHA512:
6
- metadata.gz: 5e1b3235a3252ce746a1ba5210060fc9b73998a4b4b789ce37a1bf85a8591ac4bc7f70d76250ac34a71538705c8e2d06f906b15db440ae27e6b555c33fea491b
7
- data.tar.gz: cd933f765848c9d5777aa34f677a85c01b3f591205eceb545cd523cd159db5c42381ca27d8044d1ef1f38ce8bd9a472fa93036a37f225cfcd8581fd469e2b28a
6
+ metadata.gz: ee5446beb5818aaee204b7ea525ab97e5c52e47be2f9e739594a54cc9863a8a4dacbaf074219ea8e634c098bac32d33d4f879c8c81f60770a79df27c5b11f63c
7
+ data.tar.gz: 655f6c271d60b538597c861733f48e36683cb61b72cf577d0c9f53a0e0f7498767dc49b964c64599bf3d775d4ae6ca4c814e12035601724fee6261ed3036829a
data/.gitignore CHANGED
@@ -12,4 +12,5 @@
12
12
  *.odt
13
13
  *.odt#
14
14
  *.pdf
15
- *test*.*
15
+ *test*.*
16
+ *.ods
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 handle when array creation requires more memory than available.
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 `nthprime|primenth`, `primes`, and `primescnt`.
159
- `nthprime|primenth` also displays the error message `<yyyy> not enough primes, approx nth too small.`
160
- (where `<yyyy>` is an integer value) when the computed approx_nth value < nth value.
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
@@ -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 if !residues.include?(n%mod) or n == 1
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 sozP13 Sieve of Zakiya (SoZ) as default Prime Generator
103
+ # Uses P13 SP PG as default Prime Generator
105
104
  seeds = [2, 3, 5, 7, 11, 13, 17, 19]
106
- p = 13 if !seeds.include? p
105
+ p = 13 unless seeds.include? p
107
106
 
108
107
  primes = seeds[0..seeds.index(p)]
109
- mod = primes.reduce(:*) # modulus: modPn = 2*3*5*7*..*Pn
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 == 0
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 if !seeds.include? p
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, mod, modk, residues, rescnt, * = sozcore2(num, start_num, primes)
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 + rescnt*(modk/mod)).divmod rescnt # (m+pcs2ks).divmod rescnt
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
- # Uses the P5 Strictly Prime (SP) Prime Generator
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 = [2,3,5] # P5 excluded primes lists
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, mod, modk, residues, rescnt, maxprms, r = sozcore2(num, start_num, primes)
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
- # starting at start_num's location, extract primes within given range
181
- primes = start_num <= plast ? primes.select {|p| p >= start_num} : []
182
- while m < maxprms # find primes from pcs within given range
183
- primes << modk + residues[r] if prms[m] == 1
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
- m +=1
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
- seeds = [2, 3, 5, 7, 11, 13]
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 if !nthflag # output nth's number if n a ref nth prime
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] # choose P7 or P5
206
- prms, m, * = sozcore2(num, start_num, primes)
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
- # starting at start_num's location, count primes within given range
210
- prmcnt = start_num <= plast ? primes.select {|p| p >= start_num}.size : 0
211
- prmcnt = nth > 0 ? nth-1 : primes.size if nthflag # nflag is nil or true
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 n == 2 or n == 3
224
- return false if n % 6 != 1 && n % 6 != 5 or n == 1
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) {|i| residues << i if mod.gcd(i) == 1}
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
- def pcs_to_num(num,mod,rescnt,residues) # find number of pcs upto num
289
- num = num-1 | 1 # if N even number then subtract 1
290
- k=num/mod; modk = mod*k; r=1 # init parameters for kth resgroup
291
- while num >= modk+residues[r]; r += 1 end # find pc location r >= num
292
- rescnt*k + r-1 # max number of pcs <= num
293
- end
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] # P13 excluded primes lists
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, mod, rescnt, residues) # num of pcs <= end_num
309
+ maxpcs,* = pcs_to_num(num,mod,rescnt,residues,true) # num pcs <= end_num
318
310
 
319
- # compute parameters for start location and number of pcs within range
320
- primes = start_num <= plast ? primes.select {|p| p >= start_num} : []
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 for given Prime Generator and return array of parameters
327
- # inputs: end_num and start_num of range; excluded primes array for PG
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 - r-1, num of pcs in ks before start_num residue r
330
- # mod - modulus value for PG
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 < mod
334
- # maxprms - the number of pcs in range to find primes from
335
- # r - first residue index location in ks >= start_num
336
-
337
- def sozcore2(num, start_num, primes)
338
- mod = primes.reduce(:*) # modulus: modPn = 2*3*5*7*..*Pn
339
- residues, rescnt = make_residues_rescnt(mod)
340
- maxprms = pcs_to_num(num,mod,rescnt,residues) # num of pcs <= end_num
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 of pcs <= sqrtN
344
-
345
- ks = (start_num-2).abs/mod # start_num's resgroup value
346
- maxpcs = maxprms # if ks = 0 use this for prms array
347
- begin # start arrays mem error handling block
348
- if ks > 0 # if start_num > mod+1
349
- maxpcs = pcs2sqrtN # find primes in pcs upto sqrtN
350
- pcs2ks = rescnt*ks # number of pcs upto ks resgroup
351
- max_range =maxprms-pcs2ks # number of pcs from ks resgroup to end_num
352
- begin
353
- prms_range = Array.new(max_range,1) # pc array to hold range primes
354
- rescue # for not enough memory error for prms_range
355
- return puts "ERROR1: range size too big for available memory."
356
- end
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
- next unless prms[i]==1
371
- res_r = residues[r]
372
- prime = modk + res_r
373
- prmstep = prime * rescnt
374
- residues[1..-1].each do |ri|
375
- # compute (prime * (modk + ri)) position index in prms
376
- kk,rr = (res_r * ri).divmod mod # residues product res[group|track]
377
- nonprm = (k*(prime + ri) + kk)*rescnt + pos[rr] # 1st prime multiple
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
- if ks > 0
380
- nonprm = (pcs2ks - nonprm)%prmstep # translate current prime to ks
381
- nonprm = prmstep - nonprm if nonprm != 0 # determine its location
382
- while nonprm < max_range; prms_range[nonprm]=0; nonprm += prmstep end
383
- end
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
- if ks > 0; prms = prms_range; maxprms = max_range end
388
- r=1; modk = mod*ks # find 1st residue val|location
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 <= requested
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
- nth = nths.keys.sort.select {|k| k < n}.last # find largest indexed key < n
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
- v=val = nths.values.sort.select {|v| v < n}.last # find largest indexed val < n
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
@@ -1,5 +1,5 @@
1
1
  module Primes
2
2
  module Utils
3
- VERSION = "2.3.0"
3
+ VERSION = "2.4.0"
4
4
  end
5
5
  end
@@ -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.3.0
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-07-01 00:00:00.000000000 Z
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.6
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