diff options
-rw-r--r-- | bignum.c | 5 | ||||
-rw-r--r-- | complex.c | 22 | ||||
-rw-r--r-- | internal.h | 1 | ||||
-rw-r--r-- | numeric.c | 4 |
4 files changed, 27 insertions, 5 deletions
@@ -6209,9 +6209,8 @@ rb_big_pow(VALUE x, VALUE y) if (y == INT2FIX(0)) return INT2FIX(1); if (RB_FLOAT_TYPE_P(y)) { d = RFLOAT_VALUE(y); - if ((BIGNUM_NEGATIVE_P(x) && !BIGZEROP(x)) && d != round(d)) { - x = DBL2NUM(pow(-rb_big2dbl(x), d)); - return rb_complex_polar(x, DBL2NUM(d * M_PI)); + if ((BIGNUM_NEGATIVE_P(x) && !BIGZEROP(x))) { + return rb_dbl_complex_polar(pow(-rb_big2dbl(x), d), d); } } else if (RB_BIGNUM_TYPE_P(y)) { @@ -540,6 +540,28 @@ f_complex_polar(VALUE klass, VALUE x, VALUE y) f_mul(x, m_sin(y))); } +/* returns a Complex or Float of ang*PI-rotated abs */ +VALUE +rb_dbl_complex_polar(double abs, double ang) +{ + double fi; + const double fr = modf(ang, &fi); + int pos = fr == +0.5; + + if (pos || fr == -0.5) { + if ((modf(fi / 2.0, &fi) != fr) ^ pos) abs = -abs; + return rb_complex_new(RFLOAT_0, DBL2NUM(abs)); + } + else if (fr == 0.0) { + if (modf(fi / 2.0, &fi) != 0.0) abs = -abs; + return DBL2NUM(abs); + } + else { + ang *= M_PI; + return rb_complex_new(DBL2NUM(abs * cos(ang)), DBL2NUM(abs * sin(ang))); + } +} + /* * call-seq: * Complex.polar(abs[, arg]) -> complex diff --git a/internal.h b/internal.h index 7944f87043..c486a46d99 100644 --- a/internal.h +++ b/internal.h @@ -1171,6 +1171,7 @@ VALUE rb_complex_plus(VALUE, VALUE); VALUE rb_complex_mul(VALUE, VALUE); VALUE rb_complex_abs(VALUE x); VALUE rb_complex_sqrt(VALUE x); +VALUE rb_dbl_complex_polar(double abs, double ang); /* cont.c */ VALUE rb_obj_is_fiber(VALUE); @@ -1276,7 +1276,7 @@ rb_float_pow(VALUE x, VALUE y) dx = RFLOAT_VALUE(x); dy = RFLOAT_VALUE(y); if (dx < 0 && dy != round(dy)) - return num_funcall1(rb_complex_raw1(x), idPow, y); + return rb_dbl_complex_polar(pow(-dx, dy), dy); } else { return rb_num_coerce_bin(x, y, idPow); @@ -4010,7 +4010,7 @@ fix_pow(VALUE x, VALUE y) if (a == 1) return DBL2NUM(1.0); { if (a < 0 && dy != round(dy)) - return num_funcall1(rb_complex_raw1(x), idPow, y); + return rb_dbl_complex_polar(pow(-(double)a, dy), dy); return DBL2NUM(pow((double)a, dy)); } } |