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

ruby-changes:64846

From: Kenta <ko1@a...>
Date: Wed, 13 Jan 2021 02:04:17 +0900 (JST)
Subject: [ruby-changes:64846] 2175c2c957 (master): [ruby/bigdecimal] Use pre-allocated objects for special values

https://git.ruby-lang.org/ruby.git/commit/?id=2175c2c957

From 2175c2c957a711f1c48f42d38db202bf52c8bc6f Mon Sep 17 00:00:00 2001
From: Kenta Murata <mrkn@m...>
Date: Tue, 12 Jan 2021 22:51:29 +0900
Subject: [ruby/bigdecimal] Use pre-allocated objects for special values

https://github.com/ruby/bigdecimal/commit/95c201f2d3

diff --git a/ext/bigdecimal/bigdecimal.c b/ext/bigdecimal/bigdecimal.c
index 8414769..4997487 100644
--- a/ext/bigdecimal/bigdecimal.c
+++ b/ext/bigdecimal/bigdecimal.c
@@ -127,6 +127,12 @@ static int VPrint(FILE *fp,const char *cntl_chr,Real *a); https://github.com/ruby/ruby/blob/trunk/ext/bigdecimal/bigdecimal.c#L127
  *  **** BigDecimal part ****
  */
 
+static VALUE BigDecimal_nan(void);
+static VALUE BigDecimal_positive_infinity(void);
+static VALUE BigDecimal_negative_infinity(void);
+static VALUE BigDecimal_positive_zero(void);
+static VALUE BigDecimal_negative_zero(void);
+
 static void
 BigDecimal_delete(void *pv)
 {
@@ -2782,10 +2788,27 @@ rb_float_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception) https://github.com/ruby/ruby/blob/trunk/ext/bigdecimal/bigdecimal.c#L2788
 
     double d = RFLOAT_VALUE(val);
 
-    if (!isfinite(d)) {
-        Real *vp = VpCreateRbObject(1, NULL, true);  /* vp->obj is allocated */
-        VpDtoV(vp, d);
-        return check_exception(vp->obj);
+    if (isnan(d)) {
+        VALUE obj = BigDecimal_nan();
+        return check_exception(obj);
+    }
+    else if (isinf(d)) {
+        VALUE obj;
+        if (d > 0) {
+            obj = BigDecimal_positive_infinity();
+        }
+        else {
+            obj = BigDecimal_negative_infinity();
+        }
+        return check_exception(obj);
+    }
+    else if (d == 0.0) {
+        if (1/d < 0.0) {
+            return BigDecimal_negative_zero();
+        }
+        else {
+            return BigDecimal_positive_zero();
+        }
     }
 
     if (digs == SIZE_MAX) {
@@ -2801,19 +2824,8 @@ rb_float_convert_to_BigDecimal(VALUE val, size_t digs, int raise_exception) https://github.com/ruby/ruby/blob/trunk/ext/bigdecimal/bigdecimal.c#L2824
         rb_raise(rb_eArgError, "precision too large.");
     }
 
-    if (d != 0.0) {
-        val = rb_funcall(val, id_to_r, 0);
-        return rb_rational_convert_to_BigDecimal(val, digs, raise_exception);
-    }
-
-    Real *vp;
-    if (1/d < 0.0) {
-        vp = VpCreateRbObject(digs, "-0", true);
-    }
-    else {
-        vp = VpCreateRbObject(digs, "0", true);
-    }
-    return check_exception(vp->obj);
+    val = rb_funcall(val, id_to_r, 0);
+    return rb_rational_convert_to_BigDecimal(val, digs, raise_exception);
 }
 
 static VALUE
@@ -3423,6 +3435,46 @@ get_vp_value: https://github.com/ruby/ruby/blob/trunk/ext/bigdecimal/bigdecimal.c#L3435
     return y;
 }
 
+static VALUE BIGDECIMAL_NAN = Qnil;
+
+static VALUE
+BigDecimal_nan(void)
+{
+    return BIGDECIMAL_NAN;
+}
+
+static VALUE BIGDECIMAL_POSITIVE_INFINITY = Qnil;
+
+static VALUE
+BigDecimal_positive_infinity(void)
+{
+    return BIGDECIMAL_POSITIVE_INFINITY;
+}
+
+static VALUE BIGDECIMAL_NEGATIVE_INFINITY = Qnil;
+
+static VALUE
+BigDecimal_negative_infinity(void)
+{
+    return BIGDECIMAL_NEGATIVE_INFINITY;
+}
+
+static VALUE BIGDECIMAL_POSITIVE_ZERO = Qnil;
+
+static VALUE
+BigDecimal_positive_zero(void)
+{
+    return BIGDECIMAL_POSITIVE_ZERO;
+}
+
+static VALUE BIGDECIMAL_NEGATIVE_ZERO = Qnil;
+
+static VALUE
+BigDecimal_negative_zero(void)
+{
+    return BIGDECIMAL_NEGATIVE_ZERO;
+}
+
 /* Document-class: BigDecimal
  * BigDecimal provides arbitrary-precision floating point decimal arithmetic.
  *
@@ -3694,13 +3746,34 @@ Init_bigdecimal(void) https://github.com/ruby/ruby/blob/trunk/ext/bigdecimal/bigdecimal.c#L3746
     /* -3: Indicates that a value is negative and infinite. See BigDecimal.sign. */
     rb_define_const(rb_cBigDecimal, "SIGN_NEGATIVE_INFINITE", INT2FIX(VP_SIGN_NEGATIVE_INFINITE));
 
-    arg = rb_str_new2("+Infinity");
+    /* Positive zero value. */
+    arg = rb_str_new2("+0");
+    BIGDECIMAL_POSITIVE_ZERO = f_BigDecimal(1, &arg, rb_cBigDecimal);
+    rb_gc_register_mark_object(BIGDECIMAL_POSITIVE_ZERO);
+
+    /* Negative zero value. */
+    arg = rb_str_new2("-0");
+    BIGDECIMAL_NEGATIVE_ZERO = f_BigDecimal(1, &arg, rb_cBigDecimal);
+    rb_gc_register_mark_object(BIGDECIMAL_NEGATIVE_ZERO);
+
     /* Positive infinity value. */
-    rb_define_const(rb_cBigDecimal, "INFINITY", f_BigDecimal(1, &arg, rb_cBigDecimal));
-    arg = rb_str_new2("NaN");
+    arg = rb_str_new2("+Infinity");
+    BIGDECIMAL_POSITIVE_INFINITY = f_BigDecimal(1, &arg, rb_cBigDecimal);
+    rb_gc_register_mark_object(BIGDECIMAL_POSITIVE_INFINITY);
+
+    /* Negative infinity value. */
+    arg = rb_str_new2("-Infinity");
+    BIGDECIMAL_NEGATIVE_INFINITY = f_BigDecimal(1, &arg, rb_cBigDecimal);
+    rb_gc_register_mark_object(BIGDECIMAL_NEGATIVE_INFINITY);
+
     /* 'Not a Number' value. */
-    rb_define_const(rb_cBigDecimal, "NAN", f_BigDecimal(1, &arg, rb_cBigDecimal));
+    arg = rb_str_new2("NaN");
+    BIGDECIMAL_NAN = f_BigDecimal(1, &arg, rb_cBigDecimal);
+    rb_gc_register_mark_object(BIGDECIMAL_NAN);
 
+    /* Special value constants */
+    rb_define_const(rb_cBigDecimal, "INFINITY", BIGDECIMAL_POSITIVE_INFINITY);
+    rb_define_const(rb_cBigDecimal, "NAN", BIGDECIMAL_NAN);
 
     /* instance methods */
     rb_define_method(rb_cBigDecimal, "precs", BigDecimal_prec, 0);
diff --git a/test/bigdecimal/test_bigdecimal.rb b/test/bigdecimal/test_bigdecimal.rb
index b15b046..e8fd85a 100644
--- a/test/bigdecimal/test_bigdecimal.rb
+++ b/test/bigdecimal/test_bigdecimal.rb
@@ -150,17 +150,23 @@ class TestBigDecimal < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/bigdecimal/test_bigdecimal.rb#L150
     assert_raise(ArgumentError) { BigDecimal(0.1, Float::DIG + 2) }
     assert_nothing_raised { BigDecimal(0.1, Float::DIG + 1) }
 
+    assert_same(BigDecimal(0.0), BigDecimal(0.0))
+    assert_same(BigDecimal(-0.0), BigDecimal(-0.0))
+
     bug9214 = '[ruby-core:58858]'
-    assert_equal(BigDecimal(-0.0, Float::DIG).sign, -1, bug9214)
+    assert_equal(BigDecimal(-0.0).sign, -1, bug9214)
 
     BigDecimal.save_exception_mode do
       BigDecimal.mode(BigDecimal::EXCEPTION_NaN, false)
       assert_nan(BigDecimal(Float::NAN))
+      assert_same(BigDecimal(Float::NAN), BigDecimal(Float::NAN))
     end
     BigDecimal.save_exception_mode do
       BigDecimal.mode(BigDecimal::EXCEPTION_INFINITY, false)
       assert_positive_infinite(BigDecimal(Float::INFINITY))
+      assert_same(BigDecimal(Float::INFINITY), BigDecimal(Float::INFINITY))
       assert_negative_infinite(BigDecimal(-Float::INFINITY))
+      assert_same(BigDecimal(-Float::INFINITY), BigDecimal(-Float::INFINITY))
     end
   end
 
-- 
cgit v0.10.2


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

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