Refine rb_flo_round_by_rational

Use already broken down arguments.
This commit is contained in:
Nobuyoshi Nakada 2026-05-23 15:33:23 +09:00
parent 4e8dbfdc1b
commit 97ec327efc
No known key found for this signature in database
GPG Key ID: 3582D74E1FEE4465
Notes: git 2026-05-23 08:27:36 +00:00
3 changed files with 20 additions and 9 deletions

View File

@ -38,7 +38,7 @@ VALUE rb_rational_cmp(VALUE self, VALUE other);
VALUE rb_rational_pow(VALUE self, VALUE other);
VALUE rb_rational_floor(VALUE self, int ndigits);
VALUE rb_numeric_quo(VALUE x, VALUE y);
VALUE rb_flo_round_by_rational(int argc, VALUE *argv, VALUE num);
VALUE rb_flo_round_by_rational(VALUE num, int ndigits, enum ruby_num_rounding_mode mode);
VALUE rb_float_numerator(VALUE x);
VALUE rb_float_denominator(VALUE x);

View File

@ -75,6 +75,8 @@
#define DBL_EPSILON 2.2204460492503131e-16
#endif
#define ACCURATE_POW10(ndigits) ((ndigits) < DBL_DIG)
#ifndef USE_RB_INFINITY
#elif !defined(WORDS_BIGENDIAN) /* BYTE_ORDER == LITTLE_ENDIAN */
const union bytesequence4_or_float rb_infinity = {{0x00, 0x00, 0x80, 0x7f}};
@ -2490,9 +2492,8 @@ flo_round(int argc, VALUE *argv, VALUE num)
frexp(number, &binexp);
if (float_round_overflow(ndigits, binexp)) return num;
if (float_round_underflow(ndigits, binexp)) return DBL2NUM(0);
if (ndigits >= DBL_DIG) {
/* In this case, pow(10, ndigits) may not be accurate. */
return rb_flo_round_by_rational(argc, argv, num);
if (!ACCURATE_POW10(ndigits)) {
return rb_flo_round_by_rational(num, ndigits, mode);
}
f = pow(10, ndigits);
x = ROUND_CALL(mode, round, (number, f));

View File

@ -1374,10 +1374,12 @@ nurat_round_half_even(VALUE self)
return num;
}
static VALUE f_round_n(VALUE self, VALUE n, VALUE (*func)(VALUE)) ;
static VALUE
f_round_common(int argc, VALUE *argv, VALUE self, VALUE (*func)(VALUE))
{
VALUE n, b, s;
VALUE n;
if (rb_check_arity(argc, 0, 1) == 0)
return (*func)(self);
@ -1387,6 +1389,14 @@ f_round_common(int argc, VALUE *argv, VALUE self, VALUE (*func)(VALUE))
if (!k_integer_p(n))
rb_raise(rb_eTypeError, "not an integer");
return f_round_n(self, n, func);
}
static VALUE
f_round_n(VALUE self, VALUE n, VALUE (*func)(VALUE))
{
VALUE b, s;
b = f_expt10(n);
s = rb_rational_mul(self, b);
@ -1417,8 +1427,7 @@ rb_rational_floor(VALUE self, int ndigits)
return nurat_floor(self);
}
else {
VALUE n = INT2NUM(ndigits);
return f_round_common(1, &n, self, nurat_floor);
return f_round_n(self, INT2NUM(ndigits), nurat_floor);
}
}
@ -1561,9 +1570,10 @@ nurat_round_n(int argc, VALUE *argv, VALUE self)
}
VALUE
rb_flo_round_by_rational(int argc, VALUE *argv, VALUE num)
rb_flo_round_by_rational(VALUE num, int ndigits, enum ruby_num_rounding_mode mode)
{
return nurat_to_f(nurat_round_n(argc, argv, float_to_r(num)));
VALUE (*round_func)(VALUE) = ROUND_FUNC(mode, nurat_round);
return nurat_to_f(f_round_n(float_to_r(num), INT2NUM(ndigits), round_func));
}
static double