rubylabs 0.5.4
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +20 -0
- data/README.rdoc +9 -0
- data/Rakefile +63 -0
- data/VERSION +1 -0
- data/bin/bb.rb +12 -0
- data/bin/statistics2-0.53/ext/extconf.rb +11 -0
- data/bin/statistics2-0.53/ext/show.rb +11 -0
- data/bin/statistics2-0.53/ext/t.rb +46 -0
- data/bin/statistics2-0.53/mklist.rb +26 -0
- data/bin/statistics2-0.53/sample-tbl.rb +129 -0
- data/bin/statistics2-0.53/statistics2.rb +532 -0
- data/bin/statistics2-0.53/t-inv.rb +54 -0
- data/bin/statistics2.rb +532 -0
- data/data/aafreq.txt +20 -0
- data/data/cars.txt +50 -0
- data/data/century.txt +1 -0
- data/data/colors.txt +64 -0
- data/data/earth.yaml +15 -0
- data/data/fruit.txt +45 -0
- data/data/hacodes.txt +35 -0
- data/data/hafreq.txt +16 -0
- data/data/hvfreq.txt +5 -0
- data/data/nbody.R +23 -0
- data/data/nbody.out +731 -0
- data/data/nbody.pdf +3111 -0
- data/data/nbody.png +0 -0
- data/data/nbody3d.pdf +3201 -0
- data/data/outer.pdf +182785 -0
- data/data/solar.dat +36501 -0
- data/data/solarsystem.txt +17 -0
- data/data/suits.txt +1 -0
- data/data/wordlist.txt +210653 -0
- data/lib/bitlab.rb +624 -0
- data/lib/elizalab.rb +523 -0
- data/lib/encryptionlab.rb +42 -0
- data/lib/hashlab.rb +224 -0
- data/lib/introlab.rb +14 -0
- data/lib/iterationlab.rb +130 -0
- data/lib/randomlab.rb +294 -0
- data/lib/recursionlab.rb +228 -0
- data/lib/rubylabs.rb +507 -0
- data/lib/sievelab.rb +58 -0
- data/lib/sortlab.rb +213 -0
- data/lib/spherelab.rb +352 -0
- data/lib/temps.rb +41 -0
- data/lib/tsplab.rb +416 -0
- data/lib/viewer.rb +65 -0
- data/test/bit_test.rb +175 -0
- data/test/encryption_test.rb +20 -0
- data/test/iteration_test.rb +40 -0
- data/test/random_test.rb +64 -0
- data/test/recursion_test.rb +47 -0
- data/test/rubylabs_test.rb +18 -0
- data/test/sieve_test.rb +28 -0
- data/test/sphere_test.rb +130 -0
- data/test/temps_test.rb +24 -0
- data/test/test_helper.rb +18 -0
- metadata +112 -0
data/lib/rubylabs.rb
ADDED
@@ -0,0 +1,507 @@
|
|
1
|
+
=begin rdoc
|
2
|
+
|
3
|
+
= RubyLabs
|
4
|
+
|
5
|
+
Common methods used by two or more lab projects.
|
6
|
+
|
7
|
+
Methods used to monitor execution of programs during experiments.
|
8
|
+
|
9
|
+
=end
|
10
|
+
|
11
|
+
SCRIPT_LINES__ = Hash.new unless defined? SCRIPT_LINES__
|
12
|
+
|
13
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'bin'))
|
14
|
+
|
15
|
+
autoload :Temps, "temps.rb"
|
16
|
+
autoload :SieveLab, "sievelab.rb"
|
17
|
+
autoload :IterationLab, "iterationlab.rb"
|
18
|
+
autoload :RecursionLab, "recursionlab.rb"
|
19
|
+
autoload :HashLab, "hashlab.rb"
|
20
|
+
autoload :BitLab, "bitlab.rb"
|
21
|
+
autoload :RandomLab, "randomlab.rb"
|
22
|
+
autoload :EncryptionLab, "encryptionlab.rb"
|
23
|
+
autoload :ELIZALab, "elizalab.rb"
|
24
|
+
autoload :SphereLab, "spherelab.rb"
|
25
|
+
autoload :TSPLab, "tsplab.rb"
|
26
|
+
|
27
|
+
autoload :Viewer, "viewer.rb"
|
28
|
+
|
29
|
+
module RubyLabs
|
30
|
+
|
31
|
+
=begin rdoc
|
32
|
+
|
33
|
+
=== hello
|
34
|
+
|
35
|
+
A simple 'hello world' method to test the installation.
|
36
|
+
|
37
|
+
=end
|
38
|
+
|
39
|
+
def hello
|
40
|
+
"Hello, you have successfully installed RubyLabs!"
|
41
|
+
end
|
42
|
+
|
43
|
+
=begin rdoc
|
44
|
+
Log base 2.
|
45
|
+
=end
|
46
|
+
|
47
|
+
def log2(x)
|
48
|
+
Math.log(x) / Math.log(2.0)
|
49
|
+
end
|
50
|
+
|
51
|
+
=begin rdoc
|
52
|
+
Return the larger of a and b
|
53
|
+
=end
|
54
|
+
|
55
|
+
def max(a,b)
|
56
|
+
a > b ? a : b
|
57
|
+
end
|
58
|
+
|
59
|
+
=begin rdoc
|
60
|
+
Return the smaller of a and b
|
61
|
+
=end
|
62
|
+
|
63
|
+
def min(a,b)
|
64
|
+
a < b ? a : b
|
65
|
+
end
|
66
|
+
|
67
|
+
=begin rdoc
|
68
|
+
Return a copy of object x with the elements in a new, scrambled order. The
|
69
|
+
parameter x can be any object that has an index operator (e.g. strings or
|
70
|
+
arrays).
|
71
|
+
=end
|
72
|
+
|
73
|
+
def permutation(x)
|
74
|
+
res = x.clone
|
75
|
+
for i in 0..res.length-2
|
76
|
+
r = rand(res.length-i) + i
|
77
|
+
res[i], res[r] = res[r], res[i]
|
78
|
+
end
|
79
|
+
return res
|
80
|
+
end
|
81
|
+
|
82
|
+
=begin rdoc
|
83
|
+
|
84
|
+
Call time { foo(...) } to measure the execution time of a call to foo. This
|
85
|
+
method will time any arbitrary Ruby expression.
|
86
|
+
|
87
|
+
=end
|
88
|
+
|
89
|
+
def time(&f)
|
90
|
+
tstart = Time.now
|
91
|
+
f.call
|
92
|
+
return Time.now - tstart
|
93
|
+
end
|
94
|
+
|
95
|
+
=begin rdoc
|
96
|
+
|
97
|
+
Call trace { foo(...) } to monitor the execution of the call to foo. Sets up
|
98
|
+
a callback method which checks to see if a probe has been attached to a line
|
99
|
+
via a call to Source.probe, and if so evaluates the expression associated with
|
100
|
+
the probe.
|
101
|
+
|
102
|
+
=end
|
103
|
+
|
104
|
+
# Debugging aid: put this line at the front of the trace_func:
|
105
|
+
# p [event, file, line, id, binding, classname]
|
106
|
+
|
107
|
+
def trace(&f)
|
108
|
+
set_trace_func proc { |event, file, line, id, binding, classname|
|
109
|
+
if expr = Source.probing(file, id, line)
|
110
|
+
eval(expr, binding) if expr != :count
|
111
|
+
end
|
112
|
+
}
|
113
|
+
res = f.call
|
114
|
+
set_trace_func nil
|
115
|
+
res
|
116
|
+
end
|
117
|
+
|
118
|
+
=begin rdoc
|
119
|
+
|
120
|
+
A call to count { foo(...) } is similar to a call to trace, but instead of evaluating
|
121
|
+
the expression associated with a probe it just counts the number of times the
|
122
|
+
lines are executed and returns the count.
|
123
|
+
|
124
|
+
Note: this version assumes there are two different kinds of probes. Probes monitored
|
125
|
+
by the trace method are expressions that are evaluated when the probed expression is
|
126
|
+
encountered, and probes monitored by the count method are :count tags.
|
127
|
+
|
128
|
+
=end
|
129
|
+
|
130
|
+
def count(&f)
|
131
|
+
counter = 0
|
132
|
+
set_trace_func proc { |event, file, line, id, binding, classname|
|
133
|
+
if expr = Source.probing(file, id, line)
|
134
|
+
counter += 1 if expr == :count
|
135
|
+
end
|
136
|
+
}
|
137
|
+
f.call
|
138
|
+
set_trace_func nil
|
139
|
+
return counter
|
140
|
+
end
|
141
|
+
|
142
|
+
=begin rdoc
|
143
|
+
|
144
|
+
=== TestArray
|
145
|
+
|
146
|
+
A TestArray is an array of random numbers to use in testing searching and sorting
|
147
|
+
algorithms. Call TestArray.new(n) to make an array of n unique random numbers.
|
148
|
+
|
149
|
+
A method named +random+ will return a random element to use as a search target.
|
150
|
+
Call +a.random(:success)+ to get a value that is in the array +a+, or call
|
151
|
+
+a.random(:fail)+ to get a number that is not in the array.
|
152
|
+
|
153
|
+
=end
|
154
|
+
|
155
|
+
# The constructor uses a hash to create unique numbers -- it draws random numbers
|
156
|
+
# and uses them as keys to insert into the hash, and returns when the hash has n
|
157
|
+
# items. The hash is saved so it can be reused by a call to random(:fail) -- this
|
158
|
+
# time draw random numbers until one is not a key in the hash. A lot of machinery
|
159
|
+
# to keep around for very few calls, but it's efficient enough -- making an array
|
160
|
+
# of 100K items takes less than a second.
|
161
|
+
|
162
|
+
# The @spread variable controls the average spacing between items. The 6.667 for
|
163
|
+
# small arrays means an array of 15 will have numbers between 0 and 99.
|
164
|
+
|
165
|
+
# An earlier version used a method named test_array to make a regular Array object
|
166
|
+
# and augment it with the location method, but the singleton's methods were not passed
|
167
|
+
# on to copies made by a call to sort:
|
168
|
+
# >> x = test_array(3)
|
169
|
+
# => [16, 13, 4]
|
170
|
+
# >> x.sort.random(:fail)
|
171
|
+
# NoMethodError: undefined method `random' for [4, 13, 16]:Array
|
172
|
+
|
173
|
+
class TestArray < Array
|
174
|
+
|
175
|
+
def initialize(size)
|
176
|
+
@spread = (size > 50) ? 10 : 6.667
|
177
|
+
@h = Hash.new
|
178
|
+
|
179
|
+
while @h.size < size
|
180
|
+
@h[ rand( size * @spread ) ] = 1
|
181
|
+
end
|
182
|
+
|
183
|
+
@h.keys.each do |k|
|
184
|
+
self << k
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
def random(outcome)
|
189
|
+
if outcome == :success
|
190
|
+
return self[ rand(self.length) ]
|
191
|
+
elsif outcome == :fail
|
192
|
+
loop do
|
193
|
+
i = rand( self.length * @spread )
|
194
|
+
return i if @h[i] == nil
|
195
|
+
end
|
196
|
+
else
|
197
|
+
return nil
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
end # class TestArray
|
202
|
+
|
203
|
+
=begin rdoc
|
204
|
+
|
205
|
+
=== RandomArray
|
206
|
+
|
207
|
+
Similar to TestArray, but draws random words from a file.
|
208
|
+
|
209
|
+
=end
|
210
|
+
|
211
|
+
class RandomArray < Array
|
212
|
+
|
213
|
+
data = File.join(File.dirname(__FILE__), '..', 'data')
|
214
|
+
|
215
|
+
@@sources = {
|
216
|
+
:cars => "#{data}/cars.txt",
|
217
|
+
:colors => "#{data}/colors.txt",
|
218
|
+
:fruit => "#{data}/fruit.txt",
|
219
|
+
:words => "#{data}/wordlist.txt",
|
220
|
+
}
|
221
|
+
|
222
|
+
def initialize(src, n)
|
223
|
+
fn = @@sources[src] or raise "RandomArray: undefined array type: #{src}"
|
224
|
+
words = File.open(fn).readlines
|
225
|
+
a = Hash.new
|
226
|
+
while a.size < n
|
227
|
+
w = words[rand(words.length)].chomp
|
228
|
+
a[w] = 1
|
229
|
+
end
|
230
|
+
a.keys.each do |w|
|
231
|
+
self << w
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
def RandomArray.sources
|
236
|
+
return @@sources.keys.sort { |a,b| a.to_s <=> b.to_s }
|
237
|
+
end
|
238
|
+
|
239
|
+
end # RandomArray
|
240
|
+
|
241
|
+
|
242
|
+
=begin
|
243
|
+
The Source module has methods that access the source code for a lab
|
244
|
+
project. Since the outer module (RubyLabs) assigns SCRIPT_LINES__ the
|
245
|
+
source code has already been read from the file -- these methods just have
|
246
|
+
to look for the code in memory. The methods assume the code students will
|
247
|
+
look at has been delimited by comments containing the strings :begin and :end.
|
248
|
+
=end
|
249
|
+
|
250
|
+
module Source
|
251
|
+
|
252
|
+
@@probes = Hash.new
|
253
|
+
@@file = Hash.new
|
254
|
+
@@size = Hash.new
|
255
|
+
@@base = Hash.new
|
256
|
+
@@helpers = Hash.new
|
257
|
+
@@line = nil
|
258
|
+
|
259
|
+
=begin
|
260
|
+
Print the source code for method +name+.
|
261
|
+
=end
|
262
|
+
|
263
|
+
def Source.listing(name)
|
264
|
+
begin
|
265
|
+
id = Source.find(name)
|
266
|
+
for i in @@base[id]..(@@base[id]+@@size[id]-1)
|
267
|
+
line = SCRIPT_LINES__[@@file[id]][i-1].chomp
|
268
|
+
printf "%3d: %s\n", i - @@base[id] + 1, line.gsub(/\t/," ")
|
269
|
+
end
|
270
|
+
rescue Exception => e
|
271
|
+
puts e
|
272
|
+
end
|
273
|
+
return true
|
274
|
+
end
|
275
|
+
|
276
|
+
=begin
|
277
|
+
Write a copy of the source code for method +name+. If a file name is not
|
278
|
+
specified, the output file name is the name of the method with ".rb" appended.
|
279
|
+
Prompts the user before overwriting an existing file.
|
280
|
+
=end
|
281
|
+
|
282
|
+
def Source.checkout(name, newfilename = nil)
|
283
|
+
begin
|
284
|
+
id = Source.find(name)
|
285
|
+
if newfilename.nil?
|
286
|
+
newfilename = id.to_s
|
287
|
+
end
|
288
|
+
if newfilename !~ /\.rb$/
|
289
|
+
newfilename += ".rb"
|
290
|
+
end
|
291
|
+
if File.exists?(newfilename)
|
292
|
+
print "Replace existing #{newfilename}? [yn] "
|
293
|
+
if STDIN.gets[0] != ?y
|
294
|
+
puts "File not written"
|
295
|
+
return false
|
296
|
+
end
|
297
|
+
end
|
298
|
+
File.open(newfilename, "w") do |f|
|
299
|
+
f.puts "# #{name} method exported from #{File.basename(@@file[id])}"
|
300
|
+
f.puts
|
301
|
+
Source.print_source(f, id)
|
302
|
+
@@helpers[id].each do |m|
|
303
|
+
f.puts
|
304
|
+
xid = Source.find(m)
|
305
|
+
Source.print_source(f, xid)
|
306
|
+
end
|
307
|
+
end
|
308
|
+
rescue Exception => e
|
309
|
+
puts e
|
310
|
+
end
|
311
|
+
puts "Saved a copy of source in #{newfilename}"
|
312
|
+
return true
|
313
|
+
end
|
314
|
+
|
315
|
+
def Source.print_source(f, id)
|
316
|
+
for i in @@base[id]..(@@base[id]+@@size[id]-1)
|
317
|
+
line = SCRIPT_LINES__[@@file[id]][i-1].chomp
|
318
|
+
f.puts line.gsub(/\t/," ")
|
319
|
+
end
|
320
|
+
end
|
321
|
+
|
322
|
+
=begin rdoc
|
323
|
+
Attach a probe to a line in method +name+. The line can be specified
|
324
|
+
by line number or a pattern. If a string is passed as a third parameter
|
325
|
+
that string will be evaluated when the method is called from a block passed
|
326
|
+
to trace, otherwise a count probe is created.
|
327
|
+
=end
|
328
|
+
|
329
|
+
def Source.probe(name, spec, expr = :count)
|
330
|
+
begin
|
331
|
+
id = Source.find(name)
|
332
|
+
Source.lines(spec, id).each do |n|
|
333
|
+
n += @@base[id] - 1
|
334
|
+
@@probes[id][n] = expr
|
335
|
+
end
|
336
|
+
rescue Exception => e
|
337
|
+
puts e
|
338
|
+
end
|
339
|
+
return true
|
340
|
+
end
|
341
|
+
|
342
|
+
=begin rdoc
|
343
|
+
Return probes (if any) attached to the specified file, method, and line number.
|
344
|
+
Intended to be called from a trace func callback (which is why the file is one
|
345
|
+
of the parameters).
|
346
|
+
=end
|
347
|
+
|
348
|
+
def Source.probing(filename, method, line)
|
349
|
+
return nil if line == @@line
|
350
|
+
@@line = line
|
351
|
+
return nil unless @@probes[method] && @@file[method] == filename
|
352
|
+
return @@probes[method][line]
|
353
|
+
end
|
354
|
+
|
355
|
+
=begin rdoc
|
356
|
+
Print the currently defined probes.
|
357
|
+
=end
|
358
|
+
|
359
|
+
def Source.probes
|
360
|
+
@@probes.each do |name, plist|
|
361
|
+
plist.each do |line, exprs|
|
362
|
+
n = line - @@base[name] + 1
|
363
|
+
printf "%s %2d: %s\n", name, n, exprs
|
364
|
+
end
|
365
|
+
end
|
366
|
+
return true
|
367
|
+
end
|
368
|
+
|
369
|
+
=begin rdoc
|
370
|
+
Clear the probes on a designated method (or all methods)
|
371
|
+
=end
|
372
|
+
|
373
|
+
def Source.clear(name = nil)
|
374
|
+
@@probes.each do |id, plist|
|
375
|
+
next if ! name.nil? && id != name
|
376
|
+
plist.clear
|
377
|
+
end
|
378
|
+
return true
|
379
|
+
end
|
380
|
+
|
381
|
+
=begin
|
382
|
+
Internal use only -- locate the filename, starting line number, and length
|
383
|
+
of a method named +name+ (+name+ can be a string or a symbol), record the
|
384
|
+
information for any methods that need it. This information only needs to
|
385
|
+
be found once, so it is recorded in a set of class variables. Revisit this
|
386
|
+
decision if monitoring user-defined methods....
|
387
|
+
|
388
|
+
TODO: save helper files listed on :begin line
|
389
|
+
=end
|
390
|
+
|
391
|
+
def Source.find(name)
|
392
|
+
id = name.to_sym
|
393
|
+
return id if @@file[id] # return if we looked for this source previously
|
394
|
+
|
395
|
+
filename, base, size = nil, nil, nil
|
396
|
+
names = []
|
397
|
+
|
398
|
+
catch (:found) do
|
399
|
+
SCRIPT_LINES__.each do |file, lines|
|
400
|
+
line_num = 0
|
401
|
+
lines.each do |s|
|
402
|
+
line_num += 1
|
403
|
+
if match = s.match(/:begin\s+(.*)/)
|
404
|
+
names = match[1].split.collect{|x| eval(x)}
|
405
|
+
if names[0] == id
|
406
|
+
filename = file
|
407
|
+
base = line_num + 1
|
408
|
+
next
|
409
|
+
end
|
410
|
+
end
|
411
|
+
if s =~ /:end\s+:#{id.to_s}/
|
412
|
+
size = line_num - base
|
413
|
+
throw :found
|
414
|
+
end
|
415
|
+
end
|
416
|
+
end
|
417
|
+
end
|
418
|
+
|
419
|
+
raise "Can't find method named '#{name}'" if size.nil?
|
420
|
+
|
421
|
+
@@file[id] = filename
|
422
|
+
@@size[id] = size
|
423
|
+
@@base[id] = base
|
424
|
+
@@probes[id] = Hash.new
|
425
|
+
@@helpers[id] = names[1..-1]
|
426
|
+
return id
|
427
|
+
end
|
428
|
+
|
429
|
+
=begin rdoc
|
430
|
+
Internal use only -- make an array of line numbers to use for probing method +name+.
|
431
|
+
Argument can be a single line number, an array of line numbers, or a pattern. Checks
|
432
|
+
to make sure line numbers are valid.
|
433
|
+
=end
|
434
|
+
|
435
|
+
def Source.lines(spec, id)
|
436
|
+
if spec.class == Fixnum && Source.range_check(spec, id)
|
437
|
+
return [spec]
|
438
|
+
elsif spec.class == Array
|
439
|
+
res = Array.new
|
440
|
+
spec.each do |line|
|
441
|
+
raise "line number must be an integer" unless line.class == Fixnum
|
442
|
+
res << line if Source.range_check(line, id)
|
443
|
+
end
|
444
|
+
return res
|
445
|
+
elsif spec.class == String
|
446
|
+
res = Array.new
|
447
|
+
for i in @@base[id]..(@@base[id]+@@size[id]-1)
|
448
|
+
line = SCRIPT_LINES__[@@file[id]][i-1].chomp
|
449
|
+
res << i - @@base[id] + 1 if line.index(spec)
|
450
|
+
end
|
451
|
+
return res
|
452
|
+
else
|
453
|
+
raise "invalid spec: '#{spec}' (must be an integer, array of integers, or a pattern)"
|
454
|
+
end
|
455
|
+
end
|
456
|
+
|
457
|
+
def Source.range_check(n, id)
|
458
|
+
max = @@size[id]
|
459
|
+
raise "line number must be between 1 and #{max}" unless n >= 1 && n <= max
|
460
|
+
return true
|
461
|
+
end
|
462
|
+
|
463
|
+
=begin rdoc
|
464
|
+
Internal use only -- show info about method
|
465
|
+
=end
|
466
|
+
|
467
|
+
def Source.info(name)
|
468
|
+
unless id = Source.find(name)
|
469
|
+
puts "Can't find method named '#{name}'"
|
470
|
+
return
|
471
|
+
end
|
472
|
+
|
473
|
+
printf "file: %s\n", @@file[name]
|
474
|
+
printf "size: %d\n", @@size[name]
|
475
|
+
printf "base: %d\n", @@base[name]
|
476
|
+
printf "probes: %s\n", @@probes[name].inspect
|
477
|
+
end
|
478
|
+
|
479
|
+
end # Source
|
480
|
+
|
481
|
+
end # RubyLabs
|
482
|
+
|
483
|
+
include RubyLabs
|
484
|
+
|
485
|
+
class Fixnum
|
486
|
+
|
487
|
+
=begin rdoc
|
488
|
+
|
489
|
+
An 'ord' method for the Fixnum class that maps ASCII codes for letters
|
490
|
+
to numbers between 0 and 25.
|
491
|
+
|
492
|
+
<b>NOTE:</b> +ord+ is built in to Ruby 1.9, and will be sligthly different; for
|
493
|
+
characters (1-letter strings) +ord+ will return the ASCII value.
|
494
|
+
|
495
|
+
=end
|
496
|
+
|
497
|
+
def ord
|
498
|
+
if self >= ?a && self <= ?z
|
499
|
+
self - ?a
|
500
|
+
elsif self >= ?A && self <= ?Z
|
501
|
+
self - ?A
|
502
|
+
else
|
503
|
+
self
|
504
|
+
end
|
505
|
+
end
|
506
|
+
|
507
|
+
end # Fixnum
|
data/lib/sievelab.rb
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
|
2
|
+
=begin rdoc
|
3
|
+
|
4
|
+
== Sieve of Eratosthenes
|
5
|
+
|
6
|
+
Use the Sieve of Eratosthenes algorithm to generate a list of prime
|
7
|
+
numbers. The method is an introduction to iteration, using iterators
|
8
|
+
to make and filter lists of numbers, and a while loop to repeat the
|
9
|
+
filtering step until no more composite numbers are left in the worklist.
|
10
|
+
|
11
|
+
=end
|
12
|
+
|
13
|
+
include Math
|
14
|
+
|
15
|
+
module RubyLabs
|
16
|
+
|
17
|
+
module SieveLab
|
18
|
+
|
19
|
+
# Call sieve(n) to create an array of prime numbers between 2 and n
|
20
|
+
|
21
|
+
# :begin :sieve
|
22
|
+
def sieve(n)
|
23
|
+
return [] if n < 2
|
24
|
+
worklist = []
|
25
|
+
(n-1).times { |i| worklist << i+2 }
|
26
|
+
primes = []
|
27
|
+
|
28
|
+
while worklist.first < sqrt(n)
|
29
|
+
primes << worklist.first
|
30
|
+
worklist.delete_if { |x| x % primes.last == 0 }
|
31
|
+
end
|
32
|
+
|
33
|
+
return primes + worklist
|
34
|
+
end
|
35
|
+
# :end :sieve
|
36
|
+
|
37
|
+
|
38
|
+
# A first version of the sieve, iterates until the worklist is empty
|
39
|
+
|
40
|
+
# :begin :proto_sieve
|
41
|
+
def proto_sieve(n)
|
42
|
+
return [] if n < 2
|
43
|
+
worklist = []
|
44
|
+
(n-1).times { |i| worklist << i+2 }
|
45
|
+
primes = []
|
46
|
+
|
47
|
+
while worklist.length > 0
|
48
|
+
primes << worklist.first
|
49
|
+
worklist.delete_if { |x| x % primes.last == 0 }
|
50
|
+
end
|
51
|
+
|
52
|
+
return primes
|
53
|
+
end
|
54
|
+
# :end :proto_sieve
|
55
|
+
|
56
|
+
end # SieveLab
|
57
|
+
|
58
|
+
end # RubyLabs
|