large_binomials 1.0.0 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -13,11 +13,9 @@ and larger.
13
13
  Installation
14
14
  ------------
15
15
 
16
- Do the following to install this gem:
16
+ You can install this gem from RubyGems doing the following:
17
17
 
18
- 1. Make a clone of the repository
19
- 2. Build the gem: `gem build large_binomials.gemspec`
20
- 3. Install the gem: `gem install ./large_binomials-0.9.gem`
18
+ gem install large_binomials
21
19
 
22
20
  Usage
23
21
  -----
data/Rakefile CHANGED
@@ -1,5 +1,7 @@
1
+ # encoding: utf-8
2
+ #
1
3
  # Ruby Library to Calculate Large Binomials
2
- # Copyright © 2013 Filip van Laenen <f.a.vanlaenen@ieee.org>
4
+ # Copyright (c) 2013 Filip van Laenen <f.a.vanlaenen@ieee.org>
3
5
  #
4
6
  # This file is part of the Ruby Library to Calculate Large Binomials.
5
7
  #
@@ -7,39 +9,41 @@
7
9
  # redistribute it and/or modify it under the terms of the GNU General Public
8
10
  # License as published by the Free Software Foundation, either version 3 of the
9
11
  # License, or (at your option) any later version.
10
- #
12
+ #
11
13
  # The Ruby Library to Calculate Large Binomials is distributed in the hope that
12
- # it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
13
- # of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
14
- # Public License for more details.
15
- #
14
+ # it will be useful, but WITHOUT ANY WARRANTY; without even the implied
15
+ # warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16
+ # General Public License for more details.
17
+ #
16
18
  # You can find a copy of the GNU General Public License in /LICENSE
17
19
  #
18
20
 
19
21
  require 'rspec/core/rake_task'
20
-
22
+
21
23
  desc 'Default: run specs.'
22
24
  task :default => :spec
23
-
25
+
24
26
  desc 'Run specs'
25
27
  RSpec::Core::RakeTask.new do |t|
26
- t.pattern = "./spec/**/*_spec.rb"
28
+ t.pattern = './spec/**/*_spec.rb'
27
29
  end
28
30
 
29
31
  def find_integer_methods
30
- require_relative 'lib/core_ext/integer'
31
- integer_methods = Integer.instance_methods(false)
32
- integer_methods.select!{ | m | 1.method(m).source_location != nil }
33
- integer_methods.select!{ | m | 1.method(m).source_location[0].include? 'large_binomials'}
34
- integer_methods.collect{ | m | "::Integer##{m}"}
32
+ require_relative 'lib/core_ext/integer'
33
+ integer_methods = Integer.instance_methods(false)
34
+ integer_methods.select! { | m | 1.method(m).source_location.nil? }
35
+ integer_methods.select! do | m |
36
+ 1.method(m).source_location[0].include? 'large_binomials'
37
+ end
38
+ integer_methods.map { | m | "::Integer##{m}" }
35
39
  end
36
40
 
37
41
  desc 'Run Mutant'
38
42
  task :mutant do
39
- require 'mutant'
40
- find_integer_methods
41
- status = Mutant::CLI.run(['::LargeBinomials*', find_integer_methods, '--rspec-unit'].flatten)
42
- if status.nonzero?
43
- abort 'Mutant task is not successful'
44
- end
45
- end
43
+ require 'mutant'
44
+ find_integer_methods
45
+ status = Mutant::CLI.run(['--require', 'large_binomials',
46
+ '::LargeBinomials*', find_integer_methods,
47
+ '--rspec'].flatten)
48
+ abort 'Mutant task is not successful' if status.nonzero?
49
+ end
@@ -20,7 +20,7 @@
20
20
 
21
21
  Gem::Specification.new do |gem|
22
22
  gem.name = 'large_binomials'
23
- gem.version = '1.0.0'
23
+ gem.version = '1.0.1'
24
24
  gem.authors = [ 'Filip van Laenen' ]
