sieve 0.0.2 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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