Navigation Menu

Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Math::gamma fix and spec improvements #1700

Merged
merged 13 commits into from May 3, 2012
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 3 additions & 1 deletion kernel/common/math19.rb
Expand Up @@ -34,6 +34,8 @@ def cbrt(x)
def gamma(x) def gamma(x)
x = Rubinius::Type.coerce_to_float x x = Rubinius::Type.coerce_to_float x


# if x is negative zero, return -infinity
return -Float::INFINITY if (1 / x) == -Float::INFINITY
return Float::INFINITY if x == 0.0 return Float::INFINITY if x == 0.0
return Float::NAN if x.nan? return Float::NAN if x.nan?


Expand All @@ -49,7 +51,7 @@ def gamma(x)


if fractional == 0.0 if fractional == 0.0
raise DomainError, "gamma" if int < 0 raise DomainError, "gamma" if int < 0
return FactorialTable[int - 1] return FactorialTable[int - 1] if int <= FactorialTable.size
end end
end end


Expand Down
56 changes: 28 additions & 28 deletions spec/ruby/core/math/gamma_spec.rb
Expand Up @@ -2,24 +2,41 @@


ruby_version_is "1.9" do ruby_version_is "1.9" do
describe "Math.gamma" do describe "Math.gamma" do
before :all do
@factorial1 = 1
@factorial2 = 1124000727777607680000 # 22!
end

it "returns +infinity given 0" do it "returns +infinity given 0" do
Math.gamma(0).infinite?.should == 1 Math.gamma(0).should == Float::INFINITY
end

it "returns -infinity given -0.0" do
Math.gamma(-0.0).should == -Float::INFINITY
end end


it "returns Math.sqrt(Math::PI) given 0.5" do it "returns Math.sqrt(Math::PI) given 0.5" do
Math.gamma(0.5).should be_close(Math.sqrt(Math::PI), TOLERANCE) Math.gamma(0.5).should be_close(Math.sqrt(Math::PI), TOLERANCE)
end end


# stop at n=23 because 23! is too big to fit in a IEEE 754 double # stop at n == 23 because 23! cannot be exactly represented by IEEE 754 double
f = 1
2.upto(23) do |n| 2.upto(23) do |n|
it "returns #{n-1}! given #{n}" do it "returns exactly #{n-1}! given #{n}" do
Math.gamma(n).should be_close(f*=(n-1), TOLERANCE) @factorial1 *= n - 1
Math.gamma(n).should == @factorial1
end
end

24.upto(30) do |n|
it "returns approximately #{n-1}! given #{n}" do
@factorial2 *= n - 1
# compare only the first 12 places, tolerate the rest
Math.gamma(n).should be_close(@factorial2, @factorial2.to_s[12..-1].to_i)
end end
end end


it "returns good numerical approximation for gamma(3.2)" do it "returns good numerical approximation for gamma(3.2)" do
Math.gamma(3.2) .should be_close(2.423965, TOLERANCE) Math.gamma(3.2).should be_close(2.423965, TOLERANCE)
end end


it "returns good numerical approximation for gamma(-2.15)" do it "returns good numerical approximation for gamma(-2.15)" do
Expand All @@ -34,38 +51,21 @@
Math.gamma(-0.00001).should be_close(-100000.577225, TOLERANCE) Math.gamma(-0.00001).should be_close(-100000.577225, TOLERANCE)
end end


ruby_version_is ""..."1.9" do it "raises Math::DomainError given -1" do
it "raises Domain Error given -1" do lambda { Math.gamma(-1) }.should raise_error(Math::DomainError)
lambda { Math.gamma(-1) }.should raise_error(Errno::EDOM)
end
end

ruby_version_is "1.9" do
it "raises Math::DomainError given -1" do
lambda { Math.gamma(-1) }.should raise_error(Math::DomainError)
end
end end


# See http://redmine.ruby-lang.org/issues/show/2189 # See http://redmine.ruby-lang.org/issues/show/2189
it "returns +infinity given +infinity" do it "returns +infinity given +infinity" do
Math.gamma(infinity_value).infinite?.should == 1 Math.gamma(Float::INFINITY).should == Float::INFINITY
end

ruby_version_is ""..."1.9" do
it "raises Domain Error given negative infinity" do
lambda { Math.gamma(-infinity_value) }.should raise_error(Errno::EDOM)
end
end end


ruby_version_is "1.9" do it "raises Math::DomainError given negative infinity" do
it "raises Math::DomainError given negative infinity" do lambda { Math.gamma(-Float::INFINITY) }.should raise_error(Math::DomainError)
lambda { Math.gamma(-infinity_value) }.should raise_error(Math::DomainError)
end
end end


it "returns NaN given NaN" do it "returns NaN given NaN" do
Math.gamma(nan_value).nan?.should be_true Math.gamma(nan_value).nan?.should be_true
end end

end end
end end