diff options
author | nobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2016-04-13 02:41:24 +0000 |
---|---|---|
committer | nobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2016-04-13 02:41:24 +0000 |
commit | aaf0f51f46ba3a9ad1180844a3e26af89c5d35d8 (patch) | |
tree | e7996ec924d2e49a331ef529324e33cd415e4614 /numeric.c | |
parent | 456523e2ede3073767fd8cb73cc4b159c3608890 (diff) | |
download | ruby-aaf0f51f46ba3a9ad1180844a3e26af89c5d35d8.tar.gz |
numeric.c: float_invariant_round
* numeric.c (float_invariant_round): extracted from flo_round to
be optimizer-friendly, e.g., tail-call optimization.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@54554 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'numeric.c')
-rw-r--r-- | numeric.c | 22 |
1 files changed, 16 insertions, 6 deletions
@@ -110,6 +110,7 @@ static VALUE fix_rshift(long, unsigned long); static VALUE int_pow(long x, unsigned long y); static VALUE int_cmp(VALUE x, VALUE y); static VALUE flo_truncate(VALUE num); +static int float_invariant_round(double number, int ndigits, VALUE *num); static ID id_coerce, id_div, id_divmod; #define id_to_i idTo_i @@ -1840,8 +1841,6 @@ flo_round(int argc, VALUE *argv, VALUE num) { double number, f; int ndigits = 0; - int binexp; - enum {float_dig = DBL_DIG+2}; if (rb_check_arity(argc, 0, 1)) { ndigits = NUM2INT(argv[0]); @@ -1853,6 +1852,17 @@ flo_round(int argc, VALUE *argv, VALUE num) if (ndigits == 0) { return dbl2ival(round(number)); } + if (float_invariant_round(number, ndigits, &num)) return num; + f = pow(10, ndigits); + return DBL2NUM(round(number * f) / f); +} + +static int +float_invariant_round(double number, int ndigits, VALUE *num) +{ + enum {float_dig = DBL_DIG+2}; + int binexp; + frexp(number, &binexp); /* Let `exp` be such that `number` is written as:"0.#{digits}e#{exp}", @@ -1874,13 +1884,13 @@ flo_round(int argc, VALUE *argv, VALUE num) */ if (isinf(number) || isnan(number) || (ndigits >= float_dig - (binexp > 0 ? binexp / 4 : binexp / 3 - 1))) { - return num; + return TRUE; } if (ndigits < - (binexp > 0 ? binexp / 3 + 1 : binexp / 4)) { - return DBL2NUM(0); + *num = DBL2NUM(0); + return TRUE; } - f = pow(10, ndigits); - return DBL2NUM(round(number * f) / f); + return FALSE; } /* |