primes-utils 2.7.0 → 3.0.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 +5 -5
- data/README.md +111 -82
- data/lib/primes/utils/version.rb +1 -1
- data/lib/primes/utils.rb +424 -377
- data/{primes-utils.gemspec → primes-utils-3.0.0.gemspec} +6 -10
- metadata +29 -14
- data/.gitignore +0 -16
data/lib/primes/utils.rb
CHANGED
|
@@ -1,473 +1,520 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
1
|
+
# Enable YJIT if using CRuby >= 3.3"
|
|
2
|
+
RubyVM::YJIT.enable if RUBY_ENGINE == "ruby" and RUBY_VERSION.to_f >= 3.3
|
|
3
3
|
|
|
4
|
-
require "
|
|
4
|
+
require "bitarray"
|
|
5
5
|
|
|
6
6
|
module Primes
|
|
7
7
|
module Utils
|
|
8
8
|
# Upon loading, determine if platform has cli command 'factor'
|
|
9
|
-
|
|
9
|
+
|
|
10
10
|
@@os_has_factor = false
|
|
11
11
|
begin
|
|
12
|
-
if `factor 10`.split(' ') == [
|
|
12
|
+
if `factor 10`.split(' ') == ['10:', '2', '5']
|
|
13
13
|
@@os_has_factor = true
|
|
14
14
|
end
|
|
15
15
|
rescue
|
|
16
16
|
@@os_has_factor = false
|
|
17
17
|
end
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
begin RUBY = RUBY_ENGINE rescue RUBY = 'ruby'.freeze end
|
|
20
|
+
#RUBY = `ruby -v`.split[0] # alternative old way
|
|
21
|
+
|
|
20
22
|
if @@os_has_factor # for platforms with cli 'factor' command
|
|
21
23
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
+
# Return prime factors of n in form [[-1,1],[p1,e1],...[pn,en]]
|
|
25
|
+
# Use Linux|Unix coreutils cli command 'factor' for speed and large numbers
|
|
26
|
+
def factors
|
|
27
|
+
factors = self < 0 ? [-1] : []
|
|
28
|
+
factors += `factor #{abs}`.split(' ')[1..-1].map(&:to_i)
|
|
29
|
+
factors.group_by { |prm| prm }.map { |prm, exp| [prm, exp.size] }
|
|
24
30
|
end
|
|
25
31
|
|
|
26
|
-
|
|
27
|
-
factors = `factor #{self.abs}`.split(' ')[1..-1].map(&:to_i)
|
|
28
|
-
h = Hash.new(0); factors.each {|f| h[f] +=1}; h.to_a.sort
|
|
29
|
-
end
|
|
32
|
+
alias prime_division factors
|
|
30
33
|
|
|
31
|
-
|
|
32
|
-
# List primes within a number range: end_num - start_num
|
|
33
|
-
# Uses 'prime?' to check primality of prime candidates in range
|
|
34
|
-
sozdata = sozcore1(self, start_num, true) # true for primes list
|
|
35
|
-
pcs_in_range, r, mod, modk, rescnt, residues, primes = sozdata
|
|
34
|
+
puts "Using cli 'factor' for factors|prime_division"
|
|
36
35
|
|
|
37
|
-
|
|
38
|
-
prime = modk + residues[r]
|
|
39
|
-
primes << prime if prime.prime?
|
|
40
|
-
r +=1; if r > rescnt; r=1; modk +=mod end
|
|
41
|
-
end
|
|
42
|
-
primes
|
|
43
|
-
end
|
|
36
|
+
end # use pure ruby versions for platforms without cli command 'factor'
|
|
44
37
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
38
|
+
# Return prime factors of n in form [[-1,1],[p1,e1],..[pn,en]]
|
|
39
|
+
# Adaptively selects optimum PG of reduced factored number, if possible
|
|
40
|
+
def factors1
|
|
41
|
+
modpg, rescnt = 210, (48 + 4) # P7's modulus and residues count
|
|
42
|
+
residues = [2,3,5,7, 11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,
|
|
43
|
+
97,101,103,107,109,113,121,127,131,137,139,143,149,151,157,163,
|
|
44
|
+
167,169,173,179,181,187,191,193,197,199,209,211]
|
|
50
45
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
r +=1; if r > rescnt; r=1; modk +=mod end
|
|
54
|
-
end
|
|
55
|
-
primescnt
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
puts "Using cli 'factor' for prime? primesf primescntf factors|prime_division"
|
|
59
|
-
|
|
60
|
-
else # use pure ruby versions for platforms without cli command 'factor'
|
|
61
|
-
|
|
62
|
-
def prime? # Uses P7 Strictly Prime Generator
|
|
63
|
-
residues = [1,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,
|
|
64
|
-
83,89,97,101,103,107,109,113,121,127,131,137,139,143,149,151,157,
|
|
65
|
-
163,167,169,173,179,181,187,191,193,197,199,209,211]
|
|
66
|
-
mod=210; # rescnt=48
|
|
67
|
-
|
|
68
|
-
n = self.abs
|
|
69
|
-
is_a_pc = residues.include?(n%mod) # true if n is a prime candidate
|
|
70
|
-
return false unless (n > 1 and is_a_pc) or [2,3,5,7].include? n
|
|
71
|
-
return true if n <= 211 and not [121,143,169,187,209].include? n
|
|
72
|
-
|
|
73
|
-
sqrtN = Math.sqrt(n).to_i
|
|
74
|
-
p=11 # first test prime pj
|
|
75
|
-
while p <= sqrtN
|
|
76
|
-
return false if
|
|
77
|
-
n%(p) == 0 or n%(p+2) ==0 or n%(p+6) == 0 or n%(p+8) ==0 or
|
|
78
|
-
n%(p+12) == 0 or n%(p+18) ==0 or n%(p+20) == 0 or n%(p+26) ==0 or
|
|
79
|
-
n%(p+30) == 0 or n%(p+32) ==0 or n%(p+36) == 0 or n%(p+42) ==0 or
|
|
80
|
-
n%(p+48) == 0 or n%(p+50) ==0 or n%(p+56) == 0 or n%(p+60) ==0 or
|
|
81
|
-
n%(p+62) == 0 or n%(p+68) ==0 or n%(p+72) == 0 or n%(p+78) ==0 or
|
|
82
|
-
n%(p+86) == 0 or n%(p+90) ==0 or n%(p+92) == 0 or n%(p+96) ==0 or
|
|
83
|
-
n%(p+98) == 0 or n%(p+102)==0 or n%(p+110)== 0 or n%(p+116)==0 or
|
|
84
|
-
n%(p+120)== 0 or n%(p+126)==0 or n%(p+128)== 0 or n%(p+132)==0 or
|
|
85
|
-
n%(p+138)== 0 or n%(p+140)==0 or n%(p+146)== 0 or n%(p+152)==0 or
|
|
86
|
-
n%(p+156)== 0 or n%(p+158)==0 or n%(p+162)== 0 or n%(p+168)==0 or
|
|
87
|
-
n%(p+170)== 0 or n%(p+176)==0 or n%(p+180)== 0 or n%(p+182)==0 or
|
|
88
|
-
n%(p+186)== 0 or n%(p+188)==0 or n%(p+198)== 0 or n%(p+200)==0
|
|
89
|
-
p += mod # first prime candidate for next kth residues group
|
|
90
|
-
end
|
|
91
|
-
true # n is prime (100%|deterministically)
|
|
92
|
-
end
|
|
46
|
+
factors = self < 0 ? [-1] : [] # returns [] for 0|1; [-1, 1] for negatives
|
|
47
|
+
num = self.abs # factor only non-negative integers
|
|
93
48
|
|
|
94
|
-
|
|
95
|
-
#
|
|
96
|
-
#
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
n = self.abs # number to factor
|
|
105
|
-
factors = [] # init empty factors array
|
|
106
|
-
|
|
107
|
-
return [] if n < 2
|
|
108
|
-
return [[n,1]] if primes.include? n
|
|
109
|
-
primes.each {|p| while n%p == 0; factors << p; n /= p end }
|
|
110
|
-
|
|
111
|
-
sqrtN = Math.sqrt(n).to_i
|
|
112
|
-
modk,r=0,1
|
|
113
|
-
while (p = modk+residues[r]) <= sqrtN
|
|
114
|
-
if n%p == 0
|
|
115
|
-
factors << p; r -=1; n /= p; sqrtN = Math.sqrt(n).to_i
|
|
116
|
-
end
|
|
117
|
-
r +=1; if r > rescnt; r=1; modk +=mod end
|
|
118
|
-
end
|
|
119
|
-
factors << n if n > 1
|
|
120
|
-
h=Hash.new(0); factors.each {|f| h[f] +=1}; h.to_a.sort
|
|
121
|
-
end
|
|
122
|
-
|
|
123
|
-
puts "Using pure ruby versions for all methods"
|
|
49
|
+
unless num.prime? || (num | 1) == 1 # skip factoring if num is prime, 0, or 1
|
|
50
|
+
modk, r, r0 = 0, 0, 4 # r0 is index for P7's first residue 11
|
|
51
|
+
until num.prime? || num == 1 # find factors until num is prime or 1
|
|
52
|
+
while prime = modk + residues[r]
|
|
53
|
+
(factors << prime; num /= prime; break) if (num % prime).zero?
|
|
54
|
+
(r = r0; modk += modpg) if (r = r.succ) == rescnt
|
|
55
|
+
end end end
|
|
56
|
+
factors << num if num > 1
|
|
57
|
+
factors.group_by{ |prm| prm}.map{ |prm, exp| [prm, exp.size] }
|
|
124
58
|
end
|
|
125
59
|
|
|
126
|
-
#
|
|
127
|
-
alias
|
|
60
|
+
# Use pure Ruby version of `factor` if not in OS.
|
|
61
|
+
alias prime_division factors1 unless @@os_has_factor
|
|
128
62
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
63
|
+
# Return value of nth prime for self > 0, 0 if self = 0, or nil if self < 0
|
|
64
|
+
# Adaptively selects best SP PG, unless valid input PG given at runtime
|
|
65
|
+
def primenth(p = 0)
|
|
66
|
+
return nil if (n = self) < 0
|
|
132
67
|
seeds = [2, 3, 5, 7, 11, 13]
|
|
133
|
-
|
|
68
|
+
return n > 0 ? seeds[n - 1] : 0 if n <= seeds.size
|
|
134
69
|
|
|
135
|
-
|
|
136
|
-
return
|
|
70
|
+
start_num, nth, nthflag = set_start_value(n, true)
|
|
71
|
+
return start_num if nthflag # output nthprime value if n a ref prime key
|
|
72
|
+
end_num = approximate_nth(n) # close approx to nth >= real nth
|
|
137
73
|
|
|
138
|
-
|
|
139
|
-
|
|
74
|
+
(primes = seeds[0..seeds.index(p)]; modpg = primes.reduce(:*)) if seeds.include? p
|
|
75
|
+
primes, modpg = select_pg(end_num, start_num) unless primes
|
|
140
76
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
prms, m, modk, residues, rescnt, pcs2start, * = sozcore2(num, start_num, mod)
|
|
144
|
-
return unless prms # exit gracefully if sozcore2 mem error
|
|
77
|
+
prms, m, _, residues, pcs2start, * = sozcore2(end_num, start_num, modpg)
|
|
78
|
+
return unless prms # exit gracefully if sozcore2 mem error
|
|
145
79
|
|
|
146
80
|
# starting at start_num's location, find nth prime within given range
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
k, r = (m + pcs2start).divmod
|
|
152
|
-
|
|
81
|
+
pcnt = n > nth ? nth - 1 : primes.size
|
|
82
|
+
max = prms.size
|
|
83
|
+
while pcnt < n && m < max; pcnt = pcnt.succ if prms[m].zero?; m = m.succ end
|
|
84
|
+
return puts "#{pcnt} not enough primes, ~nth val too small." if pcnt < n
|
|
85
|
+
k, r = (m + pcs2start - 1).divmod residues.size
|
|
86
|
+
modpg * k + residues[r]
|
|
153
87
|
end
|
|
154
88
|
|
|
155
|
-
alias nthprime primenth
|
|
89
|
+
alias nthprime primenth # to make life easier
|
|
156
90
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
num, start_num = start_num, num if start_num > num
|
|
91
|
+
# List primes between a number range: end_num - start_num
|
|
92
|
+
# Adaptively selects Strictly Prime (SP) Prime Generator
|
|
93
|
+
def primes(start_num = 0)
|
|
94
|
+
end_num, start_num = check_inputs(self, start_num)
|
|
162
95
|
|
|
163
|
-
primes,
|
|
164
|
-
prms, m, modk, residues,
|
|
165
|
-
return unless prms
|
|
96
|
+
primes, modpg = select_pg(end_num, start_num) # adaptively select PG
|
|
97
|
+
prms, m, modk, residues, _, r = sozcore2(end_num, start_num, modpg)
|
|
98
|
+
return unless prms # exit gracefully if sozcore2 mem error
|
|
99
|
+
rescnt, modpg, maxprms = residues.size, residues[-1] - 1, prms.size
|
|
166
100
|
|
|
167
|
-
# init 'primes' w/any excluded primes in range
|
|
168
|
-
primes.select! {|p| p >= start_num && p <=
|
|
169
|
-
|
|
101
|
+
# init 'primes' w/any excluded primes in range, extract primes from prms
|
|
102
|
+
primes.select! { |p| p >= start_num && p <= end_num }
|
|
103
|
+
|
|
104
|
+
# Find, numerate, and store primes from sieved pcs in prms for range
|
|
105
|
+
while m < maxprms
|
|
170
106
|
begin
|
|
171
|
-
primes << modk + residues[r] if prms[m]
|
|
107
|
+
primes << modk + residues[r] if prms[m].zero?; m = m.succ
|
|
172
108
|
rescue Exception
|
|
173
|
-
return puts
|
|
109
|
+
return puts 'ERROR3: not enough sys memory for primes output array.'
|
|
174
110
|
end
|
|
175
|
-
r
|
|
176
|
-
m +=1
|
|
111
|
+
(r = 0; modk += modpg) if (r = r.succ) == rescnt
|
|
177
112
|
end
|
|
178
113
|
primes
|
|
179
114
|
end
|
|
180
115
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
num, start_num = start_num, num if start_num > num
|
|
116
|
+
# Count primes between a number range: end_num - start_num
|
|
117
|
+
# Adaptively selects Strictly Prime (SP) Prime Generator
|
|
118
|
+
def primescnt(start_num = 0)
|
|
119
|
+
end_num, start_num = check_inputs(self, start_num)
|
|
186
120
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
121
|
+
nthflag, nth = 0, 0
|
|
122
|
+
if start_num < 3 # for all primes upto num
|
|
123
|
+
start_num, nth, nthflag = set_start_value(end_num, false) # closest nth value
|
|
124
|
+
return nth unless nthflag # output num's key|count if ref nth value
|
|
190
125
|
end
|
|
191
126
|
|
|
192
|
-
primes,
|
|
193
|
-
prms, m,
|
|
194
|
-
return unless prms
|
|
127
|
+
primes, modpg = select_pg(end_num, start_num) # adaptively select PG
|
|
128
|
+
prms, m, _ = sozcore2(end_num, start_num, modpg)
|
|
129
|
+
return unless prms # exit gracefully if sozcore2 mem error
|
|
195
130
|
|
|
196
|
-
# init prmcnt for any
|
|
197
|
-
prmcnt = primes.count {|p| p >= start_num && p <=
|
|
198
|
-
prmcnt = nth-1 if nthflag && nth > 0
|
|
199
|
-
|
|
131
|
+
# init prmcnt for any modulus primes in range; count primes in prms
|
|
132
|
+
prmcnt = primes.count { |p| p >= start_num && p <= end_num }
|
|
133
|
+
prmcnt = nth - 1 if nthflag && (nth > 0) # start count for small range
|
|
134
|
+
max = prms.size
|
|
135
|
+
while m < max; prmcnt = prmcnt.succ if prms[m].zero?; m = m.succ end
|
|
136
|
+
prmcnt
|
|
200
137
|
end
|
|
201
138
|
|
|
202
|
-
#
|
|
203
|
-
#
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
d = n - 1
|
|
214
|
-
s = 0
|
|
215
|
-
(d >>= 1; s += 1) while d.even?
|
|
216
|
-
k.times do
|
|
217
|
-
a = 2 + rand(n-4)
|
|
218
|
-
x = a.to_bn.mod_exp(d,n) # x = (a**d) mod n
|
|
219
|
-
next if x == 1 or x == n-1
|
|
220
|
-
(s-1).times do
|
|
221
|
-
x = x.mod_exp(2,n) # x = (x**2) mod n
|
|
222
|
-
return false if x == 1
|
|
223
|
-
break if x == n-1
|
|
224
|
-
end
|
|
225
|
-
return false if x != n-1
|
|
139
|
+
# List primes within a number range: end_num - start_num
|
|
140
|
+
# Uses 'primemr' to check primality of prime candidates in range
|
|
141
|
+
def primesmr(start_num = 0)
|
|
142
|
+
end_num, start_num = check_inputs(self, start_num)
|
|
143
|
+
r, modk, residues, primes = sozcore1(end_num, start_num)
|
|
144
|
+
rescnt, modpg = residues.size, residues[-1] - 1
|
|
145
|
+
|
|
146
|
+
while end_num >= (pc = modk + residues[r])
|
|
147
|
+
primes << pc if pc.primemr?
|
|
148
|
+
(r = 0; modk += modpg) if (r = r.succ) == rescnt
|
|
226
149
|
end
|
|
227
|
-
|
|
150
|
+
primes
|
|
228
151
|
end
|
|
229
152
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
pcs_in_range, r, mod, modk, rescnt, residues, primes = sozdata
|
|
153
|
+
# Count primes within a number range: end_num - start_num
|
|
154
|
+
# Uses 'primemr' to check primality of prime candidates in range
|
|
155
|
+
def primescntmr(start_num = 0)
|
|
156
|
+
end_num, start_num = check_inputs(self, start_num)
|
|
235
157
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
158
|
+
nthflag, nth = 0, 0
|
|
159
|
+
if start_num < 3 # for all primes upto num
|
|
160
|
+
start_num, nth, nthflag = set_start_value(end_num, false) # closest nth value
|
|
161
|
+
return nth unless nthflag # output num's key|count if ref nth value
|
|
240
162
|
end
|
|
241
|
-
primes
|
|
242
|
-
end
|
|
243
163
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
sozdata = sozcore1(self, start_num, false) # false for primescnt
|
|
248
|
-
pcs_in_range, r, mod, modk, rescnt, residues, primescnt = sozdata
|
|
164
|
+
r, modk, residues, mod_primes = sozcore1(end_num, start_num)
|
|
165
|
+
rescnt, modpg, primescnt = residues.size, residues[-1] - 1, mod_primes.size
|
|
166
|
+
primescnt = nth - 1 if nthflag && (nth > 0) # set count for nth prime < num
|
|
249
167
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
168
|
+
while end_num >= (pc = modk + residues[r])
|
|
169
|
+
primescnt = primescnt.succ if pc.primemr?
|
|
170
|
+
(r = 0; modk += modpg) if (r = r.succ) == rescnt
|
|
253
171
|
end
|
|
254
172
|
primescnt
|
|
255
173
|
end
|
|
256
174
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
175
|
+
# PGT and Miller-Rabin combined primality tests for random n
|
|
176
|
+
def prime? (k = 5) # Can change k higher for mr_prime?
|
|
177
|
+
#Use PGT residue checks for small values < PRIMES.last**2
|
|
178
|
+
return PRIMES.include? self if self <= PRIMES.last
|
|
179
|
+
return false if MODPN.gcd(self) != 1
|
|
180
|
+
return true if self < PRIMES_LAST_SQRD
|
|
181
|
+
primemr?(k)
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
# Returns the next prime number for +self+ >= 0, or nil if n < 0
|
|
185
|
+
def next_prime
|
|
186
|
+
return nil if (n = self) < 0
|
|
187
|
+
return (n >> 1) + 2 if n <= 2 # return 2 if n is 0|1
|
|
188
|
+
n = n + 1 | 1 # 1st odd number > n
|
|
189
|
+
until (res = n % 6) & 0b11 == 1; n += 2 end # n first P3 pc >= n, w/residue 1 or 5
|
|
190
|
+
inc = (res == 1) ? 4 : 2 # set its P3 PGS value, inc by 2 and 4
|
|
191
|
+
until n.primemr?; n += inc; inc ^= 0b110 end # find first prime P3 pc
|
|
192
|
+
n
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
# Returns the previous prime number < +self+, or nil if self <= 2
|
|
196
|
+
def prev_prime
|
|
197
|
+
return nil if (n = self) < 3
|
|
198
|
+
return (n >> 1) + 1 if n <= 5
|
|
199
|
+
n = n - 2 | 1 # 1st odd number < n
|
|
200
|
+
until (res = n % 6) & 0b11 == 1; n -= 2 end # n first P3 pc <= n, w/residue 1 or 5
|
|
201
|
+
dec = (res == 1) ? 2 : 4 # set its P3 PGS value, dec by 2 and 4
|
|
202
|
+
until n.primemr?; n -= dec; dec ^= 0b110 end # find first prime P3 pc
|
|
203
|
+
n
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
def primes_utils
|
|
207
|
+
# display list of available methods
|
|
208
|
+
methods = %w[prime? primemr? primes primesmr primescnt
|
|
209
|
+
primescntmr primenth|nthprime factors|prime_division
|
|
210
|
+
factors1 next_prime prev_prime primes_utils].join(" ")
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
# Returns true if +self+ is a prime number, else returns false.
|
|
214
|
+
def primemr? (k = 5) # k is default number of random bases
|
|
215
|
+
return false if self < 2 # return false for 0|1 and negatives
|
|
216
|
+
neg_one_mod = n = d = self - 1 # these are even as self is always odd
|
|
217
|
+
d >>= 2 while (d & 0b11) == 0; d >>= (d & 1)^1 # make d odd number
|
|
218
|
+
# wits = [range, [wit_prms]] or nil
|
|
219
|
+
wits = WITNESS_RANGES.find { |range, wits| range > self }
|
|
220
|
+
witnesses = wits ? wits[1] : k.times.map{ rand(self - 4) + 2 }
|
|
221
|
+
witnesses.each do |b|
|
|
222
|
+
next if (b % self).zero? # **skip base if a multiple of input**
|
|
223
|
+
y = b.pow(d, self) # y = (b**d) mod self
|
|
224
|
+
s = d
|
|
225
|
+
until y == 1 || y == neg_one_mod || s == n
|
|
226
|
+
y = y.pow(2, self) # y = (y**2) mod self
|
|
227
|
+
s <<= 1
|
|
228
|
+
end
|
|
229
|
+
return false unless y == neg_one_mod || s.odd?
|
|
230
|
+
end
|
|
231
|
+
true
|
|
261
232
|
end
|
|
262
233
|
|
|
263
234
|
private
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
235
|
+
|
|
236
|
+
# Best known deterministic witnnesses for given range and set of bases
|
|
237
|
+
# https://miller-rabin.appspot.com/
|
|
238
|
+
# https://en.wikipedia.org/wiki/Miller%E2%80%93Rabin_primality_test
|
|
239
|
+
WITNESS_RANGES = {
|
|
240
|
+
341_531 => [9345883071009581737],
|
|
241
|
+
1_050_535_501 => [336781006125, 9639812373923155],
|
|
242
|
+
350_269_456_337 => [4230279247111683200, 14694767155120705706, 16641139526367750375],
|
|
243
|
+
55_245_642_489_451 => [2, 141889084524735, 1199124725622454117, 11096072698276303650],
|
|
244
|
+
7_999_252_175_582_851 => [2, 4130806001517, 149795463772692060, 186635894390467037, 3967304179347715805],
|
|
245
|
+
585_226_005_592_931_977 => [2, 123635709730000, 9233062284813009, 43835965440333360, 761179012939631437, 1263739024124850375],
|
|
246
|
+
18_446_744_073_709_551_615 => [2, 325, 9375, 28178, 450775, 9780504, 1795265022],
|
|
247
|
+
318_665_857_834_031_151_167_461 => [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37],
|
|
248
|
+
3_317_044_064_679_887_385_961_981 => [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41]
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
MODPN = 232862364358497360900063316880507363070 # 101# (101 primorial) is largest for u128
|
|
252
|
+
PRIMES = [2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103]
|
|
253
|
+
PRIMES_LAST_SQRD = PRIMES.last ** 2
|
|
254
|
+
|
|
255
|
+
def check_inputs(end_num, start_num)
|
|
256
|
+
raise "invalid negative input(s)" if end_num < 0 || start_num < 0
|
|
257
|
+
end_num, start_num = start_num, end_num if start_num > end_num
|
|
258
|
+
[end_num, start_num]
|
|
268
259
|
end
|
|
269
260
|
|
|
270
|
-
#
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
261
|
+
# Returns for SP PG mod value array of residues [r1, r2,..mod-1, mod+1]
|
|
262
|
+
def make_residues(modpg)
|
|
263
|
+
return [ 7, 11, 13, 17, 19, 23, 29, 31] if modpg == 30
|
|
264
|
+
return [11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71,
|
|
265
|
+
73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 121, 127, 131, 137,
|
|
266
|
+
139, 143, 149, 151, 157, 163, 167, 169, 173, 179, 181, 187, 191,
|
|
267
|
+
193, 197, 199, 209, 211] if modpg == 210
|
|
268
|
+
residues = []
|
|
269
|
+
pc, inc, midmod = 13, 4, modpg >> 1
|
|
270
|
+
while pc < midmod
|
|
271
|
+
residues << pc << (modpg - pc) if modpg.gcd(pc) == 1
|
|
272
|
+
pc += inc; inc ^= 0b110
|
|
273
|
+
end
|
|
274
|
+
residues.sort << (modpg - 1) << (modpg + 1)
|
|
277
275
|
end
|
|
278
276
|
|
|
279
|
-
#
|
|
280
|
-
#
|
|
277
|
+
# lte = true: first output element is number of pcs <= num
|
|
278
|
+
# lte = false: num pcs <, residue index, resgroup val, for (start_)num pc
|
|
279
|
+
def pcs_to_num(num, residues, lte)
|
|
280
|
+
modpg, rescnt = residues[-1] - 1, residues.size
|
|
281
|
+
num -= 1; lte ? (num |= 1; k = num.abs/modpg) : k = (num - 1).abs/modpg
|
|
282
|
+
modk = modpg * k; r = 0
|
|
283
|
+
r = r.succ while num >= modk + residues[r]
|
|
284
|
+
[rescnt * k + r, r, modk] # [num pcs, r index, num modulus]
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
def pcs_to_nums(end_num, start_num, residues)
|
|
288
|
+
modpg, rescnt = residues[-1] - 1, residues.size
|
|
289
|
+
end_num = 2 if end_num < residues[0]
|
|
290
|
+
start_num = 2 if start_num < residues[0]
|
|
291
|
+
start_num -= 1; k1 = (start_num - 1)/modpg; modk1 = modpg * k1
|
|
292
|
+
end_num -= 1; k2 = (end_num |= 1 )/modpg; modk2 = modpg * k2
|
|
293
|
+
r1 = 0; r1 = r1.succ while start_num >= modk1 + residues[r1]
|
|
294
|
+
r2 = 0; r2 = r2.succ while end_num >= modk2 + residues[r2]
|
|
295
|
+
pcs2end = k2 * rescnt + r2; pcs2start = k1 * rescnt + r1
|
|
296
|
+
pcs_in_range = pcs2end - pcs2start
|
|
297
|
+
[pcs2end, pcs2start, r1, modk1, pcs_in_range]
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
# Use default SP Prime Generator to parametize the pcs within range
|
|
301
|
+
# inputs: end_num|start_num of range
|
|
281
302
|
# outputs: maxpcs-m - number of pcs in the range
|
|
282
303
|
# r - residue index value for start_num pc of range
|
|
283
|
-
# mod - mod value for PG
|
|
284
304
|
# modk - base value for start_num's resgroup
|
|
285
|
-
#
|
|
286
|
-
#
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
residues
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
# init 'primes' w/any excluded primes in the range, or [] if none
|
|
298
|
-
primes.select! {|p| p >= start_num && p <= num}
|
|
299
|
-
|
|
300
|
-
# compute parameters for start_num pc, then create output parameters array
|
|
301
|
-
m, r, modk = pcs_to_num(start_num, mod, rescnt, residues, false)
|
|
302
|
-
[maxpcs-m, r, mod, modk, rescnt, residues, method_flag ? primes : primes.size]
|
|
305
|
+
# residues - array of residues for PG: [r1..modpg-1, modpg+1]
|
|
306
|
+
# primes array|primes.size - based on method_flag
|
|
307
|
+
def sozcore1(end_num, start_num)
|
|
308
|
+
range = end_num - start_num
|
|
309
|
+
modpg = range < 10_000 ? 210 : 30030
|
|
310
|
+
residues = make_residues(modpg) # chosen PG residues
|
|
311
|
+
primes = PRIMES.select { |p| p < residues[0] && (p >= start_num && p <= end_num) }
|
|
312
|
+
start_num = 2 if start_num < residues[0]
|
|
313
|
+
k = (start_num - 2) / modpg; modk = k * modpg; r = 0
|
|
314
|
+
while (start_num - 1) >= modk + residues[r]; r = r.succ end
|
|
315
|
+
[r, modk, residues, primes]
|
|
303
316
|
end
|
|
304
317
|
|
|
305
318
|
# Perform SoZ with given Prime Generator and return array of parameters
|
|
306
|
-
# inputs: end_num and start_num of range and
|
|
319
|
+
# inputs: end_num and start_num of range and modulus value for PG
|
|
307
320
|
# outputs: prms - binary (0,1) array of pcs within a range or to end_num
|
|
308
321
|
# m - num of pcs in prms < start_num; so prms[m] = start_num
|
|
309
|
-
# modks -
|
|
310
|
-
# residues - array of residues
|
|
311
|
-
# rescnt - number of residues for PG
|
|
322
|
+
# modks - modulus value for start_num's resgroup
|
|
323
|
+
# residues - array of residues for PG: [r1..modpg-1, modpg+1]
|
|
312
324
|
# pcs2start- number of pcs < start_num pc
|
|
313
|
-
#
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
pcs2start
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
if split_arrays # if start_num > sqrtN create two arrays
|
|
328
|
-
maxpcs = pcs2sqrtN # number of pcs|array size, for pcs <= sqrtN
|
|
329
|
-
max_range = maxprms-pcs2start # number of pcs in range start_num to end_num
|
|
330
|
-
prms_range = array_check(max_range,1) # array to represent pcs in range
|
|
331
|
-
return puts "ERROR1: range size too big for available memory." unless prms_range
|
|
325
|
+
# rs - residue index location for first pc >= start_num
|
|
326
|
+
def sozcore2(end_num, start_num, modpg)
|
|
327
|
+
residues = make_residues(modpg); rescnt = residues.size
|
|
328
|
+
maxpcs, pcs2start, rs, modks, pcs_range = pcs_to_nums(end_num, start_num, residues)
|
|
329
|
+
sqrtN = Integer.sqrt(end_num)
|
|
330
|
+
pcs2sqrtN, _ = pcs_to_nums(sqrtN, 0, residues) # num pcs <= sqrtN
|
|
331
|
+
|
|
332
|
+
m = pcs2start # index to start retrieving primes in prms array
|
|
333
|
+
split_arrays = (start_num > sqrtN) # flag, true for split arrays
|
|
334
|
+
if split_arrays # if start_num > sqrtN create two arrays
|
|
335
|
+
maxpcs = pcs2sqrtN # array size now for primary sieve array prms
|
|
336
|
+
prms_range = array_check(pcs_range) # array for pcs in range
|
|
337
|
+
raise 'ERROR1: range too big for free sys mem.' unless prms_range
|
|
338
|
+
m = 0 # index to start retrieving primes in split array
|
|
332
339
|
end
|
|
333
|
-
prms = array_check(maxpcs
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
#
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
prime = modk + prm_r # its value is numerated
|
|
346
|
-
prmstep = prime * rescnt # its primestep computed
|
|
347
|
-
kcon = k * prmstep # its inner loop constant computed
|
|
348
|
-
residues[1..-1].each do |ri|# now perform sieve with it
|
|
340
|
+
prms = array_check(maxpcs) # array for pcs upto sqrtN, or end_num
|
|
341
|
+
raise 'ERROR2: end_num too big for available sys mem.' unless prms
|
|
342
|
+
|
|
343
|
+
# Sieve of Zakiya (SoZ) to eliminate nonprimes from prms, prms_range
|
|
344
|
+
pcs2sqrtN.times do |i| # sieve primes from pcs upto sqrt(end_num)
|
|
345
|
+
next unless prms[i].zero? # if pc not prime, get next one
|
|
346
|
+
prm_r = residues[i % rescnt] # save its residue value
|
|
347
|
+
prime = modpg*(k=i/rescnt)+prm_r # numerate its value; set k resgroup value
|
|
348
|
+
rem = start_num % prime # prime's distance to start_num
|
|
349
|
+
next unless (prime - rem <= end_num - start_num) || rem == 0 # skip prime mults not in range
|
|
350
|
+
prmstep = prime * rescnt # compute its primestep
|
|
351
|
+
residues.each do |ri| # find|mark its multiples
|
|
349
352
|
# convert (prime * (modk + ri)) pc value to its address in prms
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
end
|
|
361
|
-
# determine prms array parameters and starting location value m for start_num
|
|
362
|
-
split_arrays ? (prms = prms_range; maxprms = max_range; m=0) : m = pcs2start
|
|
363
|
-
[prms, m, modks, residues, rescnt, pcs2start, maxprms, rs] # parameters output
|
|
353
|
+
kn, rr = (prm_r * ri - 2).divmod modpg
|
|
354
|
+
mult = mult1 = (k*(prime + ri) + kn)*rescnt + residues.index(rr+2) # 1st prime mult
|
|
355
|
+
while mult < maxpcs; prms[mult] = 1; mult += prmstep end
|
|
356
|
+
if split_arrays # when start_num > sqrtN(pcs2sqrtN+1)
|
|
357
|
+
mult = (pcs2start - mult1) % prmstep # (start_num - last mult) pcs
|
|
358
|
+
mult = prmstep - mult if mult != 0 # location in range, or beyond
|
|
359
|
+
while mult < pcs_range; prms_range[mult] = 1; mult += prmstep end
|
|
360
|
+
end end end
|
|
361
|
+
# select prms array and start location val m for start_num in it
|
|
362
|
+
[(split_arrays ? prms_range : prms), m, modks, residues, pcs2start, rs]
|
|
364
363
|
end
|
|
365
364
|
|
|
366
|
-
def approximate_nth(n)
|
|
367
|
-
b = 0.5722*n**0.0088
|
|
368
|
-
a = b*
|
|
369
|
-
(n*(
|
|
365
|
+
def approximate_nth(n)
|
|
366
|
+
b = 0.5722 * n**0.0088
|
|
367
|
+
a = b * Math.log(log_n = Math.log(n))
|
|
368
|
+
(n * (log_n + a) + 3).to_i
|
|
370
369
|
end
|
|
371
370
|
|
|
372
|
-
|
|
371
|
+
# Find largest index nthprime|val <= n; return [start_num, nth, f/t]
|
|
372
|
+
def set_start_value(n, hshflag)
|
|
373
373
|
if hshflag
|
|
374
|
-
|
|
375
|
-
nth
|
|
376
|
-
[nth ? nths[nth] : 0, nth ||= n+1, false] # [start_num, nth, false]
|
|
374
|
+
nth = nths.keys.sort.reverse.find { |k| k <= n } # largest key <= n
|
|
375
|
+
[nth ? nths[nth] : 0, nth || (n + 1), nth == n]
|
|
377
376
|
else
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
[v ||= 0, val ? nths.key(val) : 0, true] # [start_num, nth, true]
|
|
377
|
+
val = nths.values.sort.reverse.find { |v| v <= n } # largest val <= n
|
|
378
|
+
[val || 0, val ? nths.key(val) : 0, val != n]
|
|
381
379
|
end
|
|
382
380
|
end
|
|
383
381
|
|
|
384
|
-
def nths
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
382
|
+
def nths # hash table index of reference nth primes
|
|
383
|
+
{ 1_000_000 => 15_485_863, 5_000_000 => 86_028_121,
|
|
384
|
+
7_500_000 => 132_276_691, 10_000_000 => 179_424_673,
|
|
385
|
+
12_500_000 => 227_254_201, 15_000_000 => 275_604_541,
|
|
386
|
+
18_500_000 => 344_032_387, 25_000_000 => 472_882_027,
|
|
387
|
+
31_000_000 => 593_441_843, 37_500_000 => 725_420_401,
|
|
388
|
+
43_500_000 => 848_321_917, 50_000_000 => 982_451_653,
|
|
389
|
+
56_000_000 => 1_107_029_837, 62_500_000 => 1_242_809_749,
|
|
390
|
+
68_500_000 => 1_368_724_829, 75_000_000 => 1_505_776_939,
|
|
391
|
+
81_500_000 => 1_643_429_659, 87_500_000 => 1_770_989_609,
|
|
392
|
+
93_500_000 => 1_898_979_367, 100_000_000 => 2_038_074_743,
|
|
393
|
+
106_500_000 => 2_177_624_377, 112_500_000 => 2_306_797_469,
|
|
394
|
+
125_000_000 => 2_576_983_867, 137_500_000 => 2_848_518_523,
|
|
395
|
+
150_000_000 => 3_121_238_909, 162_500_000 => 3_395_057_291,
|
|
396
|
+
175_000_000 => 3_669_829_403, 187_500_000 => 3_945_592_087,
|
|
397
|
+
200_000_000 => 4_222_234_741, 212_500_000 => 4_499_683_009,
|
|
398
|
+
225_000_000 => 4_777_890_881, 237_500_000 => 5_056_862_311,
|
|
399
|
+
250_000_000 => 5_336_500_537, 262_500_000 => 5_616_787_769,
|
|
400
|
+
275_000_000 => 5_897_707_297, 287_500_000 => 6_179_208_157,
|
|
401
|
+
300_000_000 => 6_461_335_109, 312_500_000 => 6_743_943_629,
|
|
402
|
+
325_000_000 => 7_027_107_881, 337_500_000 => 7_310_793_337,
|
|
403
|
+
350_000_000 => 7_594_955_549, 362_500_000 => 7_879_581_839,
|
|
404
|
+
375_000_000 => 8_164_628_191, 387_500_000 => 8_450_100_349,
|
|
405
|
+
400_000_000 => 8_736_028_057, 412_500_000 => 9_022_375_487,
|
|
406
|
+
425_000_000 => 9_309_109_471, 437_500_000 => 9_596_238_593,
|
|
407
|
+
450_000_000 => 9_883_692_017, 462_500_000 => 10_171_564_687,
|
|
408
|
+
475_000_000 => 10_459_805_417, 487_500_000 => 10_748_372_137,
|
|
409
|
+
500_000_000 => 11_037_271_757, 512_500_000 => 11_326_513_039,
|
|
410
|
+
525_000_000 => 11_616_020_609, 537_500_000 => 11_905_863_799,
|
|
411
|
+
550_000_000 => 12_196_034_771, 562_500_000 => 12_486_465_863,
|
|
412
|
+
575_000_000 => 12_777_222_833, 587_500_000 => 13_068_237_251,
|
|
413
|
+
600_000_000 => 13_359_555_403, 612_500_000 => 13_651_119_389,
|
|
414
|
+
625_000_000 => 13_942_985_677, 637_500_000 => 14_235_122_851,
|
|
415
|
+
650_000_000 => 14_527_476_781, 662_500_000 => 14_820_071_503,
|
|
416
|
+
675_000_000 => 15_112_928_683, 687_500_000 => 15_406_031_899,
|
|
417
|
+
700_000_000 => 15_699_342_107, 712_500_000 => 15_992_957_251,
|
|
418
|
+
725_000_000 => 16_286_768_243, 737_500_000 => 16_580_801_137,
|
|
419
|
+
750_000_000 => 16_875_026_921, 762_500_000 => 17_169_527_171,
|
|
420
|
+
775_000_000 => 17_464_243_799, 787_500_000 => 17_759_139_259,
|
|
421
|
+
800_000_000 => 18_054_236_957, 812_500_000 => 18_349_591_409,
|
|
422
|
+
825_000_000 => 18_645_104_897, 837_500_000 => 18_940_846_207,
|
|
423
|
+
850_000_000 => 19_236_701_629, 862_500_000 => 19_532_780_327,
|
|
424
|
+
875_000_000 => 19_829_092_147, 887_500_000 => 20_125_592_731,
|
|
425
|
+
900_000_000 => 20_422_213_579, 912_500_000 => 20_719_050_323,
|
|
426
|
+
925_000_000 => 21_016_060_633, 937_500_000 => 21_313_231_963,
|
|
427
|
+
950_000_000 => 21_610_588_367, 962_500_000 => 21_908_128_993,
|
|
428
|
+
975_000_000 => 22_205_818_561, 987_500_000 => 22_503_733_657,
|
|
429
|
+
1_000_000_000 => 22_801_763_489, 1_012_500_000 => 23_099_993_743,
|
|
430
|
+
1_025_000_000 => 23_398_391_231, 1_037_500_000 => 23_696_858_797,
|
|
431
|
+
1_050_000_000 => 23_995_554_823, 1_062_500_000 => 24_294_392_179,
|
|
432
|
+
1_075_000_000 => 24_593_421_187, 1_087_500_000 => 24_892_587_403,
|
|
433
|
+
1_100_000_000 => 25_191_867_719, 1_112_500_000 => 25_491_361_037,
|
|
434
|
+
1_125_000_000 => 25_790_970_053, 1_137_500_000 => 26_090_709_563,
|
|
435
|
+
1_150_000_000 => 26_390_560_513, 1_162_500_000 => 26_690_560_601,
|
|
436
|
+
1_175_000_000 => 26_990_744_987, 1_187_500_000 => 27_291_009_337,
|
|
437
|
+
1_200_000_000 => 27_591_444_869, 1_212_500_000 => 27_892_051_267,
|
|
438
|
+
1_225_000_000 => 28_192_760_279, 1_237_500_000 => 28_493_648_629,
|
|
439
|
+
1_250_000_000 => 28_794_583_627, 1_262_500_000 => 29_095_694_269,
|
|
440
|
+
1_275_000_000 => 29_396_966_971, 1_287_500_000 => 29_698_366_099,
|
|
441
|
+
1_300_000_000 => 29_999_858_327, 1_312_500_000 => 30_301_430_881,
|
|
442
|
+
1_325_000_000 => 30_603_183_581, 1_337_500_000 => 30_905_024_497,
|
|
443
|
+
1_350_000_000 => 31_207_047_449, 1_362_500_000 => 31_509_131_153,
|
|
444
|
+
1_375_000_000 => 31_811_397_571, 1_387_500_000 => 32_113_702_069,
|
|
445
|
+
1_400_000_000 => 32_416_190_071, 1_412_500_000 => 32_718_790_873,
|
|
446
|
+
1_425_000_000 => 33_021_414_143, 1_437_500_000 => 33_324_275_711,
|
|
447
|
+
1_450_000_000 => 33_627_220_709, 1_462_500_000 => 33_930_284_893,
|
|
448
|
+
1_475_000_000 => 34_233_442_279, 1_487_500_000 => 34_536_683_891,
|
|
449
|
+
1_500_000_000 => 34_840_062_373, 1_512_500_000 => 35_143_545_889,
|
|
450
|
+
1_525_000_000 => 35_447_088_559, 1_537_500_000 => 35_750_747_297,
|
|
451
|
+
1_550_000_000 => 36_054_501_641, 1_562_500_000 => 36_358_440_731,
|
|
452
|
+
1_575_000_000 => 36_662_430_631, 1_587_500_000 => 36_966_563_321,
|
|
453
|
+
1_600_000_000 => 37_270_791_697, 1_612_500_000 => 37_575_137_933,
|
|
454
|
+
1_625_000_000 => 37_879_532_671, 1_637_500_000 => 38_184_009_763,
|
|
455
|
+
1_650_000_000 => 38_488_677_419, 1_662_500_000 => 38_793_413_899,
|
|
456
|
+
1_675_000_000 => 39_098_225_629, 1_687_500_000 => 39_403_174_463,
|
|
457
|
+
1_700_000_000 => 39_708_229_123, 1_712_500_000 => 40_013_309_359,
|
|
458
|
+
1_725_000_000 => 40_318_523_009, 1_737_500_000 => 40_623_800_311,
|
|
459
|
+
1_750_000_000 => 40_929_166_261, 1_762_500_000 => 41_234_743_751,
|
|
460
|
+
1_775_000_000 => 41_540_289_619, 1_787_500_000 => 41_845_958_971,
|
|
461
|
+
1_800_000_000 => 42_151_671_491, 1_812_500_000 => 42_457_500_313,
|
|
462
|
+
1_825_000_000 => 42_763_499_629, 1_837_500_000 => 43_069_571_603,
|
|
463
|
+
1_850_000_000 => 43_375_710_643, 1_862_500_000 => 43_681_898_699,
|
|
464
|
+
1_875_000_000 => 43_988_172_667, 1_887_500_000 => 44_294_549_347,
|
|
465
|
+
1_900_000_000 => 44_601_021_791, 1_912_500_000 => 44_907_564_593,
|
|
466
|
+
1_925_000_000 => 45_214_177_441, 1_937_500_000 => 45_520_935_011,
|
|
467
|
+
1_950_000_000 => 45_827_700_419, 1_962_500_000 => 46_134_655_219,
|
|
468
|
+
1_975_000_000 => 46_441_643_177, 1_987_500_000 => 46_748_693_981,
|
|
469
|
+
2_000_000_000 => 47_055_833_459, 2_012_500_000 => 47_363_059_687,
|
|
470
|
+
2_125_000_000 => 50_131_763_837, 2_250_000_000 => 53_215_141_519,
|
|
471
|
+
2_375_000_000 => 56_305_859_821, 2_500_000_000 => 59_403_556_879,
|
|
472
|
+
2_625_000_000 => 62_507_768_977, 2_750_000_000 => 65_618_159_808,
|
|
473
|
+
2_875_000_000 => 68_734_481_527, 3_000_000_000 => 71_856_445_751,
|
|
474
|
+
3_125_000_000 => 74_983_924_661, 3_250_000_000 => 78_116_541_127,
|
|
475
|
+
3_375_000_000 => 81_254_172_953, 3_500_000_000 => 84_396_675_733,
|
|
476
|
+
3_625_000_000 => 87_543_835_147, 3_750_000_000 => 90_695_492_941,
|
|
477
|
+
3_875_000_000 => 93_851_412_433, 4_000_000_000 => 97_011_687_217,
|
|
478
|
+
4_125_000_000 =>100_175_917_301, 4_250_000_000 => 103_344_103_553,
|
|
479
|
+
4_375_000_000 =>106_516_393_597, 4_500_000_000 => 109_692_247_799,
|
|
480
|
+
4_625_000_000 =>112_871_634_437, 4_750_000_000 => 116_054_419_753,
|
|
481
|
+
4_875_000_000 =>119_240_825_947, 5_000_000_000 => 122_430_513_841,
|
|
482
|
+
5_125_000_000 =>125_623_420_333, 5_250_000_000 => 128_819_622_391,
|
|
483
|
+
5_375_000_000 =>132_018_808_321, 5_500_000_000 => 135_221_143_753,
|
|
484
|
+
5_625_000_000 =>138_426_461_137, 5_750_000_000 => 141_634_567_969,
|
|
485
|
+
5_875_000_000 =>144_845_535_431, 6_000_000_000 => 148_059_109_201,
|
|
486
|
+
6_125_000_000 =>151_275_700_969, 6_250_000_000 => 154_494_952_609,
|
|
487
|
+
6_375_000_000 =>157_716_628_943, 6_500_000_000 => 160_940_840_461,
|
|
488
|
+
6_625_000_000 =>164_167_763_329, 6_750_000_000 => 167_397_013_051,
|
|
489
|
+
6_875_000_000 =>170_628_613_009, 7_000_000_000 => 173_862_636_221 }
|
|
490
|
+
|
|
491
|
+
def select_pg(end_num, start_num) # adaptively select PG
|
|
492
|
+
range = end_num - start_num
|
|
448
493
|
pg = 5
|
|
449
|
-
if start_num <=
|
|
450
|
-
pg = 7 if
|
|
451
|
-
pg = 11 if
|
|
452
|
-
else
|
|
453
|
-
pg = 7 if (range.between?(10**6, 10**7-1) && start_num < 10**8)
|
|
454
|
-
(range.between?(10**7, 10**8-1) && start_num < 46*10**8) ||
|
|
455
|
-
(range.between?(10**8, 10**9-1) && start_num < 16*10**10) ||
|
|
456
|
-
(range >= 10**9 && start_num < 26*10**12)
|
|
457
|
-
pg = 11 if (range.between?(10**8, 10**9-1) && start_num < 55*10**7) ||
|
|
458
|
-
(range >= 10**9 && start_num < 45*10**9)
|
|
494
|
+
if start_num <= Integer.sqrt(end_num) # for one array of primes upto N
|
|
495
|
+
pg = 7 if end_num > 50 * 10**4
|
|
496
|
+
pg = 11 if end_num > 305 * 10**5
|
|
497
|
+
else # for split array cases
|
|
498
|
+
pg = 7 if (range.between?(10**6, 10**7 - 1) && start_num < 10**8) ||
|
|
499
|
+
(range.between?(10**7, 10**8 - 1) && start_num < 46 * 10**8) ||
|
|
500
|
+
(range.between?(10**8, 10**9 - 1) && start_num < 16 * 10**10) ||
|
|
501
|
+
(range >= 10**9 && start_num < 26 * 10**12)
|
|
502
|
+
pg = 11 if (range.between?(10**8, 10**9 - 1) && start_num < 55 * 10**7) ||
|
|
503
|
+
(range >= 10**9 && start_num < 45 * 10**9)
|
|
459
504
|
end
|
|
460
|
-
primes = [2,3,5,7,11,13].select! {|p| p <= pg}
|
|
461
|
-
[primes, primes.reduce(:*)]
|
|
462
|
-
end
|
|
463
|
-
|
|
464
|
-
def array_check(n,v) # catch out-of-memory errors on array creation
|
|
465
|
-
Array.new(n,v) rescue return # return an array or nil
|
|
505
|
+
primes = [2, 3, 5, 7, 11, 13].select! { |p| p <= pg }
|
|
506
|
+
[primes, primes.reduce(:*)] # [base primes, mod] for PG
|
|
466
507
|
end
|
|
467
508
|
|
|
509
|
+
def array_check(len) # for out-of-memory errors on primes array creation
|
|
510
|
+
begin
|
|
511
|
+
Array.new(len, 0) # use Array when enough mem for given length
|
|
512
|
+
rescue Exception
|
|
513
|
+
return BitArray.new(len) # use BitArray when memory-error for Array
|
|
514
|
+
end end
|
|
468
515
|
end
|
|
469
516
|
end
|
|
470
517
|
|
|
471
518
|
class Integer; include Primes::Utils end
|
|
472
519
|
|
|
473
|
-
puts "Available methods are: #{0.primes_utils}"
|
|
520
|
+
puts "Available methods are: #{0.primes_utils}" # display methods upon loading
|