斎藤です。

一貫性の話は、他の重鎮の方々から出ているので略させていただきます。

----- Original Message ----- 
From: "Shigeo Kobayashi" <shigeo / tinyforest.gr.jp>
Sent: Tuesday, July 08, 2003 5:30 PM
Subject: [ruby-dev:20551] Re: [BigDecimal] changing rule of coerce

> > いっそのこと、builtin classにしてBigDecimalリテラルを用意するとい
> > うのはどうでしょうか?
> > 「1.234B」みたいな。
> 最善と思いますが、多分 Rational を builtin するよりももっと面倒そう...

自分も「将来的には」、BigDecimalをbuiltinにすることを推します。
Floatの誤差というのは、何もしないと2**32(64)以上の大きな整数が
扱えないという問題と同種で、計算機内部の事情だと思うからです。

その「事情」を知らない人の驚きをなくすため、Bignumがあるわけですよね。
そういう意味で、BigDecimalはとっても大事なライブラリだと思うわけです。
(「驚き」の事例は、ruby-listで何回も出てますね)

FixnumとBignumとの関係と同じく、同じ表記の小数リテラルで

・誤差が出ない表記の小数は速いFloatに
・誤差が出てしまう小数は正確なBigDecimalに

というのがある意味の理想だと思います。しかし、

・誤差が出るか出ないかの判定が面倒でパフォーマンス低下
・どのみち、誤差が出てしまう場面の方が圧倒的に多そう
・結果ほとんどBigDecimal演算になり、遅くなる
・誤差がそのまま出る言語処理系がほとんどだから、「驚き」が
 「常識」になっているユーザも多いので、元からあんまり
 正確さを期待されてない

ということで、デフォルトでBigDecimalが多く出るというのは
難しいですよね。

一番簡単そうという理由で、自分はユーザによる明示的な
接尾子案を推します。
「『B』をつけるだけで、小数は正確に計算されるようになります」
なんて、かっこいいと思います。



ただそれは大きな変更になりそうなので、あくまでも1.9以降、と
いう事になってしまうと思います。

それでつなぎとして、String#to_d でも用意しませんか?
Rational には Integer#to_r もあることですし。

BigDecimal("1.23")

と比べたら、

"1.23".to_d

のタイプ数は 5-12=-7、実に6割弱減です! (^^)

ということで、以下パッチです。ちなみにto_dという名前は、
既存の bigdecimal-rational から採りました。
# ついでに Fixnum#to_d と Bignum#to_d もつけてます。

Index: bigdecimal.c
===================================================================
RCS file: /src/ruby/ext/bigdecimal/bigdecimal.c,v
retrieving revision 1.9
diff -u -p -r1.9 bigdecimal.c
--- bigdecimal.c        1 Jul 2003 14:14:18 -0000       1.9
+++ bigdecimal.c        10 Jul 2003 05:39:34 -0000
@@ -1253,6 +1253,43 @@ BigDecimal_sincos(VALUE self, VALUE nFig
     return obj;
 }

+static VALUE
+str_to_d(VALUE str)
+{
+    ENTER(1);
+    Real *a;
+
+    SafeStringValue(str);
+    GUARD_OBJ(a, VpCreateRbObject(strlen(RSTRING(str)->ptr) + VpBaseFig() +
1,
+                                RSTRING(str)->ptr));
+    return ToValue(a);
+}
+
+static VALUE
+fix_to_d(VALUE num)
+{
+    ENTER(1);
+    Real *a;
+    char szD[128];
+
+    sprintf(szD, "%d", FIX2INT(num));
+    GUARD_OBJ(a,VpCreateRbObject(VpBaseFig() * 2 + 1, szD));
+    return ToValue(a);
+}
+
+static VALUE
+big_to_d(VALUE x)
+{
+    ENTER(1);
+    Real *a;
+    VALUE bg;
+
+    bg = rb_big2str(x, 10);
+    GUARD_OBJ(a,VpCreateRbObject(strlen(RSTRING(bg)->ptr) + VpBaseFig() +
1,
+                                RSTRING(bg)->ptr));
+    return ToValue(a);
+}
+

 #ifdef USE_MUTABLE_METHOD
 /**** Following methods are all MUTABLE and not currently activated. ****/
@@ -1450,6 +1487,11 @@ Init_bigdecimal(void)
     rb_define_method(rb_cBigDecimal, "finite?",   BigDecimal_IsFinite, 0);
     rb_define_method(rb_cBigDecimal, "truncate",  BigDecimal_truncate, -1);
     rb_define_method(rb_cBigDecimal, "_dump", BigDecimal_dump, -1);
+
+    /* misc utility methods */
+    rb_define_method(rb_cString, "to_d", str_to_d, 0);
+    rb_define_method(rb_cFixnum, "to_d", fix_to_d, 0);
+    rb_define_method(rb_cBignum, "to_d", big_to_d, 0);

 #ifdef USE_MUTABLE_METHOD
     rb_define_singleton_method(rb_cBigDecimal, "assign!",
BigDecimal_assign, 3);


---
斎藤ただし