primes-utils 2.1.0 → 2.2.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: 20d402c81ad58631f39bc633f955bde445f90e20
4
- data.tar.gz: c4ab24dc642cd906197b519d70944330c98012ee
3
+ metadata.gz: 63a02f55e631a8d239a409e4b140d5323a45cdec
4
+ data.tar.gz: aeab7ca1a389c6462ef0657998032f9e95020bff
5
5
  SHA512:
6
- metadata.gz: 558148913ea88891ef1b5c4376fdf645f95c845474cdf04bcb13ff51b337a0b02f58eb230f7d029779f2d1c4a2a511743fee2c4212458b6a7dd6009c029e8acc
7
- data.tar.gz: f434c221fbe5756d665ae2ce2681c82ed8b504c31197836dcf37cc2ac111e7be32bea9ebecea0c71c7c06d508785781fd28b3ba041ec4915d4241374d413794c
6
+ metadata.gz: abe70b780cdf9efc202620c318e06373c710a46203393e4c7798df9502b48a5960ae7a07abafea4ffb2a8d837b3efdd308920a0006a581391eba06534f484caf
7
+ data.tar.gz: 74faf8fc525138bfc7e29454e986428ae6254ac002bde7596c194c6ee27078783f25f8140532bd8ba3491133a846e7b44d09acd80f57d3bf26ad24d043d297ab
data/.gitignore CHANGED
@@ -11,4 +11,5 @@
11
11
  .directory
12
12
  *.odt
13
13
  *.odt#
14
- *.pdf
14
+ *.pdf
15
+ *test*.*
data/README.md CHANGED
@@ -27,7 +27,7 @@ And then execute:
27
27
  Or install it yourself as:
28
28
 
29
29
  $ gem install primes-utils
30
-
30
+
31
31
  Then require as:
32
32
 
33
33
  require 'primes/utils'
@@ -66,8 +66,8 @@ The reliability can be increased by increasing the default input parameter of k=
66
66
  **factors(p=13) or prime_division(p=13)**
67
67
 
68
68
  Determine the prime factorization of the absolute value of an integer.
69
- This replaces the `prime division` method in the `prime.rb` standard library.
70
- Output is array of arrays of factors and exponents: [[p1,e1],[p2,e2]..[pn,en]]
69
+ This replaces the `prime_division` method in the `prime.rb` standard library.
70
+ Output is array of arrays of factors and exponents: [[p1,e1],[p2,e2]..[pn,en]].
71
71
  Default Strictly Prime (SP) Prime Generator (PG) used here is P13.
72
72
  Can change SP PG used on input. Acceptable primes range: [3 - 19].
73
73
 
@@ -85,9 +85,10 @@ Can change SP PG used on input. Acceptable primes range: [3 - 19].
85
85
  **primes(start=0), primesf(start=0), primesmr(start=0)**
86
86
 
87
87
  Return an array of primes within the absolute value range `(|start| - |end|)`.
88
- The order of the range doesn't matter if both given: `start.primes end <=> end.prime start`
88
+ The order of the range doesn't matter if both given: `start.primes end <=> end.prime start`.
89
89
  If only one parameter used, then all the primes upto that number will be returned.
90
90
  See `PRIMES-UTILS HANDBOOK` for details on best use practices.
91
+ Also see `Error Handling`.
91
92
 
92
93
  ```
93
94
  50.primes => [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47]
@@ -107,9 +108,10 @@ prms => [1000003, 1000033, 1000037, 1000039, 1000081, 1000099]
107
108
  **primescnt(start=0), primescntf(start=0), primescntmr(start=0)**
108
109
 
109
110
  Provide count of primes within the absolute value range `(|start| - |end|)`.
110
- The order of the range doesn't matter if both given: `start.primes end <=> end.prime start`
111
+ The order of the range doesn't matter if both given: `start.primes end <=> end.prime start`.
111
112
  If only one parameter used, the count of all the primes upto that number will be returned.
112
113
  See `PRIMES-UTILS HANDBOOK` for details on best use practices.
114
+ Also see `Error Handling`.
113
115
 
114
116
  ```