25
25
  gem.email = [ 'f.a.vanlaenen@ieee.org' ]
26
26
 
@@ -1,7 +1,7 @@
1
1
  # encoding: utf-8
2
2
  #
3
3
  # Ruby Library to Calculate Large Binomials
4
- # Copyright © 2013 Filip van Laenen <f.a.vanlaenen@ieee.org>
4
+ # Copyright (C) 2013 Filip van Laenen <f.a.vanlaenen@ieee.org>
5
5
  #
6
6
  # This file is part of the Ruby Library to Calculate Large Binomials.
7
7
  #
@@ -9,119 +9,118 @@
9
9
  # redistribute it and/or modify it under the terms of the GNU General Public
10
10
  # License as published by the Free Software Foundation, either version 3 of the
11
11
  # License, or (at your option) any later version.
12
- #
12
+ #
13
13
  # The Ruby Library to Calculate Large Binomials is distributed in the hope that
14
- # it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
15
- # of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
16
- # Public License for more details.
17
- #
14
+ # it will be useful, but WITHOUT ANY WARRANTY; without even the implied
15
+ # warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16
+ # General Public License for more details.
17
+ #
18
18
  # You can find a copy of the GNU General Public License in /LICENSE
19
19
  #
20
20
 
21
21
  class Integer
22
+ def to_lf
23
+ LargeBinomials::LargeFloat.new(self)
24
+ end
22
25
 
23
- def to_lf
24
- LargeBinomials::LargeFloat.new(self)
25
- end
26
-
27
- def binomial(k)
28
- binomial = breaking_binomial_by_product_of_divisions(k)
29
- if binomial == nil
30
- large_float_binomial_by_product_of_divisions(k)
31
- else
32
- binomial
33
- end
34
- end
35
-
36
- # Copied from http://rosettacode.org/wiki/Evaluate_binomial_coefficients#Ruby (on 7 June 2013)
37
- def binomial_by_product_of_divisions(k)
38
- (0...k).inject(1) do |m,i|
39
- (m * (self - i)) / (i + 1)
40
- end
41
- end
26
+ def binomial(k)
27
+ binomial = breaking_binomial_by_product_of_divisions(k)
28
+ if binomial.nil?
29
+ large_float_binomial_by_product_of_divisions(k)
30
+ else
31
+ binomial
32
+ end
33
+ end
42
34
 
43
- # Breaking version of binomial_by_product_of_divisions
44
- def breaking_binomial_by_product_of_divisions(k)
45
- (0...k).inject(1) do |m,i|
46
- if m > Float::MAX
47
- return nil
48
- end
49
- (m * (self - i)) / (i + 1)
50
- end
51
- end
35
+ # Copied from http://rosettacode.org/wiki/Evaluate_binomial_coefficients#Ruby
36
+ # (on 7 June 2013)
37
+ def binomial_by_product_of_divisions(k)
38
+ (0...k).reduce(1) do |m, i|
39
+ (m * (self - i)) / (i + 1)
40
+ end
41
+ end
52
42
 
53
- # LargeFloat version of binomial_by_product_of_divisions
54
- def large_float_binomial_by_product_of_divisions(k)
55
- (0...k).inject(1.to_lf) do |m,i|
56
- (m * (self - i)) / (i + 1)
57
- end
58
- end
43
+ # Breaking version of binomial_by_product_of_divisions
44
+ def breaking_binomial_by_product_of_divisions(k)
45
+ (0...k).reduce(1) do |m, i|
46
+ return nil if m > Float::MAX
47
+ (m * (self - i)) / (i + 1)
48
+ end
49
+ end
59
50
 
60
- # Float version of binomial_by_product_of_divisions
61
- def float_binomial_by_product_of_divisions(k)
62
- (0...k).inject(1.to_f) do |m,i|
63
- (m * (self - i)) / (i + 1)
64
- end
65
- end
51
+ # LargeFloat version of binomial_by_product_of_divisions
52
+ def large_float_binomial_by_product_of_divisions(k)
53
+ (0...k).reduce(1.to_lf) do |m, i|
54
+ (m * (self - i)) / (i + 1)
55
+ end
56
+ end
66
57
 
