summaryrefslogtreecommitdiffstatshomepage
path: root/py/objint.c
diff options
context:
space:
mode:
Diffstat (limited to 'py/objint.c')
-rw-r--r--py/objint.c116
1 files changed, 74 insertions, 42 deletions
diff --git a/py/objint.c b/py/objint.c
index 5842a00a4d..bda9c46cf0 100644
--- a/py/objint.c
+++ b/py/objint.c
@@ -56,7 +56,7 @@ STATIC mp_obj_t mp_obj_int_make_new(const mp_obj_type_t *type_in, size_t n_args,
return args[0];
} else if (MP_OBJ_IS_STR_OR_BYTES(args[0])) {
// a string, parse it
- mp_uint_t l;
+ size_t l;
const char *s = mp_obj_str_get_data(args[0], &l);
return mp_parse_num_integer(s, l, 0, NULL);
#if MICROPY_PY_BUILTINS_FLOAT
@@ -72,7 +72,7 @@ STATIC mp_obj_t mp_obj_int_make_new(const mp_obj_type_t *type_in, size_t n_args,
default: {
// should be a string, parse it
// TODO proper error checking of argument types
- mp_uint_t l;
+ size_t l;
const char *s = mp_obj_str_get_data(args[0], &l);
return mp_parse_num_integer(s, l, mp_obj_get_int(args[1]), NULL);
}
@@ -80,7 +80,14 @@ STATIC mp_obj_t mp_obj_int_make_new(const mp_obj_type_t *type_in, size_t n_args,
}
#if MICROPY_PY_BUILTINS_FLOAT
-mp_fp_as_int_class_t mp_classify_fp_as_int(mp_float_t val) {
+
+typedef enum {
+ MP_FP_CLASS_FIT_SMALLINT,
+ MP_FP_CLASS_FIT_LONGINT,
+ MP_FP_CLASS_OVERFLOW
+} mp_fp_as_int_class_t;
+
+STATIC mp_fp_as_int_class_t mp_classify_fp_as_int(mp_float_t val) {
union {
mp_float_t f;
#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT
@@ -103,7 +110,12 @@ mp_fp_as_int_class_t mp_classify_fp_as_int(mp_float_t val) {
#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE
e |= u.i[MP_ENDIANNESS_BIG] != 0;
#endif
- e += ((1 << MP_FLOAT_EXP_BITS) - 1) << MP_FLOAT_EXP_SHIFT_I32;
+ if ((e & ~(1 << MP_FLOAT_SIGN_SHIFT_I32)) == 0) {
+ // handle case of -0 (when sign is set but rest of bits are zero)
+ e = 0;
+ } else {
+ e += ((1 << MP_FLOAT_EXP_BITS) - 1) << MP_FLOAT_EXP_SHIFT_I32;
+ }
} else {
e &= ~((1 << MP_FLOAT_EXP_SHIFT_I32) - 1);
}
@@ -125,13 +137,50 @@ mp_fp_as_int_class_t mp_classify_fp_as_int(mp_float_t val) {
}
#undef MP_FLOAT_SIGN_SHIFT_I32
#undef MP_FLOAT_EXP_SHIFT_I32
+
+mp_obj_t mp_obj_new_int_from_float(mp_float_t val) {
+ int cl = fpclassify(val);
+ if (cl == FP_INFINITE) {
+ nlr_raise(mp_obj_new_exception_msg(&mp_type_OverflowError, "can't convert inf to int"));
+ } else if (cl == FP_NAN) {
+ mp_raise_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);
+ #if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_MPZ
+ } else {
+ mp_obj_int_t *o = mp_obj_int_new_mpz();
+ mpz_set_from_float(&o->mpz, val);
+ return MP_OBJ_FROM_PTR(o);
+ }
+ #else
+ #if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_LONGLONG
+ } else if (icl == MP_FP_CLASS_FIT_LONGINT) {
+ return mp_obj_new_int_from_ll((long long)val);
+ #endif
+ } else {
+ mp_raise_ValueError("float too big");
+ }
+ #endif
+ }
+}
+
+#endif
+
+#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_LONGLONG
+typedef mp_longint_impl_t fmt_int_t;
+typedef unsigned long long fmt_uint_t;
+#else
+typedef mp_int_t fmt_int_t;
+typedef mp_uint_t fmt_uint_t;
#endif
void mp_obj_int_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
(void)kind;
// The size of this buffer is rather arbitrary. If it's not large
// enough, a dynamic one will be allocated.
- char stack_buf[sizeof(mp_int_t) * 4];
+ char stack_buf[sizeof(fmt_int_t) * 4];
char *buf = stack_buf;
size_t buf_size = sizeof(stack_buf);
size_t fmt_size;
@@ -144,12 +193,6 @@ void mp_obj_int_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t
}
}
-#if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_LONGLONG
-typedef mp_longint_impl_t fmt_int_t;
-#else
-typedef mp_int_t fmt_int_t;
-#endif
-
STATIC const uint8_t log_base2_floor[] = {
0, 1, 1, 2,
2, 2, 2, 3,
@@ -183,7 +226,7 @@ char *mp_obj_int_formatted(char **buf, size_t *buf_size, size_t *fmt_size, mp_co
fmt_int_t num;
if (MP_OBJ_IS_SMALL_INT(self_in)) {
// A small int; get the integer value to format.
- num = mp_obj_get_int(self_in);
+ num = MP_OBJ_SMALL_INT_VALUE(self_in);
#if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
} else if (MP_OBJ_IS_TYPE(self_in, &mp_type_int)) {
// Not a small int.
@@ -224,8 +267,9 @@ char *mp_obj_int_formatted(char **buf, size_t *buf_size, size_t *fmt_size, mp_co
*(--b) = '0';
} else {
do {
- int c = num % base;
- num /= base;
+ // The cast to fmt_uint_t is because num is positive and we want unsigned arithmetic
+ int c = (fmt_uint_t)num % base;
+ num = (fmt_uint_t)num / base;
if (c >= 10) {
c += base_char - 10;
} else {
@@ -291,7 +335,7 @@ mp_obj_t mp_obj_int_binary_op(mp_uint_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
}
// This is called only with strings whose value doesn't fit in SMALL_INT
-mp_obj_t mp_obj_new_int_from_str_len(const char **str, mp_uint_t len, bool neg, mp_uint_t base) {
+mp_obj_t mp_obj_new_int_from_str_len(const char **str, size_t len, bool neg, unsigned int base) {
mp_raise_msg(&mp_type_OverflowError, "long int not supported in this build");
return mp_const_none;
}
@@ -318,24 +362,6 @@ mp_obj_t mp_obj_new_int_from_uint(mp_uint_t value) {
return mp_const_none;
}
-#if MICROPY_PY_BUILTINS_FLOAT
-mp_obj_t mp_obj_new_int_from_float(mp_float_t val) {
- 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
-
mp_obj_t mp_obj_new_int(mp_int_t value) {
if (MP_SMALL_INT_FITS(value)) {
return MP_OBJ_NEW_SMALL_INT(value);
@@ -374,25 +400,31 @@ mp_obj_t mp_obj_int_binary_op_extra_cases(mp_uint_t op, mp_obj_t lhs_in, mp_obj_
// this is a classmethod
STATIC mp_obj_t int_from_bytes(size_t n_args, const mp_obj_t *args) {
- // TODO: Support long ints
- // TODO: Support byteorder param
// TODO: Support signed param (assumes signed=False at the moment)
(void)n_args;
- if (args[2] != MP_OBJ_NEW_QSTR(MP_QSTR_little)) {
- mp_not_implemented("");
- }
-
// get the buffer info
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_READ);
- // convert the bytes to an integer
+ const byte* buf = (const byte*)bufinfo.buf;
+ int delta = 1;
+ if (args[2] == MP_OBJ_NEW_QSTR(MP_QSTR_little)) {
+ buf += bufinfo.len - 1;
+ delta = -1;
+ }
+
mp_uint_t value = 0;
- for (const byte* buf = (const byte*)bufinfo.buf + bufinfo.len - 1; buf >= (byte*)bufinfo.buf; buf--) {
+ size_t len = bufinfo.len;
+ for (; len--; buf += delta) {
+ #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
+ if (value > (MP_SMALL_INT_MAX >> 8)) {
+ // Result will overflow a small-int so construct a big-int
+ return mp_obj_int_from_bytes_impl(args[2] != MP_OBJ_NEW_QSTR(MP_QSTR_little), bufinfo.len, bufinfo.buf);
+ }
+ #endif
value = (value << 8) | *buf;
}
-
return mp_obj_new_int_from_uint(value);
}