115
117
  100000.primescnt => 9592
@@ -125,8 +127,8 @@ n=10**400; (n-500).primescntmr(n+500) => 1
125
127
  Return the value of the (absolute value of) nth prime.
126
128
  Default Strictly Prime (SP) Prime Generator (PG) used here is P7.
127
129
  Can change SP PG used on input. Acceptable primes range: [3 - 13].
128
- Currently, parameters are set so that the 1122951705th prime is max.
129
- An error message will be given if requested nth prime is > than max.
130
+ Indexed nth primes now upto 1.6 billionth.
131
+ Also see `Error Handling`.
130
132
 
131
133
  ```
132
134
  1000000.primenth => 15485863
@@ -134,29 +136,42 @@ An error message will be given if requested nth prime is > than max.
134
136
  2000000.nthprime 11 => 32452843
135
137
  -500000.nthprime => 7368787
136
138
  1122951705.nthprime => 25741879847
137
- 1122951706.primenth => "1122951705 not enough primes, nth approx too small"
138
139
  0.nthprime => 0
140
+ 1.primenth => 2
139
141
  ```
140
142
 
141
143
  **primes_utils**
142
144
 
143
- Displays a list of all the `primes-utils` methods available for your system.
145
+ Displays a list of all the `primes-utils` methods available for your system.
144
146
  Use as `x.primes_utils` where x is any `class Integer` value.
145
147
 
146
148
  ```
147
149
  0.primes_utils => "prime? primemr? primes primesf primesmr primescnt primescntf primescntmr primenth|nthprime factors|prime_division"
148
150
  ```
149
151
 
152
+ ## Error Handling
153
+ Starting with 2.2.0, error handling has been implemented to gracefully handle when array creation requires more memory than available.
154
+ This occurs then the range size, or end_num, need arrays greater than the amount of avalable memory. The first case shows the message
155
+ `ERROR1: range size too big for available memory.` and the second case `ERROR2: end_num too big for available memory.`
156
+ The affected methods are `nthprime|primenth`, `primes`, and `primescnt`.
157
+ `nthprime|primenth` also displays the error message `<yyyy> not enough primes, approx nth too small.`
158
+ (where `<yyyy>` is an integer value) when the computed approx_nth value < nth value.
159
+ For all errors, the return value for each method is `nil`.
160
+
161
+ This behavior is referenced to MRI Ruby.
162
+
163
+
150
164
  ## Coding Implementations
151
- The methods `primemr?`, `nthprime/primenth`, `primes`, `primescnt`, `primesmr`, and `primescnt` are coded in pure ruby.
165
+ The methods `primemr?`, `nthprime|primenth`, `primes`, `primescnt`, `primesmr`, and `primescnt` are coded in pure ruby.
152
166
  The methods `prime?` and `prime_division|factors` have two implementations.
153
167
  Each has a pure ruby implementation, and a hybrid implementation using the Unix cli command `factor` if its available on the host OS.
154
168
  The methods `primesf` and `primescntf` use the `factor` version of `prime?` and are created if it exits.
155
169
  `factor` [5] is an extremely fast C coded factoring algorithm, part of the GNU Core Utilities package [4].
156
-
170
+
157
171
  Upon loading, the gem tests if the command `factor` exists on the host OS.
158
- If so, it performs a system call to it within `prime?` and `prime_division/factors`, which uses its output.
172
+ If so, it performs a system call to it within `prime?` and `prime_division|factors`, which uses its output.
159
173
  If not, each method uses a fast pure ruby implementation based on the Sieve of Zakiya (SoZ)[1][2][3].
174
+ New in 2.2.0, upon loading with Ruby 1.8 `require 'rubygems'` is invoked to enable installing gems.
160
175
 
161
176
  All the `primes-utils` methods are `instance_methods` for `class Integer`.
162
177
 
@@ -171,6 +186,5 @@ Jabari Zakiya
171
186
  [5]https://en.wikipedia.org/wiki/Factor_(Unix)
172
187
  [6]https://en.wikipedia.org/wiki/Miller-Rabin_primality_test
173
188
 