67
- # From http://rosettacode.org/wiki/Evaluate_binomial_coefficients#Ruby (on 7 June 2013)
68
- def binomial_by_division_of_products(k)
69
- # n!/(n-k)!
70
- pTop = (self-k+1 .. self).inject(1, &:*)
71
- # k!
72
- pBottom = (2 .. k).inject(1, &:*)
73
- pTop / pBottom
74
- end
58
+ # Float version of binomial_by_product_of_divisions
59
+ def float_binomial_by_product_of_divisions(k)
60
+ (0...k).reduce(1.to_f) do |m, i|
61
+ (m * (self - i)) / (i + 1)
62
+ end
63
+ end
75
64
 
76
- # Parallel version of binomial_by_division_of_products
77
- # Note that threads in Ruby 1.9 don't spread over multiple processors, so
78
- # due to context switching this parallel version will often be a bit slower
79
- # than the sequential one.
80
- def binomial_by_division_of_parallel_products(k)
81
- # n!/(n-k)!
82
- top_thread = Thread.new do
83
- Thread.current[:output] = (self-k+1 .. self).inject(1, &:*)
84
- end
85
- # k!
86
- bottom_thread = Thread.new do
87
- Thread.current[:output] = (2 .. k).inject(1, &:*)
88
- end
89
- top_thread.join
90
- bottom_thread.join
91
- top_thread[:output] / bottom_thread[:output]
92
- end
65
+ # From http://rosettacode.org/wiki/Evaluate_binomial_coefficients#Ruby (on 7
66
+ # June 2013)
67
+ def binomial_by_division_of_products(k)
68
+ # n!/(n-k)!
69
+ p_top = (self - k + 1 .. self).inject(1, &:*)
70
+ # k!
71
+ p_bottom = (2 .. k).inject(1, &:*)
72
+ p_top / p_bottom
73
+ end
93
74
 
94
- # LargeFloat version of binomial_by_division_of_products
95
- def large_float_binomial_by_division_of_products(k)
96
- # n!/(n-k)!
97
- pTop = (self-k+1 .. self).inject(1.to_lf, &:*)
98
- # k!
99
- pBottom = (2 .. k).inject(1.to_lf, &:*)
100
- pTop / pBottom
101
- end
75
+ # Parallel version of binomial_by_division_of_products
76
+ # Note that threads in Ruby 1.9 don't spread over multiple processors, so
77
+ # due to context switching this parallel version will often be a bit slower
78
+ # than the sequential one.
79
+ def binomial_by_division_of_parallel_products(k)
80
+ # n!/(n-k)!
81
+ top_thread = Thread.new do
82
+ Thread.current[:output] = (self - k + 1 .. self).inject(1, &:*)
83
+ end
84
+ # k!
85
+ bottom_thread = Thread.new do
86
+ Thread.current[:output] = (2 .. k).inject(1, &:*)
87
+ end
88
+ top_thread.join
89
+ bottom_thread.join
90
+ top_thread[:output] / bottom_thread[:output]
91
+ end
102
92
 
103
- # Float version of binomial_by_division_of_products
104
- def float_binomial_by_division_of_products(k)
105
- # n!/(n-k)!
106
- pTop = (self-k+1 .. self).inject(1.to_f, &:*)
107
- # k!
108
- pBottom = (2 .. k).inject(1.to_f, &:*)
109
- pTop / pBottom
110
- end
93
+ # LargeFloat version of binomial_by_division_of_products
94
+ def large_float_binomial_by_division_of_products(k)
95
+ # n!/(n-k)!
96
+ p_top = (self - k + 1 .. self).inject(1.to_lf, &:*)
97
+ # k!
98
+ p_bottom = (2 .. k).inject(1.to_lf, &:*)
99
+ p_top / p_bottom
100
+ end
111
101
 
