From: Yusuke ENDOH Date: 2010-02-07T19:16:30+09:00 Subject: [ruby-dev:40343] Re: patch for ruby-core:17472 遠藤です。 2010年2月7日16:06 Yusuke ENDOH : > 2008年7月7日18:23 wanabe : >> 2008/07/06 15:36 Nobuyoshi Nakada : >>> BigDecimal('1').div(BigDecimal('3E-9')) の結果の有効数字が一桁に >>> なるというのは、もしかして仕様どおりの動作なんじゃないでしょうか。 >>> 左辺も右辺も、(あるいはレシーバも引数も)有効数字一桁ですから。 >> >> ありがとうございます。なるほど。 >> >> BigDecimal('1').divmod(BigDecimal('3E-9')) #=> [0.3E9, 0.1E0] >> >> 上のように余りが割る数を上回るのが理解できず >> バグかと思ったのですが、そういうことでしたら納得しました。 > > > これはやはりバグだと思います。 > *snip > > よってこのパッチはあてるべきです。rubyspec のエラーも消えます。 すみません、rubyspec については嘘でした。 手元で試行錯誤していて、以下のようなパッチにして、rubyspec 側も / でなく div を使うように修正した上で、やっと通っています。が、 ワナベさんのパッチから精度を勝手に 2 倍にあげているので、たぶん ダメなパッチです。 mrkn さんがちゃんと考えて直してくれると信じています。 diff --git a/ext/bigdecimal/bigdecimal.c b/ext/bigdecimal/bigdecimal.c index 8e85fdf..661b238 100644 --- a/ext/bigdecimal/bigdecimal.c +++ b/ext/bigdecimal/bigdecimal.c @@ -970,10 +970,8 @@ BigDecimal_DoDivmod(VALUE self, VALUE r, Real **div, Real **mod) return Qtrue; } - mx = a->Prec; - if(mxPrec) mx = b->Prec; - mx =(mx + 1) * VpBaseFig(); - GUARD_OBJ(c,VpCreateRbObject(mx, "0")); + mx = (a->MaxPrec + b->MaxPrec + 1) * 2 * VpBaseFig(); + GUARD_OBJ(c,VpCreateRbObject(mx, "#0")); GUARD_OBJ(res,VpCreateRbObject((mx+1) * 2 +(VpBaseFig() + 1), "#0")); VpDivd(c, res, a, b); mx = c->Prec *(VpBaseFig() + 1); @@ -983,6 +981,7 @@ BigDecimal_DoDivmod(VALUE self, VALUE r, Real **div, Real **mod) VpAddSub(c,a,res,-1); if(!VpIsZero(c) && (VpGetSign(a)*VpGetSign(b)<0)) { VpAddSub(res,d,VpOne(),-1); + GUARD_OBJ(d,VpCreateRbObject(GetAddSubPrec(c, b)*(VpBaseFig() + 1), "0")); VpAddSub(d ,c,b, 1); *div = res; *mod = d; diff --git a/library/bigdecimal/divmod_spec.rb b/library/bigdecimal/divmod_spec.rb index 5ea6d82..d3a47fc 100644 --- a/library/bigdecimal/divmod_spec.rb +++ b/library/bigdecimal/divmod_spec.rb @@ -143,7 +143,7 @@ describe "BigDecimal#divmod" do values.each do |val2| res = val1.divmod(val2) DivmodSpecs::check_both_bigdecimal(res) - res[0].should == ((val1/val2).floor) + res[0].should == val1.div(val2) res[1].should == (val1 - res[0] * val2) end end -- Yusuke ENDOH