174
-
175
189
  ## License
176
190
  GPLv2+
@@ -1,5 +1,7 @@
1
+ # need rubygems to load gems, and rational for 'gcd' method for 1.8
2
+ %w/rubygems rational/.each{|r| require r} if RUBY_VERSION =~ /^(1.8)/
3
+
1
4
  require "primes/utils/version"
2
- require "rational" if RUBY_VERSION =~ /^(1.8)/ # for 'gcd' method
3
5
 
4
6
  module Primes
5
7
  module Utils
@@ -23,11 +25,11 @@ module Primes
23
25
  if os_has_factor # for platforms with cli 'factor' command
24
26
 
25
27
  def prime?
26
- `factor #{self.abs}`.split(' ').size == 2
28
+ `factor #{self.abs}`.split(' ').size == 2
27
29
  end
28
30
 
29
31
  def factors(p=0) # p is unused dummy variable for method consistency
30
- factors = `factor #{self.abs}`.split(' ')[1..-1].map {|i| i.to_i}
32
+ factors = `factor #{self.abs}`.split(' ')[1..-1].map(&:to_i)
31
33
  h = Hash.new(0); factors.each {|f| h[f] +=1}; h.to_a.sort
32
34
  end
33
35
 
@@ -98,7 +100,7 @@ module Primes
98
100
  end
99
101
 
100
102
  def factors(p=13)
101
- # Return prime factors of n in form [[p1,e1],[p2.e2]..[pn.en]]
103
+ # Return prime factors of n in form [[p1,e1],[p2,e2]..[pn,en]]
102
104
  # Uses sozP13 Sieve of Zakiya (SoZ) as default Prime Generator
103
105
  seeds = [2, 3, 5, 7, 11, 13, 17, 19]
104
106
  p = 13 if !seeds.include? p
@@ -112,9 +114,9 @@ module Primes
112
114
 
113
115
  return [] if n == 0
114
116
  return [[n,1]] if primes.include? n
115
- primes.each {|p| while n%p ==0; factors << p; n /= p end }
117
+ primes.each {|p| while n%p == 0; factors << p; n /= p end }
116
118
 
117
- sqrtN= Math.sqrt(n).to_i
119
+ sqrtN = Math.sqrt(n).to_i
118
120
  modk,r=0,1; p=residues[1] # first test prime pj
119
121
  while p <= sqrtN
120
122
  if n%p == 0
@@ -142,24 +144,22 @@ module Primes
142
144
  n = self.abs # the desired nth prime
143
145
  return n != 0 ? seeds[n-1] : 0 if n <= seeds.size
144
146
 
145
- start_num, nth, nthflag = set_start_value(n, nths)
147
+ start_num, nth, nthflag = set_start_value(n)
146
148
  return start_num if nthflag # output nthprime if nth ref value
147
149
 
148
150
  num = approximate_nth(n) # close approx to nth >= real nth
149
151
  primes = seeds[0..seeds.index(p)]
150
152
 
151
- ks, mod, residues, maxprms,
152
- max_range, prms, prms_range = sozcore2(num, start_num, primes)
153
-
153
+ prms, m, mod, modk, residues, * = sozcore2(num, start_num, primes)
154
+ return if prms == nil # exit gracefully if sozcore2 mem error
155
+
154
156
  rescnt = residues[1..-1].size
155
- pcs2ks = rescnt*ks
157
+ pcs2ks = rescnt*(modk/mod) # rescnt*ks - number of pcs upto ks resgroup
158
+
156
159
  # starting at start_num's location, find nth prime within given range
157
- prms = prms_range if ks > 0
158
160
  prmcnt = n > nth ? nth-1 : primes.size
159
- m=0; r=1; modk = mod*ks # find number of pcs, m, in ks < start_num
160
- while modk + residues[r] < start_num; r += 1; m +=1 end
161
161
  pcnt = prmcnt + prms[m..-1].count(1) # number of primes upto nth approx
162
- return "#{pcnt} not enough primes, nth approx too small" if pcnt < n
162
+ return puts "#{pcnt} not enough primes, approx nth too small." if pcnt < n
163
163
  while prmcnt < n; prmcnt +=1 if prms[m] == 1; m +=1 end
