From 0fb17f6ef46ade018a3fda8d4266f15638ddf5e3 Mon Sep 17 00:00:00 2001
From: David Steinberg <david.steinberg.dev@gmail.com>
Date: Tue, 13 Jan 2015 15:22:30 +0000
Subject: [PATCH] py: Use float-to-int classifications for
 mp_obj_new_int_from_float() functions

---
 py/objint.c          | 16 +++++++++++++---
 py/objint_longlong.c | 18 +++++++++++++++---
 py/objint_mpz.c      | 14 ++++++++------
 3 files changed, 36 insertions(+), 12 deletions(-)

diff --git a/py/objint.c b/py/objint.c
index 370c6a5df..fd0b2be55 100644
--- a/py/objint.c
+++ b/py/objint.c
@@ -306,9 +306,19 @@ mp_obj_t mp_obj_new_int_from_uint(mp_uint_t value) {
 
 #if MICROPY_PY_BUILTINS_FLOAT
 mp_obj_t mp_obj_new_int_from_float(mp_float_t val) {
-    // TODO raise an exception if the int won't fit
-    mp_int_t i = MICROPY_FLOAT_C_FUN(trunc)(val);
-    return mp_obj_new_int(i);
+    int cl = fpclassify(val);
+    if (cl == FP_INFINITE) {
+        nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OverflowError, "can't convert inf to int"));
+    } else if (cl == FP_NAN) {
+        nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "can't convert NaN to int"));
+    } else {
+        mp_fp_as_int_class_t icl = mp_classify_fp_as_int(val);
+        if (icl == MP_FP_CLASS_FIT_SMALLINT) {
+            return MP_OBJ_NEW_SMALL_INT((mp_int_t)val);
+        } else {
+            nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "float too big"));
+        }
+    }
 }
 #endif
 
diff --git a/py/objint_longlong.c b/py/objint_longlong.c
index 394ae111a..83e1c67d6 100644
--- a/py/objint_longlong.c
+++ b/py/objint_longlong.c
@@ -187,9 +187,21 @@ mp_obj_t mp_obj_new_int_from_ull(unsigned long long val) {
 
 #if MICROPY_PY_BUILTINS_FLOAT
 mp_obj_t mp_obj_new_int_from_float(mp_float_t val) {
-    // TODO raise an exception if the unsigned long long won't fit
-    long long i = MICROPY_FLOAT_C_FUN(trunc)(val);
-    return mp_obj_new_int_from_ll(i);
+    int cl = fpclassify(val);
+    if (cl == FP_INFINITE) {
+        nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OverflowError, "can't convert inf to int"));
+    } else if (cl == FP_NAN) {
+        nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "can't convert NaN to int"));
+    } else {
+        mp_fp_as_int_class_t icl = mp_classify_fp_as_int(val);
+        if (icl == MP_FP_CLASS_FIT_SMALLINT) {
+            return MP_OBJ_NEW_SMALL_INT((mp_int_t)val);
+        } else if (icl == MP_FP_CLASS_FIT_LONGINT) {
+            return mp_obj_new_int_from_ll((long long)val);
+        } else {
+            nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "float too big"));
+        }
+    }
 }
 #endif
 
diff --git a/py/objint_mpz.c b/py/objint_mpz.c
index 02b3ec0fe..c46692ec7 100644
--- a/py/objint_mpz.c
+++ b/py/objint_mpz.c
@@ -303,13 +303,15 @@ mp_obj_t mp_obj_new_int_from_float(mp_float_t val) {
         nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OverflowError, "can't convert inf to int"));
     } else if (cl == FP_NAN) {
         nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "can't convert NaN to int"));
-    } else if (MICROPY_FLOAT_C_FUN(fabs)(val) < 10000) {
-        // temporary(?) fix for optimising case where int will be small int
-        return MP_OBJ_NEW_SMALL_INT(MICROPY_FLOAT_C_FUN(trunc)(val));
     } else {
-        mp_obj_int_t *o = mp_obj_int_new_mpz();
-        mpz_set_from_float(&o->mpz, val);
-        return o;
+        mp_fp_as_int_class_t icl = mp_classify_fp_as_int(val);
+        if (icl == MP_FP_CLASS_FIT_SMALLINT) {
+            return MP_OBJ_NEW_SMALL_INT((mp_int_t)val);
+        } else {
+            mp_obj_int_t *o = mp_obj_int_new_mpz();
+            mpz_set_from_float(&o->mpz, val);
+            return o;
+        }
     }
 }
 #endif
-- 
GitLab