Bug #2661
closedBignum <= BigDecimal("NaN") raises an Exception
Description
=begin
遠藤です。
Bignum と BigDecimal("NaN") を <= などで比較すると例外があがります。
$ ./ruby -rbigdecimal -ve 'p 2**100 <= BigDecimal("NaN")'
ruby 1.9.2dev (2010-01-27 trunk 26434) [i686-linux]
-e:1:in <=': comparison of Bignum with BigDecimal failed (ArgumentError) from -e:1:in
'
ざっと確認した限りで、1.8.6-p388 、1.8.7-p249 、1.9.1-p378 、trunk のいずれ
でも発生します。
Comparable#<= が動き、その中で coerce と <=> が呼ばれますが、NaN との <=> は
nil が返るため、Comparable#<= が音を上げます。
Fixnum#<= の場合は、coerce を呼んだ後、coerce の結果に対して <= を呼ぶので
例外にはなりません。
Fixnum と同様に Bignum#<=, <, >= > を実装しないと対処できないような気が
します。
例によって、rubyspec がこれで落ちています。
BigDecimal#<= properly handles NaN values ERROR
ArgumentError: comparison of Bignum with BigDecimal failed
/home/mame/work/ruby/spec/rubyspec/library/bigdecimal/lte_spec.rb:77:in <=' /home/mame/work/ruby/spec/rubyspec/library/bigdecimal/lte_spec.rb:77:in
block (4 levels) in <top (required)>'
/home/mame/work/ruby/spec/rubyspec/library/bigdecimal/lte_spec.rb:74:in each' /home/mame/work/ruby/spec/rubyspec/library/bigdecimal/lte_spec.rb:74:in
block (3 levels) in <top (required)>'
/home/mame/work/ruby/spec/rubyspec/library/bigdecimal/lte_spec.rb:4:in `<top (required)>'
--
Yusuke Endoh [email protected]
=end
Updated by mame (Yusuke Endoh) over 15 years ago
=begin
遠藤です。
2010年1月27日1:31 Yusuke Endoh [email protected]:
Fixnum と同様に Bignum#<=, <, >= > を実装しないと対処できないような気が
します。
実装してみました。反対がなければコミットしたいと思います。
diff --git a/bignum.c b/bignum.c
index 0b464f2..d3b1d01 100644
--- a/bignum.c
+++ b/bignum.c
@@ -1329,6 +1329,113 @@ rb_big_cmp(VALUE x, VALUE y)
(RBIGNUM_SIGN(x) ? INT2FIX(-1) : INT2FIX(1));
}
+static VALUE
+big_op(VALUE x, VALUE y, int op)
+{
- long xlen = RBIGNUM_LEN(x);
- BDIGIT *xds, *yds;
- VALUE rel;
- int n;
- switch (TYPE(y)) {
-
case T_FIXNUM:
-
case T_BIGNUM:
- rel = rb_big_cmp(x, y);
- break;
-
case T_FLOAT:
- {
-
double a = RFLOAT_VALUE(y);
-
if (isinf(a)) {
-
if (a > 0.0) return INT2FIX(-1);
-
else return INT2FIX(1);
-
}
-
rel = rb_dbl_cmp(rb_big2dbl(x), a);
-
break;
- }
-
default:
- {
-
ID id = 0;
-
switch (op) {
-
case 0: id = '>'; break;
-
case 1: id = rb_intern(">="); break;
-
case 2: id = '<'; break;
-
case 3: id = rb_intern("<="); break;
-
}
-
return rb_num_coerce_relop(x, y, id);
- }
- }
- if (NIL_P(rel)) return Qfalse;
- n = FIX2INT(rel);
- switch (op) {
- case 0: return n > 0 ? Qtrue : Qfalse;
- case 1: return n >= 0 ? Qtrue : Qfalse;
- case 2: return n < 0 ? Qtrue : Qfalse;
- case 3: return n <= 0 ? Qtrue : Qfalse;
- }
- return Qundef;
+}
+/*
-
- call-seq:
-
- big > real -> true or false
-
-
- Returns
true
if the value ofbig
is
- Returns
-
- greater than that of
real
.
- greater than that of
- */
+static VALUE
+big_gt(VALUE x, VALUE y)
+{
- return big_op(x, y, 0);
+}
+/*
-
- call-seq:
-
- big >= real -> true or false
-
-
- Returns
true
if the value ofbig
is
- Returns
-
- greater than or equal to that of
real
.
- greater than or equal to that of
- */
+static VALUE
+big_ge(VALUE x, VALUE y)
+{
- return big_op(x, y, 1);
+}
+/*
-
- call-seq:
-
- big < real -> true or false
-
-
- Returns
true
if the value ofbig
is
- Returns
-
- less than that of
real
.
- less than that of
- */
+static VALUE
+big_lt(VALUE x, VALUE y)
+{
- return big_op(x, y, 2);
+}
+/*
-
- call-seq:
-
- big <= real -> true or false
-
-
- Returns
true
if the value ofbig
is
- Returns
-
- less than or equal to that of
real
.
- less than or equal to that of
- */
+static VALUE
+big_le(VALUE x, VALUE y)
+{
- return big_op(x, y, 3);
+}
/*
- call-seq:
-
big == obj => true or false
@@ -3286,6 +3393,10 @@ Init_Bignum(void)
rb_define_method(rb_cBignum, "<=>", rb_big_cmp, 1);
rb_define_method(rb_cBignum, "==", rb_big_eq, 1);
- rb_define_method(rb_cBignum, ">", big_gt, 1);
- rb_define_method(rb_cBignum, ">=", big_ge, 1);
- rb_define_method(rb_cBignum, "<", big_lt, 1);
- rb_define_method(rb_cBignum, "<=", big_le, 1);
rb_define_method(rb_cBignum, "===", rb_big_eq, 1);
rb_define_method(rb_cBignum, "eql?", rb_big_eql, 1);
rb_define_method(rb_cBignum, "hash", rb_big_hash, 0);
--
Yusuke ENDOH [email protected]
=end
Updated by mame (Yusuke Endoh) over 15 years ago
- Status changed from Open to Closed
- % Done changed from 0 to 100
=begin
This issue was solved with changeset r26574.
Yusuke, thank you for reporting this issue.
Your contribution to Ruby is greatly appreciated.
May Ruby be with you.
=end