164
164
  k, r = (m+pcs2ks).divmod rescnt
165
165
  mod*k + residues[r]
@@ -177,23 +177,21 @@ module Primes
177
177
  plast = primes.last # last prime in primes
178
178
  return primes.select {|p| p >= start_num && p <= num} if num <= plast
179
179
 
180
- ks, mod, residues, maxprms,
181
- max_range, prms, prms_range = sozcore2(num, start_num, primes)
182
-
180
+ prms, m, mod, modk, residues, maxprms, r = sozcore2(num, start_num, primes)
181
+ return if prms == nil # exit gracefully if sozcore2 mem error
182
+
183
183
  rescnt = residues[1..-1].size
184
+
184
185
  # starting at start_num's location, extract primes within given range
185
186
  primes = start_num <= plast ? primes.drop_while {|p| p < start_num} : []
186
- if ks > 0; maxprms = max_range; prms = prms_range end
187
- m=0; r=1; modk = mod*ks; # find number of pcs, m, in ks < start_num
188
- while modk + residues[r] < start_num; r +=1; m +=1 end
189
- (maxprms-m).times do # find primes from this num pcs within range
187
+ while m < maxprms # find primes from pcs within given range
190
188
  primes << modk + residues[r] if prms[m] == 1
191
189
  r +=1; if r > rescnt; r=1; modk +=mod end
192
190
  m +=1
193
191
  end
194
192
  primes
195
193
  end
196
-
194
+
197
195
  def primescnt(start_num=0)
198
196
  # Count primes between a number range: end_num - start_num
199
197
  # Uses the P5 Strictly Prime (SP) Prime Generator
@@ -204,14 +202,11 @@ module Primes
204
202
  plast = primes.last # last prime in primes
205
203
  return primes.select {|p| p >= start_num && p <= num}.size if num <= plast
206
204
 
207
- ks, mod, residues, maxprms,
208
- max_range, prms, prms_range = sozcore2(num, start_num, primes)
205
+ prms, m, * = sozcore2(num, start_num, primes)
206
+ return if prms == nil # exit gracefully if sozcore2 mem error
209
207
 
210
208
  # starting at start_num's location, count primes within given range
211
209
  primes = start_num <= plast ? primes.drop_while {|p| p < start_num} : []
212
- prms = prms_range if ks > 0
213
- m=0; r=1; modk = mod*ks # find number of pcs, m, in ks < start_num
214
- while modk + residues[r] < start_num; r +=1; m +=1 end
215
210
  primecnt = primes.size + prms[m..-1].count(1)
216
211
  end
217
212
 
@@ -285,14 +280,14 @@ module Primes
285
280
  def make_residues_rescnt(mod)
286
281
  residues=[1]; 3.step(mod,2) {|i| residues << i if mod.gcd(i) == 1}
287
282
  residues << mod+1
288
- [residues, residues.size-1] # return residues array and rescnt
283
+ [residues, residues.size-1] # return residues array and rescnt
289
284
  end
290
285
 
291
286
  def pcs_to_num(num,mod,rescnt,residues) # find number of pcs upto num
292
- num = num-1 | 1 # if N even number then subtract 1
293
- k=num/mod; modk = mod*k; r=1 # kth residue group; base num value
294
- while num >= modk+residues[r]; r += 1 end # compute extra prms size
295
- k*rescnt + r-1 # max number of pcs <= num
287
+ num = num-1 | 1 # if N even number then subtract 1
288
+ k=num/mod; modk = mod*k; r=1 # init parameters for kth resgroup
289
+ while num >= modk+residues[r]; r += 1 end # find pc location r >= num
290
+ rescnt*k + r-1 # max number of pcs <= num
296
291
  end
297
292
 
298
293
  def pcs_to_start_num(start_num, mod, rescnt, residues)
@@ -300,8 +295,8 @@ module Primes
300
295
  modk = mod*k # start_num's mod group value
301
296
  m = rescnt*k # number of pcs upto kth resgroup
