From: Yusuke Endoh Date: 2010-01-27T02:42:38+09:00 Subject: [ruby-dev:40168] [Bug #2662] BigDecimal#ceil, etc. should not return Integer Bug #2662: BigDecimal#ceil, etc. should not return Integer http://redmine.ruby-lang.org/issues/show/2662 起票者: Yusuke Endoh ステータス: Open, 優先度: Normal 担当者: Yukihiro Matsumoto, カテゴリ: ext, Target version: 1.9.x ruby -v: ruby 1.9.2dev (2010-01-27 trunk 26434) [i686-linux] まつもとさん 遠藤です。 r20584 と r20616 で BigDecimal#ceil 、truncate 、floor 、round 、div の 戻り値を Integer にする変更がありますが、これだと巨大な BigDecimal を 扱えなく、または扱いが面倒になります。 # 巨大な BigDecimal は ceil が取れない $ ./ruby -rbigdecimal -e 'p BigDecimal("1E100000").ceil' (巨大な Bignum を確保しようとして固まる...) # Infinity が混ざるときは自分で対処する必要がある $ ./ruby -rbigdecimal -e 'p BigDecimal("Infinity").ceil' -e:1:in `ceil': Computation results to 'Infinity' (FloatDomainError) from -e:1:in `
' Float#ceil などが Integer を返すのに合わせるためだと思いますが、この変更 では BigDecimal のありがたみ自体が減ってしまう気がします。 どうしてもということでなければ、revert を提案します。 diff --git a/ext/bigdecimal/bigdecimal.c b/ext/bigdecimal/bigdecimal.c index c6ffe98..1f51f61 100644 --- a/ext/bigdecimal/bigdecimal.c +++ b/ext/bigdecimal/bigdecimal.c @@ -1108,7 +1108,7 @@ BigDecimal_div2(int argc, VALUE *argv, VALUE self) Real *div=NULL; Real *mod; if(BigDecimal_DoDivmod(self,b,&div,&mod)) { - return BigDecimal_to_i(ToValue(div)); + return ToValue(div); } return DoSomeOne(self,b,rb_intern("div")); } else { /* div in BigDecimal sense */ @@ -1308,9 +1308,6 @@ BigDecimal_round(int argc, VALUE *argv, VALUE self) GUARD_OBJ(c,VpCreateRbObject(mx, "0")); VpSetPrecLimit(pl); VpActiveRound(c,a,sw,iLoc); - if (argc == 0) { - return BigDecimal_to_i(ToValue(c)); - } return ToValue(c); } @@ -1355,9 +1352,6 @@ BigDecimal_truncate(int argc, VALUE *argv, VALUE self) GUARD_OBJ(c,VpCreateRbObject(mx, "0")); VpSetPrecLimit(pl); VpActiveRound(c,a,VP_ROUND_DOWN,iLoc); /* 0: truncate */ - if (argc == 0) { - return BigDecimal_to_i(ToValue(c)); - } return ToValue(c); } @@ -1418,9 +1412,6 @@ BigDecimal_floor(int argc, VALUE *argv, VALUE self) GUARD_OBJ(c,VpCreateRbObject(mx, "0")); VpSetPrecLimit(pl); VpActiveRound(c,a,VP_ROUND_FLOOR,iLoc); - if (argc == 0) { - return BigDecimal_to_i(ToValue(c)); - } return ToValue(c); } @@ -1465,9 +1456,6 @@ BigDecimal_ceil(int argc, VALUE *argv, VALUE self) GUARD_OBJ(c,VpCreateRbObject(mx, "0")); VpSetPrecLimit(pl); VpActiveRound(c,a,VP_ROUND_CEIL,iLoc); - if (argc == 0) { - return BigDecimal_to_i(ToValue(c)); - } return ToValue(c); } ついでに、この変更で rubyspec がやっぱりいっぱい失敗しています。 2) BigDecimal#ceil returns the smallest integer greater or equal to self, if n is unspecified ERROR FloatDomainError: Computation results to 'Infinity' /home/mame/work/ruby/spec/rubyspec/library/bigdecimal/ceil_spec.rb:34:in `ceil' /home/mame/work/ruby/spec/rubyspec/library/bigdecimal/ceil_spec.rb:34:in `block (2 levels) in ' /home/mame/work/ruby/spec/rubyspec/library/bigdecimal/ceil_spec.rb:4:in `' 3) BigDecimal#div with precision set to 0 returns NaN if NaN is involved ERROR FloatDomainError: Computation results to 'NaN'(Not a Number) /home/mame/work/ruby/spec/rubyspec/library/bigdecimal/shared/quo.rb:34:in `div' /home/mame/work/ruby/spec/rubyspec/library/bigdecimal/shared/quo.rb:34:in `block (2 levels) in ' /home/mame/work/ruby/spec/rubyspec/library/bigdecimal/div_spec.rb:5:in `' 4) BigDecimal#div returns NaN if NaN is involved ERROR FloatDomainError: Computation results to 'NaN'(Not a Number) /home/mame/work/ruby/spec/rubyspec/library/bigdecimal/div_spec.rb:46:in `div' /home/mame/work/ruby/spec/rubyspec/library/bigdecimal/div_spec.rb:46:in `block (2 levels) in ' /home/mame/work/ruby/spec/rubyspec/library/bigdecimal/div_spec.rb:12:in `' 5) BigDecimal#div returns NaN if divided by Infinity and no precision given ERROR FloatDomainError: Computation results to 'NaN'(Not a Number) /home/mame/work/ruby/spec/rubyspec/library/bigdecimal/div_spec.rb:51:in `div' /home/mame/work/ruby/spec/rubyspec/library/bigdecimal/div_spec.rb:51:in `block (2 levels) in ' /home/mame/work/ruby/spec/rubyspec/library/bigdecimal/div_spec.rb:12:in `' 6) BigDecimal#div returns NaN if (+|-) Infinity divided by 1 and no precision given ERROR FloatDomainError: Computation results to 'NaN'(Not a Number) /home/mame/work/ruby/spec/rubyspec/library/bigdecimal/div_spec.rb:109:in `div' /home/mame/work/ruby/spec/rubyspec/library/bigdecimal/div_spec.rb:109:in `block (2 levels) in ' /home/mame/work/ruby/spec/rubyspec/library/bigdecimal/div_spec.rb:12:in `' 8) BigDecimal#floor returns the greatest integer smaller or equal to self ERROR FloatDomainError: Computation results to 'Infinity' /home/mame/work/ruby/spec/rubyspec/library/bigdecimal/floor_spec.rb:29:in `floor' /home/mame/work/ruby/spec/rubyspec/library/bigdecimal/floor_spec.rb:29:in `block (2 levels) in ' /home/mame/work/ruby/spec/rubyspec/library/bigdecimal/floor_spec.rb:4:in `' 13) BigDecimal#truncate returns value of type Bigdecimal. FAILED Expected false to equal true /home/mame/work/ruby/spec/rubyspec/library/bigdecimal/truncate_spec.rb:16:in `block (3 levels) in ' /home/mame/work/ruby/spec/rubyspec/library/bigdecimal/truncate_spec.rb:15:in `each' /home/mame/work/ruby/spec/rubyspec/library/bigdecimal/truncate_spec.rb:15:in `block (2 levels) in ' /home/mame/work/ruby/spec/rubyspec/library/bigdecimal/truncate_spec.rb:4:in `' 14) BigDecimal#truncate returns NaN if self is NaN ERROR FloatDomainError: Computation results to 'NaN'(Not a Number) /home/mame/work/ruby/spec/rubyspec/library/bigdecimal/truncate_spec.rb:64:in `truncate' /home/mame/work/ruby/spec/rubyspec/library/bigdecimal/truncate_spec.rb:64:in `block (2 levels) in ' /home/mame/work/ruby/spec/rubyspec/library/bigdecimal/truncate_spec.rb:4:in `' 15) BigDecimal#truncate returns Infinity if self is infinite ERROR FloatDomainError: Computation results to 'Infinity' /home/mame/work/ruby/spec/rubyspec/library/bigdecimal/truncate_spec.rb:71:in `truncate' /home/mame/work/ruby/spec/rubyspec/library/bigdecimal/truncate_spec.rb:71:in `block (2 levels) in ' /home/mame/work/ruby/spec/rubyspec/library/bigdecimal/truncate_spec.rb:4:in `' -- Yusuke Endoh ---------------------------------------- http://redmine.ruby-lang.org