[前][次][番号順一覧][スレッド一覧]

ruby-changes:13252

From: nobu <ko1@a...>
Date: Mon, 21 Sep 2009 00:08:06 +0900 (JST)
Subject: [ruby-changes:13252] Ruby:r25013 (trunk): * ext/bigdecimal/lib/bigdecimal/math.rb (sin, cos, atan, exp, log):

nobu	2009-09-21 00:07:38 +0900 (Mon, 21 Sep 2009)

  New Revision: 25013

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=25013

  Log:
    * 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].

  Added files:
    trunk/test/bigdecimal/test_bigmath.rb
  Modified files:
    trunk/ChangeLog
    trunk/ext/bigdecimal/lib/bigdecimal/math.rb
    trunk/version.h

Index: ChangeLog
===================================================================
--- ChangeLog	(revision 25012)
+++ ChangeLog	(revision 25013)
@@ -1,3 +1,9 @@
+Mon Sep 21 00:07:36 2009  Nobuyoshi Nakada  <nobu@r...>
+
+	* 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@m...>
 
 	* struct.c (rb_struct_equal, rb_struct_eql): Handle comparison of
Index: ext/bigdecimal/lib/bigdecimal/math.rb
===================================================================
--- ext/bigdecimal/lib/bigdecimal/math.rb	(revision 25012)
+++ ext/bigdecimal/lib/bigdecimal/math.rb	(revision 25013)
@@ -49,6 +49,14 @@
     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 @@
       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 @@
     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 @@
   # 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 @@
     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 @@
       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 @@
     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 @@
       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.
Index: version.h
===================================================================
--- version.h	(revision 25012)
+++ version.h	(revision 25013)
@@ -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"
 
Index: test/bigdecimal/test_bigmath.rb
===================================================================
--- test/bigdecimal/test_bigmath.rb	(revision 0)
+++ test/bigdecimal/test_bigmath.rb	(revision 25013)
@@ -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

Property changes on: test/bigdecimal/test_bigmath.rb
___________________________________________________________________
Name: svn:eol-style
   + LF
Name: svn:keywords
   + Author Id Revision


--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]