large_binomials 1.0.0 → 1.0.1

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.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: