summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorYukihiro "Matz" Matsumoto <[email protected]>2021-01-09 23:39:36 +0900
committerYukihiro "Matz" Matsumoto <[email protected]>2021-01-09 23:39:36 +0900
commit6f6eabf05adbfd7b9041eac6c4678bc9851c13c6 (patch)
treead838e105cd9ac74a13d49d8d6a1058163e936cc
parentf81591ceb6d8d2f82b3b83b9d9faaa06dd796740 (diff)
downloadmruby-6f6eabf05adbfd7b9041eac6c4678bc9851c13c6.tar.gz
mruby-6f6eabf05adbfd7b9041eac6c4678bc9851c13c6.zip
Fix wrong float to rational conversion in 32 bit mode.
-rw-r--r--mrbgems/mruby-rational/src/rational.c35
1 files changed, 21 insertions, 14 deletions
diff --git a/mrbgems/mruby-rational/src/rational.c b/mrbgems/mruby-rational/src/rational.c
index c3141638a..4093f1b13 100644
--- a/mrbgems/mruby-rational/src/rational.c
+++ b/mrbgems/mruby-rational/src/rational.c
@@ -146,27 +146,24 @@ rational_new_i(mrb_state *mrb, mrb_int n, mrb_int d)
#include <math.h>
#if defined(MRB_INT32) || defined(MRB_USE_FLOAT32)
-typedef float rat_float;
#define frexp_rat frexpf
#define ldexp_rat ldexpf
-#define RAT_MANT_DIG DBL_MANT_DIG
+#define RAT_MANT_DIG FLT_MANT_DIG
+#define RAT_INT_LIMIT 30
#else
-typedef double rat_float;
#define frexp_rat frexp
#define ldexp_rat ldexp
-#define RAT_MANT_DIG FLT_MANT_DIG
+#define RAT_MANT_DIG DBL_MANT_DIG
+#define RAT_INT_LIMIT 62
#endif
static void
-float_decode_internal(mrb_state *mrb, rat_float f, mrb_int *rf, int *n)
+float_decode_internal(mrb_state *mrb, mrb_float f, mrb_float *rf, int *n)
{
f = frexp_rat(f, n);
f = ldexp_rat(f, RAT_MANT_DIG);
*n -= RAT_MANT_DIG;
- if (!TYPED_FIXABLE(f, rat_float)) {
- mrb_raise(mrb, E_RANGE_ERROR, "integer overflow in rational");
- }
- *rf = (mrb_int)f;
+ *rf = f;
}
void mrb_check_num_exact(mrb_state *mrb, mrb_float num);
@@ -174,22 +171,32 @@ void mrb_check_num_exact(mrb_state *mrb, mrb_float num);
static mrb_value
rational_new_f(mrb_state *mrb, mrb_float f0)
{
- mrb_int f;
+ mrb_float f;
int n;
mrb_check_num_exact(mrb, f0);
float_decode_internal(mrb, f0, &f, &n);
#if FLT_RADIX == 2
if (n == 0)
- return rational_new(mrb, f, 1);
+ return rational_new(mrb, (mrb_int)f, 1);
if (n > 0)
- return rational_new(mrb, f<<n, 1);
- n = -n;
+ return rational_new(mrb, ((mrb_int)f)<<n, 1);
+ if (n < -RAT_INT_LIMIT) {
+ f = ldexp(f, n+RAT_INT_LIMIT);
+ n = RAT_INT_LIMIT;
+ }
+ else {
+ n = -n;
+ }
return rational_new_i(mrb, f, 1L<<n);
#else
- mrb_uint pow = 1;
+ mrb_int pow = 1;
if (n < 0) {
n = -n;
+ while (n > RAT_INT_LIMIT) {
+ f /= 2;
+ n--;
+ }
while (n--) {
pow *= FLT_RADIX;
}