112
- # Copied from http://www.brpreiss.com/books/opus8/html/page459.html (on 7 June 2013)
113
- def binomial_by_pascals_triangle(k)
114
- b = []
115
- b[0] = 1
116
- for i in 1 .. self
117
- b[i] = 1
118
- j = i - 1
119
- while j > 0
120
- b[j] += b[j - 1]
121
- j -= 1
122
- end
123
- end
124
- b[k]
125
- end
102
+ # Float version of binomial_by_division_of_products
103
+ def float_binomial_by_division_of_products(k)
104
+ # n!/(n-k)!
105
+ p_top = (self - k + 1 .. self).inject(1.to_f, &:*)
106
+ # k!
107
+ p_bottom = (2 .. k).inject(1.to_f, &:*)
108
+ p_top / p_bottom
109
+ end
126
110
 
127
- end
111
+ # Copied from http://www.brpreiss.com/books/opus8/html/page459.html (on 7
112
+ # June 2013)
113
+ def binomial_by_pascals_triangle(k)
114
+ b = []
115
+ b[0] = 1
116
+ (1 .. self).each do | i |
117
+ b[i] = 1
118
+ j = i - 1
119
+ while j > 0
120
+ b[j] += b[j - 1]
121
+ j -= 1
122
+ end
123
+ end
124
+ b[k]
125
+ end
126
+ end
@@ -1,7 +1,7 @@
1
1
  # encoding: utf-8
2
2
  #
3
3
  # Ruby Library to Calculate Large Binomials
4
- # Copyright © 2013 Filip van Laenen <f.a.vanlaenen@ieee.org>
4
+ # Copyright (c) 2013 Filip van Laenen <f.a.vanlaenen@ieee.org>
5
5
  #
6
6
  # This file is part of the Ruby Library to Calculate Large Binomials.
7
7
  #
@@ -9,121 +9,119 @@
9
9
  # redistribute it and/or modify it under the terms of the GNU General Public
10
10
  # License as published by the Free Software Foundation, either version 3 of the
11
11
  # License, or (at your option) any later version.
12
- #
12
+ #
13
13
  # The Ruby Library to Calculate Large Binomials is distributed in the hope that
14
- # it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
15
- # of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
16
- # Public License for more details.
17
- #
14
+ # it will be useful, but WITHOUT ANY WARRANTY; without even the implied
15
+ # warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16
+ # General Public License for more details.
17
+ #
18
18
  # You can find a copy of the GNU General Public License in /LICENSE
19
19
  #
20
20
 
21
21
  module LargeBinomials
