From 4fedad85efa84f25cad199eb325d3a300778a046 Mon Sep 17 00:00:00 2001 From: nobu Date: Sun, 17 Jun 2018 02:37:32 +0000 Subject: [PATCH] refine Integer#** and Float#** * complex.c (rb_dbl_complex_polar): utility function, which returns more precise value in right angle cases. * bignum.c (rb_big_pow): use rb_dbl_complex_polar(). * numeric.c (rb_float_pow, fix_pow): create a Complex by polar form. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@63678 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- bignum.c | 5 ++--- complex.c | 22 ++++++++++++++++++++++ internal.h | 1 + numeric.c | 4 ++-- 4 files changed, 27 insertions(+), 5 deletions(-) diff --git a/bignum.c b/bignum.c index 00d46ee662..7e5ce4d585 100644 --- a/bignum.c +++ b/bignum.c @@ -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)) { diff --git a/complex.c b/complex.c index e9bfc02f7a..2b452e23c0 100644 --- a/complex.c +++ b/complex.c @@ -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); diff --git a/numeric.c b/numeric.c index 30afc581fe..fe867f9fd3 100644 --- a/numeric.c +++ b/numeric.c @@ -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)); } }