From: Tadashi Saito Date: 2003-07-10T15:27:20+09:00 Subject: [ruby-dev:20595] Re: [BigDecimal] changing rule of coerce 斎藤です。 一貫性の話は、他の重鎮の方々から出ているので略させていただきます。 ----- Original Message ----- From: "Shigeo Kobayashi" 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); --- 斎藤ただし