302
297
  r = 1 # find r,m for first pc >= start_num
303
- while modk + residues[r] < start_num; r +=1; m +=1 end
304
- [m, r, modk] # parameters for 1st pc >= start_num
298
+ while modk + residues[r] < start_num; r +=1 end
299
+ [m+r-1, r, modk] # parameters for 1st pc >= start_num
305
300
  end
306
301
 
307
302
  def sozcore1(num, start_num, method_flag)
@@ -325,6 +320,16 @@ module Primes
325
320
  [false, maxpcs-m, r, mod, modk, rescnt, residues, primes]
326
321
  end
327
322
 
323
+ # Perform SoZ for given Prime Generator and return array of parameters
324
+ # inputs: end_num and start_num of range; excluded primes array for PG
325
+ # outputs: prms - binary (0,1) array of pcs within a range or to end_num
326
+ # m - r-1, num of pcs in ks before start_num residue r
327
+ # mod - modulus value for PG
328
+ # modk - mod*ks; mod value for ks, start_num's resgroup
329
+ # residues - array of residues plus mod+1 for PG
330
+ # maxprms - the number of pcs in range to find primes from
331
+ # r - first residue location in ks >= start_num
332
+
328
333
  def sozcore2(num, start_num, primes)
329
334
  mod = primes.reduce(:*) # modulus: modPn = 2*3*5*7*..*Pn
330
335
  residues, rescnt = make_residues_rescnt(mod)
@@ -335,13 +340,21 @@ module Primes
335
340
 
336
341
  ks = (start_num-2).abs/mod # start_num's resgroup value
337
342
  maxpcs = maxprms # if ks = 0 use this for prms array
338
- if ks > 0 # if start_num > mod+1
339
- maxpcs = pcs2sqrtN # find primes in pcs upto sqrtN
340
- pcs2ks = rescnt*ks # number of pcs upto ks resgroup
341
- max_range = maxprms-pcs2ks # number of pcs from ks resgroup to end_num
342
- prms_range = Array.new(max_range,1) # pc array to generate range primes
343
- end
344
- prms=Array.new(maxpcs,1) # for primes upto sqrtN and end_num if ks=0
343
+ begin # start arrays mem error handling block
344
+ if ks > 0 # if start_num > mod+1
345
+ maxpcs = pcs2sqrtN # find primes in pcs upto sqrtN
346
+ pcs2ks = rescnt*ks # number of pcs upto ks resgroup
347
+ max_range =maxprms-pcs2ks # number of pcs from ks resgroup to end_num
348
+ begin
349
+ prms_range = Array.new(max_range,1) # pc array to hold range primes
350
+ rescue # for not enough memory error for prms_range
351
+ return puts "ERROR1: range size too big for available memory."
352
+ end
353
+ end
354
+ prms=Array.new(maxpcs,1) # for primes upto sqrtN and end_num if ks=0
355
+ rescue # for not enough memory error for prms
356
+ return puts "ERROR2: end_num too big for available memory."
357
+ end # method return value is `nil` upon error
345
358
 
346
359
  # hash of residues offsets to compute nonprimes positions in prms
347
360
  pos =[]; rescnt.times {|i| pos[residues[i]] = i-1}
@@ -360,27 +373,32 @@ module Primes
360
373
  nonprm = (k*(prime + ri) + kk)*rescnt + pos[rr] # 1st prime multiple
361
374
  while nonprm < maxpcs; prms[nonprm]=0; nonprm +=prmstep end
362
375
  if ks > 0
363
- nonprm = (pcs2ks - nonprm)%prmstep
364
- nonprm = prmstep - nonprm if nonprm != 0
376
+ nonprm = (pcs2ks - nonprm)%prmstep # translate current prime to ks
377
+ nonprm = prmstep - nonprm if nonprm != 0 # determine its location
365
378
  while nonprm < max_range; prms_range[nonprm]=0; nonprm += prmstep end
366
379
  end
367
380
  end
368
381
  end