22
- class LargeFloat
23
- include Comparable
24
-
25
- attr_accessor :exponent, :mantissa
26
-
27
- def initialize(m, e = 0)
28
- @mantissa = m.to_f
29
- @exponent = e
30
- end
31
-
32
- def clone
33
- LargeFloat.new(@mantissa, @exponent)
34
- end
35
-
36
- def normalize
37
- unless @mantissa == 0
38
- normalization = Math.log10(@mantissa).floor
39
- @mantissa /= 10 ** normalization
40
- @exponent += normalization
41
- end
42
- end
43
-
44
- def *(x)
45
- if (x.instance_of? LargeFloat)
46
- multiply_with_large_float(x)
47
- else
48
- multiply_with_numeric(x)
49
- end
50
- end
51
-
52
- def multiply_with_large_float(lf)
53
- product = self * lf.mantissa
54
- product.exponent += lf.exponent
55
- product
56
- end
57
-
58
- def multiply_with_numeric(i)
59
- product = clone
60
- new_mantissa = product.mantissa * i
61
- if new_mantissa == Float::INFINITY
62
- product.normalize
63
- end
64
- product.mantissa *= i
65
- product
66
- end
67
-
68
- def /(x)
69
- if (x.instance_of? LargeFloat)
70
- divide_by_large_float(x)
71
- else
72
- divide_by_numeric(x)
73
- end
74
- end
75
-
76
- def divide_by_large_float(lf)
77
- quotient = self / lf.mantissa
78
- quotient.exponent -= lf.exponent
79
- quotient
80
- end
81
-
82
- def divide_by_numeric(n)
83
- quotient = clone
84
- quotient.mantissa /= n
85
- quotient
86
- end
87
-
88
- def new_mantissa_for_addition(lf)
89
- @mantissa + lf.mantissa * 10 ** (lf.exponent - @exponent)
90
- end
91
-
92
- def +(lf)
93
- if self < lf
94
- lf + self
95
- else
96
- LargeFloat.new(new_mantissa_for_addition(lf), @exponent)
97
- end
98
- end
99
-
100
- def superscript(i)
101
- s = i.to_s
102
- s = s.gsub(/1/, '¹')
103
- s = s.gsub(/2/, '²')
104
- s = s.gsub(/3/, '³')
105
- s = s.gsub(/4/, '⁴')
106
- s = s.gsub(/5/, '⁵')
107
- s = s.gsub(/6/, '')
108
- s = s.gsub(/7/, '⁷')
109
- s = s.gsub(/8/, '')
110
- s = s.gsub(/9/, '⁹')
111
- s.gsub(/0/, '⁰')
112
- end
113
-
114
- def to_s
115
- normalize
116
- "#{@mantissa}×10#{superscript(@exponent)}"
117
- end
118
-
119
- def <=>(lf)
120
- normalize
121
- lf.normalize
122
- if @exponent == lf.exponent
123
- @mantissa - lf.mantissa
124
- else
125
- @exponent - lf.exponent
126
- end
127
- end
128
- end
129
- end
22
+ # Class modeling floats larger than Ruby's regular float. They consist of a
23
+ # regular float (the mantissa) plus an additional exponent of 10.
24
+ class LargeFloat
25
+ include Comparable
26
+
27
+ attr_accessor :exponent, :mantissa
28
+
29
+ def initialize(m, e = 0)
30
+ @mantissa = m.to_f
31
+ @exponent = e
32
+ end
33
+
34
+ def clone
35
+ LargeFloat.new(@mantissa, @exponent)
36
+ end
37
+
38
+ def normalize
39
+ unless @mantissa == 0
40
+ normalization = Math.log10(@mantissa.abs).floor
41
+ @mantissa /= 10**normalization
42
+ @exponent += normalization
43
+ end
44
+ end
45
+
46
+ def *(other)
47
+ if other.instance_of? LargeFloat
48
+ multiply_with_large_float(other)
49
+ else
50
+ multiply_with_numeric(other)
51
+ end
52
+ end
53
+
54
+ def multiply_with_large_float(lf)
55
+ product = self * lf.mantissa
56
+ product.exponent += lf.exponent
57
+ product
58
+ end
59
+
60
+ def multiply_with_numeric(i)
61
+ product = clone
62
+ new_mantissa = product.mantissa * i
63
+ product.normalize if new_mantissa == Float::INFINITY
64
+ new_mantissa = product.mantissa * i
65
+ if new_mantissa == Float::INFINITY
66
+ product.exponent += 1
67
+ i /= 10
68
+ end
69
+ product.mantissa *= i
70
+ product
71
+ end
72
+
73
+ def /(other)
74
+ if other.instance_of? LargeFloat
75
+ divide_by_large_float(other)
76
+ else
77
+ divide_by_numeric(other)
78
+ end
79
+ end
80
+
81
+ def divide_by_large_float(lf)
82
+ quotient = self / lf.mantissa
83
+ quotient.exponent -= lf.exponent
84
+ quotient
85
+ end
86
+
87
+ def divide_by_numeric(n)
88
+ quotient = clone
89
+ quotient.mantissa /= n
90
+ quotient
91
+ end
92
+
93
+ def new_mantissa_for_addition(lf)
94
+ @mantissa + lf.mantissa * 10**(lf.exponent - @exponent)
95
+ end
96
+
97
+ def +(other)
98
+ if self < other
99
+ other + self
100
+ else
101
+ LargeFloat.new(new_mantissa_for_addition(other), @exponent)
102
+ end
103
+ end
104
+
105
+ def superscript(i)
106
+ s = i.to_s
107
+ s = s.gsub(/1/, '¹').gsub(/2/, '²').gsub(/3/, '³').gsub(/4/, '⁴')
108
+ s = s.gsub(/5/, '⁵').gsub(/6/, '⁶').gsub(/7/, '⁷').gsub(/8/, '⁸')
109
+ s.gsub(/9/, '⁹').gsub(/0/, '').gsub(/-/, '⁻')
110
+ end
111
+
112
+ def to_s
113
+ normalize
114
+ "#{@mantissa}×10#{superscript(@exponent)}"
115
+ end
116
+
117
+ def <=>(other)
118
+ normalize
119
+ other.normalize
120
+ if @exponent == other.exponent
121
+ @mantissa - other.mantissa
122
+ else
123
+ @exponent - other.exponent
124
+ end
125
+ end
126
+ end
127
+ end
@@ -76,6 +76,12 @@ describe LargeBinomials::LargeFloat, '#multiply_by_numeric' do
76
76
  big_number_squared = big_number * 1E+300
77
77
  big_number_squared.exponent.should eq(303)
78
78
  end
79
+
80
+ it 'normalizes twice if needed' do
81
+ big_number = LargeBinomials::LargeFloat.new(2, 3)
82
+ big_number_squared = big_number * 1E+308
83
+ big_number_squared.should eq(LargeBinomials::LargeFloat.new(2, 311))
84
+ end
79
85
 
80
86
  it "doesn't change the exponent of the original LargeFloat in case of overflow" do
81
87
  big_number = LargeBinomials::LargeFloat.new(1E+300, 3)
@@ -185,9 +191,17 @@ describe LargeBinomials::LargeFloat, '#to_s' do
185
191
  10.to_lf.to_s.should eq('1.0×10¹')
186
192
  end
187
193
 
194
+ it 'converts 0.1 to a string as 1.0×10⁻¹' do
195
+ LargeBinomials::LargeFloat.new(1, -1).to_s.should eq('1.0×10⁻¹')
196
+ end
197
+
188
198
  it 'converts 1¹²³⁴⁵⁶⁷⁸⁹⁰ to a string as 1.0×10¹²³⁴⁵⁶⁷⁸⁹⁰' do
189
199
  LargeBinomials::LargeFloat.new(1, 1234567890).to_s.should eq('1.0×10¹²³⁴⁵⁶⁷⁸⁹⁰')
190
200
  end
201
+
202
+ it 'converts 1¹²³⁴⁵⁶⁷⁸⁹⁰¹²³⁴⁵⁶⁷⁸⁹⁰ to a string as 1.0×10¹²³⁴⁵⁶⁷⁸⁹⁰¹²³⁴⁵⁶⁷⁸⁹⁰' do
203
+ LargeBinomials::LargeFloat.new(1, 12345678901234567890).to_s.should eq('1.0×10¹²³⁴⁵⁶⁷⁸⁹⁰¹²³⁴⁵⁶⁷⁸⁹⁰')
204
+ end
191
205
  end
192
206
 
193
207
  describe LargeBinomials::LargeFloat, '#+' do
@@ -279,3 +293,9 @@ describe LargeBinomials::LargeFloat, '#<=>' do
279
293
  (one < ten).should be_true
280
294
  end
281
295
  end
296
+
297
+ describe LargeBinomials::LargeFloat, '#normalize' do
298
+ it 'normalizes negative numbers' do
299
+ -1.to_lf.should eq LargeBinomials::LargeFloat.new(-1, 0)
300
+ end
301
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: large_binomials
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.0.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-07-31 00:00:00.000000000 Z
12
+ date: 2014-06-09 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: Large binomials
15
15
  email: