diff options
author | Nobuyoshi Nakada <nobu@ruby-lang.org> | 2023-11-29 20:16:36 +0900 |
---|---|---|
committer | Nobuyoshi Nakada <nobu@ruby-lang.org> | 2023-11-29 20:16:36 +0900 |
commit | 8e93bf8e1fbac73b677c333b19a8b55ae9daddc3 (patch) | |
tree | 92a47d3fe8bb981af5a476cd4a30e4f7e2a0997b /numeric.c | |
parent | 79eb75a8dd64848f23e9efc465f06326b5d4b680 (diff) |
[Bug #17037] Improve accuracy of division near precision limits
When dividing near the precision limit of `double`, use Bignum division to get rid of rounding errors.
Diffstat (limited to 'numeric.c')
-rw-r--r-- | numeric.c | 10 |
1 files changed, 8 insertions, 2 deletions
@@ -4096,7 +4096,13 @@ static double fix_fdiv_double(VALUE x, VALUE y) { if (FIXNUM_P(y)) { - return double_div_double(FIX2LONG(x), FIX2LONG(y)); + long iy = FIX2LONG(y); +#if SIZEOF_LONG * CHAR_BIT > DBL_MANT_DIG + if ((iy < 0 ? -iy : iy) >= (1L << DBL_MANT_DIG)) { + return rb_big_fdiv_double(rb_int2big(FIX2LONG(x)), rb_int2big(iy)); + } +#endif + return double_div_double(FIX2LONG(x), iy); } else if (RB_BIGNUM_TYPE_P(y)) { return rb_big_fdiv_double(rb_int2big(FIX2LONG(x)), y); @@ -4114,7 +4120,7 @@ rb_int_fdiv_double(VALUE x, VALUE y) { if (RB_INTEGER_TYPE_P(y) && !FIXNUM_ZERO_P(y)) { VALUE gcd = rb_gcd(x, y); - if (!FIXNUM_ZERO_P(gcd)) { + if (!FIXNUM_ZERO_P(gcd) && gcd != INT2FIX(1)) { x = rb_int_idiv(x, gcd); y = rb_int_idiv(y, gcd); } |