diff --git a/Rakefile b/Rakefile index 241287b..6708a69 100644 --- a/Rakefile +++ b/Rakefile @@ -1,5 +1,4 @@ require "bundler/gem_tasks" -require_relative "lib/histogram/version" require 'rspec/core' require 'rspec/core/rake_task' diff --git a/histogram.gemspec b/histogram.gemspec index 6fe5f46..b4b182b 100644 --- a/histogram.gemspec +++ b/histogram.gemspec @@ -19,12 +19,16 @@ Gem::Specification.new do |spec| spec.require_paths = ["lib"] - [ "bundler ~> 1.3", + [ "bundler ~> 1.3", "rake ~> 10.1.0", "simplecov ~> 0.7.1", "rspec ~> 2.13.0", - "narray", + "rdoc" ].each do |argline| spec.add_development_dependency *argline.split(' ', 2).compact end + + unless RUBY_PLATFORM =~ /java/ + spec.add_development_dependency "narray" + end end diff --git a/lib/histogram.rb b/lib/histogram.rb index ee3ff56..405721d 100644 --- a/lib/histogram.rb +++ b/lib/histogram.rb @@ -1,5 +1,11 @@ -class NArray +class NArray +end + +unless Math.respond_to?(:log2) + def Math.log2(num) + Math.log(num, 2) + end end module Histogram @@ -44,8 +50,8 @@ def sample_stats(obj) # :sorted => false # def iqrange(obj, opts={}) - opt = {method: DEFAULT_QUARTILE_METHOD, sorted: false}.merge( opts ) - srted = opt[:sorted] ? obj : obj.sort + opt = {:method => DEFAULT_QUARTILE_METHOD, :sorted => false}.merge( opts ) + srted = opt[:sorted] ? obj : obj.sort sz = srted.size answer = case opt[:method] @@ -89,9 +95,9 @@ def number_of_bins(methd=DEFAULT_BIN_METHOD, quartile_method=DEFAULT_QUARTILE_ME (mean, stddev) = Histogram.sample_stats(self) range / ( 3.5*stddev*(self.size**(-1.0/3)) ) when :sturges - 1 + Math::log(self.size, 2) + 1 + Math::log2(self.size) when :fd - 2 * Histogram.iqrange(self, method: quartile_method) * (self.size**(-1.0/3)) + 2 * Histogram.iqrange(self, :method => quartile_method) * (self.size**(-1.0/3)) end nbins = 1 if nbins <= 0 nbins = 1 if nbins.nan? diff --git a/spec/histogram_spec.rb b/spec/histogram_spec.rb index 1e91d0d..9ddd80f 100644 --- a/spec/histogram_spec.rb +++ b/spec/histogram_spec.rb @@ -2,6 +2,16 @@ require 'histogram' +class Float + def round(n=nil) + if n + ((n**10) * self).to_i/(10**n) + else + super() + end + end +end + RSpec::Matchers.define :be_within_rounding_error_of do |expected| match do |actual| (act, exp) = [actual, expected].map {|ar| ar.collect {|v| v.to_f.round(8) } } @@ -91,14 +101,14 @@ end describe Histogram do - tmp = { - obj0: (0..10).to_a, - obj1: [0, 1, 1.5, 2.0, 5.0, 6.0, 7, 8, 9, 9], - obj2: [-1, 0, 1, 1.5, 2.0, 5.0, 6.0, 7, 8, 9, 9, 10], - obj3: [1, 1, 2, 2, 3, 3, 4, 4, 4], - obj4: [2, 2, 2, 2, 2, 4], - obj5: [1,2,3,3,3,4,5,6,7,8], - obj6: [0,0,0,0,0] + tmp = { + :obj0 => (0..10).to_a, + :obj1 => [0, 1, 1.5, 2.0, 5.0, 6.0, 7, 8, 9, 9], + :obj2 => [-1, 0, 1, 1.5, 2.0, 5.0, 6.0, 7, 8, 9, 9, 10], + :obj3 => [1, 1, 2, 2, 3, 3, 4, 4, 4], + :obj4 => [2, 2, 2, 2, 2, 4], + :obj5 => [1,2,3,3,3,4,5,6,7,8], + :obj6 => [0,0,0,0,0] } data = tmp.each {|k,v| [k, v.map(&:to_f).extend(Histogram)] } @@ -112,12 +122,12 @@ it_behaves_like 'something that can histogram' end - have_narray = + have_narray = begin require 'narray' NArray.respond_to?(:to_na) true - rescue + rescue LoadError false end @@ -152,16 +162,15 @@ end it 'calculates the interquartile range via moore_mccabe' do - Histogram.iqrange(even, method: :moore_mccabe).should == 4.0 - Histogram.iqrange(odd, method: :moore_mccabe).should == 4.0 + Histogram.iqrange(even, :method => :moore_mccabe).should == 4.0 + Histogram.iqrange(odd, :method => :moore_mccabe).should == 4.0 end it 'calculates the interquartile range via tukey' do - Histogram.iqrange(even, method: :tukey).should == 4.0 - Histogram.iqrange(odd, method: :tukey).should == 3.0 + Histogram.iqrange(even, :method => :tukey).should == 4.0 + Histogram.iqrange(odd, :method => :tukey).should == 3.0 end end end -