summaryrefslogtreecommitdiff
path: root/ext/bigdecimal
diff options
context:
space:
mode:
authornobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2009-09-20 15:07:38 +0000
committernobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2009-09-20 15:07:38 +0000
commitcd4f59bc5e32c71fcef679ebdbd750c7d2ed5f5e (patch)
tree1f13e1e640ac8b543a7e6c958731b8bbf6942932 /ext/bigdecimal
parent970ec9c02d683b86ca90dc6e63f3c1b4d8226960 (diff)
* 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
Diffstat (limited to 'ext/bigdecimal')
-rw-r--r--ext/bigdecimal/lib/bigdecimal/math.rb36
1 files changed, 31 insertions, 5 deletions
diff --git a/ext/bigdecimal/lib/bigdecimal/math.rb b/ext/bigdecimal/lib/bigdecimal/math.rb
index 24e928b..635992e 100644
--- a/ext/bigdecimal/lib/bigdecimal/math.rb
+++ b/ext/bigdecimal/lib/bigdecimal/math.rb
@@ -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.