From: Tadayoshi Funaba Date: 2008-09-19T07:40:15+09:00 Subject: [ruby-dev:36383] Re: mathn (#**) Common Lisp や Scheme でも (expt -2 2.0) が複素数になるかどうかはまち まちみたいですが、とりあえずこの場合を除外してみました。 (-2) ** 2.0 #=> 4.0 (-2) ** 2.1 #=> (4.07726854214945+1.32478485617518i) (-2) ** Rational(2) #=> (4/1) (-2) ** Rational('2.1') #=> (4.07726854214945+1.32478485617518i) あと豊福さんの指摘も含めて修正。 Index: numeric.c =================================================================== --- numeric.c (revision 19423) +++ numeric.c (working copy) @@ -794,7 +794,14 @@ case T_BIGNUM: return DBL2NUM(pow(RFLOAT_VALUE(x), rb_big2dbl(y))); case T_FLOAT: - return DBL2NUM(pow(RFLOAT_VALUE(x), RFLOAT_VALUE(y))); + { + double dx = RFLOAT_VALUE(x); + double dy = RFLOAT_VALUE(y); + + if (dx < 0 && dy != round(dy)) + return rb_funcall(rb_complex_raw1(x), rb_intern("**"), 1, y); + return DBL2NUM(pow(dx, dy)); + } default: return rb_num_coerce_bin(x, y, rb_intern("**")); } @@ -2484,7 +2491,13 @@ return DBL2NUM(RFLOAT_VALUE(y) < 0 ? (1.0 / zero) : 0.0); } if (a == 1) return DBL2NUM(1.0); - return DBL2NUM(pow((double)a, RFLOAT_VALUE(y))); + { + double dy = RFLOAT_VALUE(y); + + if (a < 0 && dy != round(dy)) + return rb_funcall(rb_complex_raw1(x), rb_intern("**"), 1, y); + return DBL2NUM(pow((double)a, dy)); + } default: return rb_num_coerce_bin(x, y, rb_intern("**")); } Index: bignum.c =================================================================== --- bignum.c (revision 19423) +++ bignum.c (working copy) @@ -2099,11 +2099,13 @@ switch (TYPE(y)) { case T_FLOAT: d = RFLOAT_VALUE(y); + if ((!RBIGNUM_SIGN(x) && !BIGZEROP(x)) && d != round(d)) + return rb_funcall(rb_complex_raw1(x), rb_intern("**"), 1, y); break; case T_BIGNUM: - if (rb_funcall(y, '<', 1, INT2FIX(0))) - return rb_funcall(rb_rational_raw1(x), rb_intern("**"), 1, y); + if (!RBIGNUM_SIGN(y) && !BIGZEROP(y)) + return rb_funcall(rb_rational_raw1(x), rb_intern("**"), 1, y); rb_warn("in a**b, b may be too big"); d = rb_big2dbl(y); @@ -2113,7 +2115,7 @@ yy = FIX2LONG(y); if (yy < 0) - return rb_funcall(rb_rational_raw1(x), rb_intern("**"), 1, y); + return rb_funcall(rb_rational_raw1(x), rb_intern("**"), 1, y); else { VALUE z = 0; SIGNED_VALUE mask;