mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
* ext/bigdecimal/lib/bigdecimal/math.rb (sin, cos, atan, exp, log):
improved precision and performance. based on a patch from Makoto Yamashita in [ruby-core:25600] and [ruby-core:25602]. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@25013 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
970ec9c02d
commit
cd4f59bc5e
4 changed files with 116 additions and 7 deletions
|
@ -1,3 +1,9 @@
|
|||
Mon Sep 21 00:07:36 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
|
||||
|
||||
* ext/bigdecimal/lib/bigdecimal/math.rb (sin, cos, atan, exp, log):
|
||||
improved precision and performance. based on a patch from Makoto
|
||||
Yamashita in [ruby-core:25600] and [ruby-core:25602].
|
||||
|
||||
Sun Sep 20 11:11:34 2009 Marc-Andre Lafortune <ruby-core@marc-andre.ca>
|
||||
|
||||
* struct.c (rb_struct_equal, rb_struct_eql): Handle comparison of
|
||||
|
|
|
@ -49,6 +49,14 @@ module BigMath
|
|||
n = prec + BigDecimal.double_fig
|
||||
one = BigDecimal("1")
|
||||
two = BigDecimal("2")
|
||||
x = -x if neg = x < 0
|
||||
if x > (twopi = two * BigMath.PI(prec))
|
||||
if x > 30
|
||||
x %= twopi
|
||||
else
|
||||
x -= twopi while x > twopi
|
||||
end
|
||||
end
|
||||
x1 = x
|
||||
x2 = x.mult(x,n)
|
||||
sign = 1
|
||||
|
@ -65,7 +73,7 @@ module BigMath
|
|||
d = sign * x1.div(z,m)
|
||||
y += d
|
||||
end
|
||||
y
|
||||
neg ? -y : y
|
||||
end
|
||||
|
||||
# Computes the cosine of x to the specified number of digits of precision.
|
||||
|
@ -77,6 +85,14 @@ module BigMath
|
|||
n = prec + BigDecimal.double_fig
|
||||
one = BigDecimal("1")
|
||||
two = BigDecimal("2")
|
||||
x = -x if x < 0
|
||||
if x > (twopi = two * BigMath.PI(prec))
|
||||
if x > 30
|
||||
x %= twopi
|
||||
else
|
||||
x -= twopi while x > twopi
|
||||
end
|
||||
end
|
||||
x1 = one
|
||||
x2 = x.mult(x,n)
|
||||
sign = 1
|
||||
|
@ -99,11 +115,9 @@ module BigMath
|
|||
# Computes the arctangent of x to the specified number of digits of precision.
|
||||
#
|
||||
# If x is infinite or NaN, returns NaN.
|
||||
# Raises an argument error if x > 1.
|
||||
def atan(x, prec)
|
||||
raise ArgumentError, "Zero or negative precision for atan" if prec <= 0
|
||||
return BigDecimal("NaN") if x.infinite? || x.nan?
|
||||
raise ArgumentError, "x.abs must be less than 1.0" if x.abs>=1
|
||||
n = prec + BigDecimal.double_fig
|
||||
y = x
|
||||
d = y
|
||||
|
@ -132,6 +146,7 @@ module BigMath
|
|||
return BigDecimal("NaN") if x.infinite? || x.nan?
|
||||
n = prec + BigDecimal.double_fig
|
||||
one = BigDecimal("1")
|
||||
x = -x if neg = x < 0
|
||||
x1 = one
|
||||
y = one
|
||||
d = y
|
||||
|
@ -145,7 +160,11 @@ module BigMath
|
|||
d = x1.div(z,m)
|
||||
y += d
|
||||
end
|
||||
y
|
||||
if neg
|
||||
one.div(y, prec)
|
||||
else
|
||||
y.round(prec - y.exponent)
|
||||
end
|
||||
end
|
||||
|
||||
# Computes the natural logarithm of x to the specified number of digits
|
||||
|
@ -159,6 +178,9 @@ module BigMath
|
|||
one = BigDecimal("1")
|
||||
two = BigDecimal("2")
|
||||
n = prec + BigDecimal.double_fig
|
||||
if (expo = x.exponent) < 0
|
||||
x = x.mult(BigDecimal("1E#{-expo}"), n)
|
||||
end
|
||||
x = (x - one).div(x + one,n)
|
||||
x2 = x.mult(x,n)
|
||||
y = x
|
||||
|
@ -171,7 +193,11 @@ module BigMath
|
|||
d = x.div(i,m)
|
||||
y += d
|
||||
end
|
||||
y*two
|
||||
y *= two
|
||||
if expo < 0
|
||||
y += log(BigDecimal("10"),prec) * BigDecimal(expo.to_s)
|
||||
end
|
||||
y
|
||||
end
|
||||
|
||||
# Computes the value of pi to the specified number of digits of precision.
|
||||
|
|
77
test/bigdecimal/test_bigmath.rb
Normal file
77
test/bigdecimal/test_bigmath.rb
Normal file
|
@ -0,0 +1,77 @@
|
|||
require "test/unit"
|
||||
require "bigdecimal"
|
||||
require "bigdecimal/math"
|
||||
|
||||
class TestBigMath < Test::Unit::TestCase
|
||||
include BigMath
|
||||
N = 20
|
||||
PINF = BigDecimal("+Infinity")
|
||||
MINF = BigDecimal("-Infinity")
|
||||
NAN = BigDecimal("NaN")
|
||||
|
||||
def test_const
|
||||
assert_in_delta(Math::PI, PI(N))
|
||||
assert_in_delta(Math::E, E(N))
|
||||
end
|
||||
|
||||
def test_sqrt
|
||||
assert_in_delta(2**0.5, sqrt(BigDecimal("2"), N))
|
||||
assert_equal(10, sqrt(BigDecimal("100"), N))
|
||||
assert_equal(0.0, sqrt(BigDecimal("0"), N))
|
||||
assert_equal(0.0, sqrt(BigDecimal("-0"), N))
|
||||
assert_raise(FloatDomainError) {sqrt(BigDecimal("-1.0"), N)}
|
||||
assert_raise(FloatDomainError) {sqrt(NAN, N)}
|
||||
assert_equal(PINF, sqrt(PINF, N))
|
||||
end
|
||||
|
||||
def test_sin
|
||||
assert_in_delta(0.0, sin(BigDecimal("0.0"), N))
|
||||
assert_in_delta(Math.sqrt(2.0) / 2, sin(PI(N) / 4, N))
|
||||
assert_in_delta(1.0, sin(PI(N) / 2, N))
|
||||
assert_in_delta(0.0, sin(PI(N) * 2, N))
|
||||
assert_in_delta(0.0, sin(PI(N), N))
|
||||
assert_in_delta(-1.0, sin(PI(N) / -2, N))
|
||||
assert_in_delta(0.0, sin(PI(N) * -2, N))
|
||||
assert_in_delta(0.0, sin(-PI(N), N))
|
||||
assert_in_delta(0.0, sin(PI(N) * 21, N))
|
||||
assert_in_delta(0.0, sin(PI(N) * 30, N))
|
||||
assert_in_delta(-1.0, sin(PI(N) * BigDecimal("301.5"), N))
|
||||
end
|
||||
|
||||
def test_cos
|
||||
assert_in_delta(1.0, cos(BigDecimal("0.0"), N))
|
||||
assert_in_delta(Math.sqrt(2.0) / 2, cos(PI(N) / 4, N))
|
||||
assert_in_delta(0.0, cos(PI(N) / 2, N))
|
||||
assert_in_delta(1.0, cos(PI(N) * 2, N))
|
||||
assert_in_delta(-1.0, cos(PI(N), N))
|
||||
assert_in_delta(0.0, cos(PI(N) / -2, N))
|
||||
assert_in_delta(1.0, cos(PI(N) * -2, N))
|
||||
assert_in_delta(-1.0, cos(-PI(N), N))
|
||||
assert_in_delta(-1.0, cos(PI(N) * 21, N))
|
||||
assert_in_delta(1.0, cos(PI(N) * 30, N))
|
||||
assert_in_delta(0.0, cos(PI(N) * BigDecimal("301.5"), N))
|
||||
end
|
||||
|
||||
def test_atan
|
||||
assert_equal(0.0, atan(BigDecimal("0.0"), N))
|
||||
assert_in_delta(Math::PI/4, atan(BigDecimal("1.0"), N))
|
||||
assert_in_delta(Math::PI/6, atan(sqrt(BigDecimal("3.0"), N) / 3, N))
|
||||
end
|
||||
|
||||
def test_exp
|
||||
assert_in_epsilon(Math::E, exp(BigDecimal("1"), N))
|
||||
assert_in_epsilon(Math.exp(N), exp(BigDecimal("20"), N))
|
||||
assert_in_epsilon(Math.exp(40), exp(BigDecimal("40"), N))
|
||||
assert_in_epsilon(Math.exp(-N), exp(BigDecimal("-20"), N))
|
||||
assert_in_epsilon(Math.exp(-40), exp(BigDecimal("-40"), N))
|
||||
end
|
||||
|
||||
def test_log
|
||||
assert_in_delta(0.0, log(BigDecimal("1"), N))
|
||||
assert_in_delta(1.0, log(E(N), N))
|
||||
assert_in_delta(Math.log(2.0), log(BigDecimal("2"), N))
|
||||
assert_in_delta(2.0, log(E(N)*E(N), N))
|
||||
assert_in_delta(Math.log(42.0), log(BigDecimal("42"), N))
|
||||
assert_in_delta(Math.log(1e-42), log(BigDecimal("1e-42"), N))
|
||||
end
|
||||
end
|
|
@ -1,5 +1,5 @@
|
|||
#define RUBY_VERSION "1.9.2"
|
||||
#define RUBY_RELEASE_DATE "2009-09-20"
|
||||
#define RUBY_RELEASE_DATE "2009-09-21"
|
||||
#define RUBY_PATCHLEVEL -1
|
||||
#define RUBY_BRANCH_NAME "trunk"
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
|||
#define RUBY_VERSION_TEENY 1
|
||||
#define RUBY_RELEASE_YEAR 2009
|
||||
#define RUBY_RELEASE_MONTH 9
|
||||
#define RUBY_RELEASE_DAY 20
|
||||
#define RUBY_RELEASE_DAY 21
|
||||
|
||||
#include "ruby/version.h"
|
||||
|
||||
|
|
Loading…
Reference in a new issue