sieve 0.0.2 → 0.1.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.
data/README.markdown CHANGED
@@ -13,7 +13,7 @@ Install with Rubygems:
13
13
  A method is added to the Numeric class.
14
14
 
15
15
  5.sieve # [2, 3, 5]
16
- 20.sieve # [2, 3, 5, 7, 11, 13, 17]
16
+ 20.sieve # [2, 3, 5, 7, 11, 13, 17, 19]
17
17
 
18
18
  ## Benchmarks
19
19
 
@@ -37,17 +37,30 @@ As far as I know, this is the most optimized pure Ruby sieve written.
37
37
 
38
38
  The benchmarks were run on a 2.8GHz Intel Core 2 Duo MacBook Pro with 8 GB memory.
39
39
 
40
- Ruby 1.8.7p253 REE 2010.02
40
+ ruby 1.8.6 (2010-02-05 patchlevel 399) [i686-darwin10.4.0]
41
41
 
42
42
  user system total real
43
- sieve method 32.820000 0.710000 33.530000 ( 33.727176)
44
- Numeric#sieve 1.040000 0.420000 1.460000 ( 1.476743)
43
+ sieve method 41.430000 0.600000 42.030000 ( 42.261872)
44
+ Numeric#sieve 1.010000 0.250000 1.260000 ( 1.342326)
45
45
 
46
- Ruby 1.9.2p0
46
+ ruby 1.8.7 (2010-08-16 patchlevel 302) [i686-darwin10.4.0]
47
47
 
48
48
  user system total real
49
- sieve method 21.460000 0.620000 22.080000 ( 22.170883)
50
- Numeric#sieve 0.940000 0.320000 1.260000 ( 1.262891)
49
+ sieve method 41.720000 0.730000 42.450000 ( 43.640117)
50
+ Numeric#sieve 0.960000 0.380000 1.340000 ( 1.385924)
51
+
52
+ ruby 1.8.7 (2010-04-19 patchlevel 253) [i686-darwin10.4.0], MBARI 0x6770, Ruby Enterprise Edition 2010.02
53
+
54
+ user system total real
55
+ sieve method 42.800000 0.910000 43.710000 ( 45.105879)
56
+ Numeric#sieve 1.090000 0.370000 1.460000 ( 1.517832)
57
+
58
+
59
+ ruby 1.9.2p0 (2010-08-18 revision 29036) [x86_64-darwin10.4.0]
60
+
61
+ user system total real
62
+ sieve method 22.800000 0.670000 23.470000 ( 24.132390)
63
+ Numeric#sieve 1.000000 0.380000 1.380000 ( 1.422877)
51
64
 
52
65
  ## Author
53
66
 
data/Rakefile CHANGED
@@ -1,5 +1,7 @@
1
1
  require "rubygems"
2
2
  require "rake"
3
+ require "benchmark"
4
+ require "sieve"
3
5
 
4
6
  require "rake/extensiontask"
5
7
  Rake::ExtensionTask.new("sieve") do |extension|
@@ -12,3 +14,34 @@ Cucumber::Rake::Task.new(:cucumber => [:clean, :compile]) do |t|
12
14
  end
13
15
 
14
16
  task :default => :cucumber
17
+
18
+ desc "Benchmark C implementation against pure Ruby implementation of the Sieve"
19
+ task(:benchmark => [:clean, :compile]) do
20
+ def sieve(n)
21
+ numbers = (0..n).map {|i| i }
22
+ numbers[0] = numbers[1] = nil
23
+ numbers.each do |num|
24
+ next unless num
25
+ break if num**2 > n
26
+ (num**2).step(n, num) {|idx| numbers[idx] = nil }
27
+ end
28
+ numbers.compact
29
+ end
30
+
31
+ Benchmark.bmbm(15) do |benchmark|
32
+ range = (0..1000000)
33
+ step = 10000
34
+
35
+ benchmark.report("sieve method") do
36
+ range.step(step) do |i|
37
+ sieve(i)
38
+ end
39
+ end
40
+
41
+ benchmark.report("Numeric#sieve") do
42
+ range.step(step) do |i|
43
+ i.sieve
44
+ end
45
+ end
46
+ end
47
+ end
data/ext/sieve/sieve.c CHANGED
@@ -10,22 +10,23 @@ void Init_sieve() {
10
10
  }