369
- [ks, mod, residues, maxprms, max_range, prms, prms_range]
382
+
383
+ if ks > 0; prms = prms_range; maxprms = max_range end
384
+ r=1; modk = mod*ks # find 1st residue val|location
385
+ while modk + residues[r] < start_num; r +=1 end # r in ks >= start_num
386
+
387
+ [prms, m=r-1, mod, modk, residues, maxprms, r] # parameter output
370
388
  end
371
389
 
372
- def approximate_nth(n, b=0.686) # approximate nthprime value >= real value
373
- b=0.6863 if n > 1064000000 # good upto nth <= 1122951705
390
+ def approximate_nth(n) # approximate nthprime value >= real value
391
+ b = 0.5722*n**0.0088 # derived equation to compute close nth values
374
392
  a = b*(Math.log(Math.log(n)))
375
- (n*(Math.log(n)+a)+1).to_i
393
+ (n*(Math.log(n)+a)+3).to_i # use nth approximation as end_num of range
376
394
  end
377
395
 
378
- def set_start_value(n, nths) # find closest nth|nthprime val <= requested
379
- nthkeys = nths.keys.sort
380
- return [nths[n], 0, true] if nthkeys.include? n # if nth in nths table
396
+ def set_start_value(n) # find closest index nthprime <= requested nth
397
+ nthkeys = nths.keys.sort # create array of indexed nth numbers
398
+ return [nths[n], 0, true] if nthkeys.include? n # if n in nths table
381
399
  start_num, nth = 0, nthkeys[0]
382
400
  nthkeys.each {|i| start_num, nth = nths[i], i if n > i}
383
- [start_num, nth, false]
401
+ [start_num, nth, false] # use index prime value as start_num of range
384
402
  end
385
403
 
386
404
  def nths # hash table index of reference nth primes
@@ -414,7 +432,20 @@ module Primes
414
432
  975000000 =>22205818561, 987500000 =>22503733657, 1000000000=>22801763489,
415
433
  1012500000=>23099993743, 1025000000=>23398391231, 1037500000=>23696858797,
416
434
  1050000000=>23995554823, 1062500000=>24294392179, 1075000000=>24593421187,
417
- 1087500000=>24892587403, 1100000000=>25191867719, 1112500000=>25491361037
435
+ 1087500000=>24892587403, 1100000000=>25191867719, 1112500000=>25491361037,
436
+ 1125000000=>25790970053, 1137500000=>26090709563, 1150000000=>26390560513,
437
+ 1162500000=>26690560601, 1175000000=>26990744987, 1187500000=>27291009337,
438
+ 1200000000=>27591444869, 1212500000=>27892051267, 1225000000=>28192760279,
439
+ 1237500000=>28493648629, 1250000000=>28794583627, 1262500000=>29095694269,
440
+ 1275000000=>29396966971, 1287500000=>29698366099, 1300000000=>29999858327,
441
+ 1312500000=>30301430881, 1325000000=>30603183581, 1337500000=>30905024497,
442
+ 1350000000=>31207047449, 1362500000=>31509131153, 1375000000=>31811397571,
443
+ 1387500000=>32113702069, 1400000000=>32416190071, 1412500000=>32718790873,
444
+ 1425000000=>33021414143, 1437500000=>33324275711, 1450000000=>33627220709,
445
+ 1462500000=>33930284893, 1475000000=>34233442279, 1487500000=>34536683891,
446
+ 1500000000=>34840062373, 1512500000=>35143545889, 1525000000=>35447088559,
447
+ 1537500000=>35750747297, 1550000000=>36054501641, 1562500000=>36358440731,
448
+ 1575000000=>36662430631, 1587500000=>36966563321, 1600000000=>37270791697
418
449
  }
419
450
  end
420
451
  end
@@ -1,5 +1,5 @@
1
1
  module Primes
2
2
  module Utils
3
- VERSION = "2.1.0"
3
+ VERSION = "2.2.0"
4
4
  end
5
5
  end
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.1.0
4
+ version: 2.2.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-05-25 00:00:00.000000000 Z
11
+ date: 2015-06-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -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.2.2
80
80
  signing_key:
81
81
  specification_version: 4
82
82
  summary: suite of extremely fast utility methods for testing and generating primes