diff --git a/py/mpz.c b/py/mpz.c
index a25ba9e7d208bb7c7a3964c0639193da1650d8ed..b1d6e2b3226e519552682658b00b6a79823d7241 100644
--- a/py/mpz.c
+++ b/py/mpz.c
@@ -590,6 +590,14 @@ mpz_t *mpz_from_ll(long long val, bool is_signed) {
     return z;
 }
 
+#if MICROPY_PY_BUILTINS_FLOAT
+mpz_t *mpz_from_float(mp_float_t val) {
+    mpz_t *z = mpz_zero();
+    mpz_set_from_float(z, val);
+    return z;
+}
+#endif
+
 mpz_t *mpz_from_str(const char *str, mp_uint_t len, bool neg, mp_uint_t base) {
     mpz_t *z = mpz_zero();
     mpz_set_from_str(z, str, len, neg, base);
@@ -682,6 +690,80 @@ void mpz_set_from_ll(mpz_t *z, long long val, bool is_signed) {
     }
 }
 
+#if MICROPY_PY_BUILTINS_FLOAT
+void mpz_set_from_float(mpz_t *z, mp_float_t src) {
+#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE
+#define EXP_SZ      11
+#define FRC_SZ      52
+typedef uint64_t mp_float_int_t;
+#else
+#define EXP_SZ      8
+#define FRC_SZ      23
+typedef uint32_t mp_float_int_t;
+#endif
+    union {
+        mp_float_t f;
+        struct { mp_float_int_t frc:FRC_SZ, exp:EXP_SZ, sgn:1; } p;
+    } u = {src};
+
+    z->neg = u.p.sgn;
+    if (u.p.exp == 0) {
+        // value == 0 || value < 1
+        mpz_init_zero(z);
+    } else if (u.p.exp == ((1 << EXP_SZ) - 1)) {
+        // inf or NaN
+#if 0
+        // TODO: this probably isn't the right place to throw an exception
+        if(u.p.frc == 0)
+            nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OverflowError, "cannot convert float infinity to integer"));
+        else
+            nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "cannot convert float NaN to integer"));
+#else
+        mpz_init_zero(z);
+#endif
+    } else {
+        const int adj_exp = (int)u.p.exp - ((1 << (EXP_SZ - 1)) - 1);
+        if (adj_exp < 0) {
+            // value < 1 , truncates to 0
+            mpz_init_zero(z);
+        } else if (adj_exp == 0) {
+            // 1 <= value < 2 , so truncates to 1
+            mpz_init_from_int(z, 1);
+        } else {
+            // 2 <= value
+            const int dig_cnt = (adj_exp + 1 + (DIG_SIZE - 1)) / DIG_SIZE;
+            const unsigned int rem = adj_exp % DIG_SIZE;
+            int dig_ind, shft;
+            mp_float_int_t frc = u.p.frc | ((mp_float_int_t)1 << FRC_SZ);
+
+            if (adj_exp < FRC_SZ) {
+                shft = 0;
+                dig_ind = 0;
+                frc >>= FRC_SZ - adj_exp;
+            } else {
+                shft = (rem - FRC_SZ) % DIG_SIZE;
+                dig_ind = (adj_exp - FRC_SZ) / DIG_SIZE;
+            }
+            mpz_need_dig(z, dig_cnt);
+            z->len = dig_cnt;
+            if (dig_ind != 0) {
+                memset(z->dig, 0, dig_ind * sizeof(mpz_dig_t));
+            }
+            if (shft != 0) {
+                z->dig[dig_ind++] = (frc << shft) & DIG_MASK;
+                frc >>= DIG_SIZE - shft;
+            }
+            while (dig_ind != dig_cnt) {
+                z->dig[dig_ind++] = frc & DIG_MASK;
+                frc >>= DIG_SIZE;
+            }
+        }
+    }
+}
+#undef EXP_SZ
+#undef FRC_SZ
+#endif
+
 // returns number of bytes from str that were processed
 mp_uint_t mpz_set_from_str(mpz_t *z, const char *str, mp_uint_t len, bool neg, mp_uint_t base) {
     assert(base < 36);
diff --git a/py/mpz.h b/py/mpz.h
index e1d71bf4aef7d07b685aa7212c36eae07a7a4f55..d2b6fad5c6d39a934ba6822a7c640b567dcbe6f1 100644
--- a/py/mpz.h
+++ b/py/mpz.h
@@ -85,6 +85,9 @@ void mpz_deinit(mpz_t *z);
 mpz_t *mpz_zero(void);
 mpz_t *mpz_from_int(mp_int_t i);
 mpz_t *mpz_from_ll(long long i, bool is_signed);
+#if MICROPY_PY_BUILTINS_FLOAT
+mpz_t *mpz_from_float(mp_float_t i);
+#endif
 mpz_t *mpz_from_str(const char *str, mp_uint_t len, bool neg, mp_uint_t base);
 void mpz_free(mpz_t *z);
 
@@ -93,6 +96,9 @@ mpz_t *mpz_clone(const mpz_t *src);
 void mpz_set(mpz_t *dest, const mpz_t *src);
 void mpz_set_from_int(mpz_t *z, mp_int_t src);
 void mpz_set_from_ll(mpz_t *z, long long i, bool is_signed);
+#if MICROPY_PY_BUILTINS_FLOAT
+void mpz_set_from_float(mpz_t *z, mp_float_t src);
+#endif
 mp_uint_t mpz_set_from_str(mpz_t *z, const char *str, mp_uint_t len, bool neg, mp_uint_t base);
 
 bool mpz_is_zero(const mpz_t *z);
diff --git a/py/objint_mpz.c b/py/objint_mpz.c
index 554ec965798046f4d89317419ef547b2d9522f2b..23e30002359e0a38786a3bbfa667f89d9d003a67 100644
--- a/py/objint_mpz.c
+++ b/py/objint_mpz.c
@@ -298,9 +298,9 @@ 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: This doesn't handle numbers with large exponent
-    long long i = MICROPY_FLOAT_C_FUN(trunc)(val);
-    return mp_obj_new_int_from_ll(i);
+    mp_obj_int_t *o = mp_obj_int_new_mpz();
+    mpz_set_from_float(&o->mpz, val);
+    return o;
 }
 #endif
 
diff --git a/tests/float/float2int.py b/tests/float/float2int.py
index ca2914c01a9b31b9b4c73866b7783454b4f8a38c..b948755de5712452b5b8c2160311e48a4b0979f8 100644
--- a/tests/float/float2int.py
+++ b/tests/float/float2int.py
@@ -1,10 +1,24 @@
 # This case occurs with time.time() values
 print(int(1418774543.))
 
-# TODO: General case with large exponent
-#print(int(2.**100))
+print(int(2.**100))
 
 print("%d" % 1418774543.)
 
-# TODO: General case with large exponent
-#print("%d" % 2.**100)
+print("%d" % 2.**100)
+
+testpass = True
+for i in range(0,1024):
+    bitcnt = len(bin(int(2.**i))) - 3;
+    if i != bitcnt:
+        print('fail: 2**%u was %u bits long' % (i, bitcnt));
+        testpass = False
+print("power of  2 test: %s" % (testpass and 'passed' or 'failed'))
+
+testpass = True
+for i in range(0,23):
+    digcnt = len(str(int(10.**i))) - 1;
+    if i != digcnt:
+        print('fail: 10**%u was %u digits long' % (i, digcnt));
+        testpass = False
+print("power of 10 test: %s" % (testpass and 'passed' or 'failed'))