11
11
 
12
12
  static VALUE sieve(const VALUE self) {
13
- if(rb_num2long(self) < 0) { return Qnil; }
14
- long number = rb_num2long(self) + 1,
13
+ if(NUM2LONG(self) < 2) { return Qnil; }
14
+ long number = NUM2LONG(self) + 1,
15
15
  * numbers = malloc(number * sizeof(long));
16
16
 
17
- if(numbers == NULL) { return Qnil; }
18
-
19
- long i;
20
- for(i = 0; i < number; i++) {
21
- numbers[i] = i;
17
+ if(numbers == NULL) {
18
+ rb_raise(rb_eNoMemError, "Can't allocate enough memory.");
22
19
  }
20
+
23
21
  numbers[0] = numbers[1] = -1;
22
+ long i;
23
+ for(i = 2; i < number; i++) { numbers[i] = i; }
24
24
 
25
25
  long current_square;
26
26
  for(i = 0; i < number; i++) {
27
+ if(numbers[i] == -1) { continue; }
28
+
27
29
  current_square = powl(i, 2);
28
- if(numbers[i] == -1) { continue; }
29
30
  if(current_square > number) { break; }
30
31
 
31
32
  long n;
@@ -36,9 +37,8 @@ static VALUE sieve(const VALUE self) {
36
37
 
37
38
  VALUE primes_array = rb_ary_new();
38
39
  for(i = 0; i < number; i++) {
39
- if(numbers[i] != -1) {
40
- rb_ary_push(primes_array, LONG2FIX(numbers[i]));
41
- }
40
+ if(numbers[i] == -1) { continue; }
41
+ rb_ary_push(primes_array, LONG2FIX(numbers[i]));
42
42
  }
43
43
 
44
44
  free(numbers);
@@ -4,15 +4,15 @@ Feature: Sieve of Eratosthenes
4
4
  I should be able to call a sieve on a numeric to find its primes
5
5
 
6
6
  Scenario Outline: Find primes effectively
7
- When I run a sieve on <number>
7
+ When I calculate the sieve for <number>
8
8
  Then I should have the primes <primes>
9
9
  Examples:
10
10
  | number | primes |
11
11
  | -12345 | nil |
12
12
  | -5 | nil |
13
13
  | -1 | nil |
14
- | 0 | |
15
- | 1 | |
14
+ | 0 | nil |
15
+ | 1 | nil |
16
16
  | 2 | 2 |
17
17
  | 3 | 2,3 |
18
18
  | 4 | 2,3 |
@@ -23,7 +23,11 @@ Feature: Sieve of Eratosthenes
23
23
  | 30 | 2,3,5,7,11,13,17,19,23,29 |
24
24
  | 110 | 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,107,109 |
25
25
 
26
+ Scenario: Allocating memory for the sieve raises an exception if it fails
27
+ When I calculate the sieve for 1000000000000000000
28
+ Then a NoMemoryError should be raised
29
+
26
30
  Scenario: Prime tables
27
31
  When I load all the primes from "features/support/primes.txt"
28
- And I run a sieve on the last number
32
+ And I calculate the sieve for the last number
29
33
  Then I should have all primes from "features/support/primes.txt"
@@ -1,15 +1,16 @@
1
- When /^I run a sieve on (\-?\d+)$/ do |number|
2
- @result = number.to_i.sieve
1
+ When /^I calculate the sieve for (\-?\d+)$/ do |number|
2
+ begin
3
+ @result = number.to_i.sieve
4
+ rescue Exception => @sieve_exception
5
+ end
3
6
  end
4
7
 
5
8
  Then /^I should have the primes (.*)$/ do |primes|
6
9
  case primes
7
10
  when "nil"
8
11
  @result.should be_nil
9
- when ""
10
- @result.should be_empty
11
12
  else
12
- @primes = primes.split(",").map(&:strip).map(&:to_i)
13
+ @primes = primes.split(",").map {|prime| prime.to_i }
13
14
  @result.should == @primes
14
15
  end
15
16
  end
@@ -19,17 +20,27 @@ When /^I load all the primes from "([^"]*)"$/ do |path|
19
20
  @primes.should_not be_empty
20
21
  end
21
22
 
22
- When /^I run a sieve on the last number$/ do
23
- @result = @primes.last.sieve
23
+ When /^I calculate the sieve for the last number$/ do
24
+ When %{I calculate the sieve for #{@primes.last}}
24
25
  end
25
26
 
26
27
  Then /^I should have all primes from "([^"]*)"$/ do |path|
27
28
  Then %{I should have the primes #{prime_file_process(path).join(",")}}
28
29
  end
29
30
 
31
+ Then /^a NoMemoryError should be raised$/ do
32
+ @sieve_exception.should be_a(NoMemoryError)
33
+ end
34
+
30
35
  module PrimeFileProcessor
31
36
  def prime_file_process(path)
32
- File.new(path).read.strip.split(/\s+/).map(&:to_i)
37
+ @processed_cache ||= {}
38
+
39
+ if @processed_cache[path]
40
+ @processed_cache[path]
41
+ else
42
+ @processed_cache[path] = File.new(path).read.strip.split(/\s+/).map {|prime| prime.to_i }
43
+ end
33
44
  end
34
45
  end
35
46
 
data/lib/sieve.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require "sieve/sieve"
2
2
 
3
3
  module Sieve
4
+ VERSION = "0.1.0"
4
5
  end
metadata CHANGED
@@ -1,13 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sieve
3
3
  version: !ruby/object:Gem::Version
4
- hash: 27
5
4
  prerelease: false
6
5
  segments:
7
6
  - 0
7
+ - 1
8
8
  - 0
9
- - 2
10
- version: 0.0.2
9
+ version: 0.1.0
11
10
  platform: ruby
12
11
  authors:
13
12
  - Josh Clayton
@@ -15,11 +14,11 @@ autorequire:
15
14
  bindir: bin
16
15
  cert_chain: []
17
16
 
18
- date: 2010-08-28 00:00:00 -04:00
17
+ date: 2010-08-29 00:00:00 -04:00
19
18
  default_executable:
20
19
  dependencies: []
21
20
 
22
- description:
21
+ description: Ruby C Extension for the Sieve of Eratosthenes
23
22
  email: joshua.clayton@gmail.com
24
23
  executables: []
25
24
 
@@ -32,7 +31,6 @@ files:
32
31
  - MIT-LICENSE
33
32
  - README.markdown
34
33
  - Rakefile
35
- - benchmark.rb
36
34
  - ext/sieve/extconf.rb
37
35
  - ext/sieve/sieve.c
38
36
  - ext/sieve/sieve.h
@@ -56,7 +54,6 @@ required_ruby_version: !ruby/object:Gem::Requirement
56
54
  requirements:
57
55
  - - ">="
58
56
  - !ruby/object:Gem::Version
59
- hash: 3
60
57
  segments:
61
58
  - 0
62
59
  version: "0"
@@ -65,7 +62,6 @@ required_rubygems_version: !ruby/object:Gem::Requirement
65
62
  requirements:
66
63
  - - ">="
67
64
  - !ruby/object:Gem::Version
68
- hash: 3
69
65
  segments:
70
66
  - 0
71
67
  version: "0"
data/benchmark.rb DELETED
@@ -1,32 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require "rubygems"
4
- require "benchmark"
5
- require "sieve"
6
-
7
- def sieve(n)
8
- numbers = (0..n).map(&:to_i)
9
- numbers[0] = numbers[1] = nil
10
- numbers.each do |num|
11
- next unless num
12
- break if num**2 > n
13
- (num**2).step(n, num) {|idx| numbers[idx] = nil }
14
- end
15
- numbers.compact
16
- end
17
-
18
- Benchmark.bm(15) do |benchmark|
19
- range = (0..1000000)
20
- step = 10000
21
- benchmark.report("sieve method") do
22
- range.step(step).each do |i|
23
- sieve(i)
24
- end
25
- end
26
-
27
- benchmark.report("Numeric#sieve") do
28
- range.step(step).each do |i|
29
- i.sieve
30
- end
31
- end
32
- end