Skip to content

Commit 0fb17f6

Browse files
doogledpgeorge
authored andcommitted
py: Use float-to-int classifications for mp_obj_new_int_from_float() functions
1 parent ca377b1 commit 0fb17f6

3 files changed

Lines changed: 36 additions & 12 deletions

File tree

py/objint.c

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -306,9 +306,19 @@ mp_obj_t mp_obj_new_int_from_uint(mp_uint_t value) {
306306

307307
#if MICROPY_PY_BUILTINS_FLOAT
308308
mp_obj_t mp_obj_new_int_from_float(mp_float_t val) {
309-
// TODO raise an exception if the int won't fit
310-
mp_int_t i = MICROPY_FLOAT_C_FUN(trunc)(val);
311-
return mp_obj_new_int(i);
309+
int cl = fpclassify(val);
310+
if (cl == FP_INFINITE) {
311+
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OverflowError, "can't convert inf to int"));
312+
} else if (cl == FP_NAN) {
313+
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "can't convert NaN to int"));
314+
} else {
315+
mp_fp_as_int_class_t icl = mp_classify_fp_as_int(val);
316+
if (icl == MP_FP_CLASS_FIT_SMALLINT) {
317+
return MP_OBJ_NEW_SMALL_INT((mp_int_t)val);
318+
} else {
319+
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "float too big"));
320+
}
321+
}
312322
}
313323
#endif
314324

py/objint_longlong.c

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -187,9 +187,21 @@ mp_obj_t mp_obj_new_int_from_ull(unsigned long long val) {
187187

188188
#if MICROPY_PY_BUILTINS_FLOAT
189189
mp_obj_t mp_obj_new_int_from_float(mp_float_t val) {
190-
// TODO raise an exception if the unsigned long long won't fit
191-
long long i = MICROPY_FLOAT_C_FUN(trunc)(val);
192-
return mp_obj_new_int_from_ll(i);
190+
int cl = fpclassify(val);
191+
if (cl == FP_INFINITE) {
192+
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OverflowError, "can't convert inf to int"));
193+
} else if (cl == FP_NAN) {
194+
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "can't convert NaN to int"));
195+
} else {
196+
mp_fp_as_int_class_t icl = mp_classify_fp_as_int(val);
197+
if (icl == MP_FP_CLASS_FIT_SMALLINT) {
198+
return MP_OBJ_NEW_SMALL_INT((mp_int_t)val);
199+
} else if (icl == MP_FP_CLASS_FIT_LONGINT) {
200+
return mp_obj_new_int_from_ll((long long)val);
201+
} else {
202+
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "float too big"));
203+
}
204+
}
193205
}
194206
#endif
195207

py/objint_mpz.c

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -303,13 +303,15 @@ mp_obj_t mp_obj_new_int_from_float(mp_float_t val) {
303303
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OverflowError, "can't convert inf to int"));
304304
} else if (cl == FP_NAN) {
305305
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "can't convert NaN to int"));
306-
} else if (MICROPY_FLOAT_C_FUN(fabs)(val) < 10000) {
307-
// temporary(?) fix for optimising case where int will be small int
308-
return MP_OBJ_NEW_SMALL_INT(MICROPY_FLOAT_C_FUN(trunc)(val));
309306
} else {
310-
mp_obj_int_t *o = mp_obj_int_new_mpz();
311-
mpz_set_from_float(&o->mpz, val);
312-
return o;
307+
mp_fp_as_int_class_t icl = mp_classify_fp_as_int(val);
308+
if (icl == MP_FP_CLASS_FIT_SMALLINT) {
309+
return MP_OBJ_NEW_SMALL_INT((mp_int_t)val);
310+
} else {
311+
mp_obj_int_t *o = mp_obj_int_new_mpz();
312+
mpz_set_from_float(&o->mpz, val);
313+
return o;
314+
}
313315
}
314316
}
315317
#endif

0 commit comments

Comments
 (0)