core: add int.bit_length() when MICROPY_CYPTHON_COMPAT is enabled

This method of integer objects is needed for a port of python3's
decimal.py module.

MICROPY_CPYTHON_COMPAT is enabled by CIRCUITPY_FULL_BUILD.
This commit is contained in:
Jeff Epler 2020-04-28 09:13:49 -05:00
parent 5d17d6402d
commit 20c2dd0c08
7 changed files with 52 additions and 2 deletions

View File

@ -135,6 +135,9 @@ void mpz_xor_inpl(mpz_t *dest, const mpz_t *lhs, const mpz_t *rhs);
void mpz_divmod_inpl(mpz_t *dest_quo, mpz_t *dest_rem, const mpz_t *lhs, const mpz_t *rhs); void mpz_divmod_inpl(mpz_t *dest_quo, mpz_t *dest_rem, const mpz_t *lhs, const mpz_t *rhs);
static inline size_t mpz_max_num_bits(const mpz_t *z) { return z->len * MPZ_DIG_SIZE; } static inline size_t mpz_max_num_bits(const mpz_t *z) { return z->len * MPZ_DIG_SIZE; }
static inline size_t mpz_num_bits(const mpz_t *z) {
size_t last_bits = (8 * (sizeof(long) - sizeof(mpz_dig_t))) - __builtin_clzl(z->dig[z->len-1]);
return z->len * MPZ_DIG_SIZE + last_bits; }
mp_int_t mpz_hash(const mpz_t *z); mp_int_t mpz_hash(const mpz_t *z);
bool mpz_as_int_checked(const mpz_t *z, mp_int_t *value); bool mpz_as_int_checked(const mpz_t *z, mp_int_t *value);
bool mpz_as_uint_checked(const mpz_t *z, mp_uint_t *value); bool mpz_as_uint_checked(const mpz_t *z, mp_uint_t *value);

View File

@ -457,6 +457,28 @@ mp_obj_t mp_obj_int_binary_op_extra_cases(mp_binary_op_t op, mp_obj_t lhs_in, mp
return MP_OBJ_NULL; // op not supported return MP_OBJ_NULL; // op not supported
} }
#if MICROPY_CPYTHON_COMPAT
STATIC mp_obj_t int_bit_length(mp_obj_t self_in) {
#if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
if (!MP_OBJ_IS_SMALL_INT(self_in)) {
return mp_obj_int_bit_length_impl(self_in);
}
else
#endif
{
mp_int_t int_val = MP_OBJ_SMALL_INT_VALUE(self_in);
mp_uint_t value =
(int_val == 0) ? 0 :
(int_val == MP_SMALL_INT_MIN) ? 8 * sizeof(mp_int_t) :
(int_val < 0) ? 8 * sizeof(long) - __builtin_clzl(-int_val) :
8 * sizeof(long) - __builtin_clzl(int_val);
return mp_obj_new_int_from_uint(value);
}
}
MP_DEFINE_CONST_FUN_OBJ_1(int_bit_length_obj, int_bit_length);
#endif
// this is a classmethod // this is a classmethod
STATIC mp_obj_t int_from_bytes(size_t n_args, const mp_obj_t *args) { STATIC mp_obj_t int_from_bytes(size_t n_args, const mp_obj_t *args) {
// TODO: Support signed param (assumes signed=False at the moment) // TODO: Support signed param (assumes signed=False at the moment)
@ -537,6 +559,9 @@ STATIC mp_obj_t int_to_bytes(size_t n_args, const mp_obj_t *pos_args, mp_map_t *
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(int_to_bytes_obj, 3, int_to_bytes); STATIC MP_DEFINE_CONST_FUN_OBJ_KW(int_to_bytes_obj, 3, int_to_bytes);
STATIC const mp_rom_map_elem_t int_locals_dict_table[] = { STATIC const mp_rom_map_elem_t int_locals_dict_table[] = {
#if MICROPY_CPYTHON_COMPAT
{ MP_ROM_QSTR(MP_QSTR_bit_length), MP_ROM_PTR(&int_bit_length_obj) },
#endif
{ MP_ROM_QSTR(MP_QSTR_from_bytes), MP_ROM_PTR(&int_from_bytes_obj) }, { MP_ROM_QSTR(MP_QSTR_from_bytes), MP_ROM_PTR(&int_from_bytes_obj) },
{ MP_ROM_QSTR(MP_QSTR_to_bytes), MP_ROM_PTR(&int_to_bytes_obj) }, { MP_ROM_QSTR(MP_QSTR_to_bytes), MP_ROM_PTR(&int_to_bytes_obj) },
}; };

View File

@ -60,6 +60,7 @@ void mp_obj_int_buffer_overflow_check(mp_obj_t self_in, size_t nbytes, bool is_s
void mp_small_int_buffer_overflow_check(mp_int_t val, size_t nbytes, bool is_signed); void mp_small_int_buffer_overflow_check(mp_int_t val, size_t nbytes, bool is_signed);
mp_int_t mp_obj_int_hash(mp_obj_t self_in); mp_int_t mp_obj_int_hash(mp_obj_t self_in);
mp_obj_t mp_obj_int_bit_length_impl(mp_obj_t self_in);
mp_obj_t mp_obj_int_from_bytes_impl(bool big_endian, size_t len, const byte *buf); mp_obj_t mp_obj_int_from_bytes_impl(bool big_endian, size_t len, const byte *buf);
void mp_obj_int_to_bytes_impl(mp_obj_t self_in, bool big_endian, size_t len, byte *buf); void mp_obj_int_to_bytes_impl(mp_obj_t self_in, bool big_endian, size_t len, byte *buf);
int mp_obj_int_sign(mp_obj_t self_in); int mp_obj_int_sign(mp_obj_t self_in);

View File

@ -45,6 +45,17 @@
const mp_obj_int_t mp_maxsize_obj = {{&mp_type_int}, MP_SSIZE_MAX}; const mp_obj_int_t mp_maxsize_obj = {{&mp_type_int}, MP_SSIZE_MAX};
#endif #endif
mp_obj_t mp_obj_int_bit_length_impl(mp_obj_t self_in) {
assert(MP_OBJ_IS_TYPE(self_in, &mp_type_int));
mp_obj_int_t *self = self_in;
long long val = self->val;
return MP_OBJ_NEW_SMALL_INT(
(val == 0) ? 0 :
(val == MP_SMALL_INT_MIN) ? 8 * sizeof(long long) :
(val < 0) ? 8 * sizeof(long long) - __builtin_clzll(-val) :
8 * sizeof(long long) - __builtin_clzll(val));
}
mp_obj_t mp_obj_int_from_bytes_impl(bool big_endian, size_t len, const byte *buf) { mp_obj_t mp_obj_int_from_bytes_impl(bool big_endian, size_t len, const byte *buf) {
int delta = 1; int delta = 1;
if (!big_endian) { if (!big_endian) {

View File

@ -107,6 +107,12 @@ char *mp_obj_int_formatted_impl(char **buf, size_t *buf_size, size_t *fmt_size,
return str; return str;
} }
mp_obj_t mp_obj_int_bit_length_impl(mp_obj_t self_in) {
assert(MP_OBJ_IS_TYPE(self_in, &mp_type_int));
mp_obj_int_t *self = MP_OBJ_TO_PTR(self_in);
return MP_OBJ_NEW_SMALL_INT(mpz_num_bits(&self->mpz));
}
mp_obj_t mp_obj_int_from_bytes_impl(bool big_endian, size_t len, const byte *buf) { mp_obj_t mp_obj_int_from_bytes_impl(bool big_endian, size_t len, const byte *buf) {
mp_obj_int_t *o = mp_obj_int_new_mpz(); mp_obj_int_t *o = mp_obj_int_new_mpz();
mpz_set_from_bytes(&o->mpz, big_endian, len, buf); mpz_set_from_bytes(&o->mpz, big_endian, len, buf);

View File

@ -0,0 +1,4 @@
for i in range(129):
j = (1 << i)
print(i, (j-1).bit_length(), (j).bit_length(), (j+1).bit_length())
print(i, (-j-1).bit_length(), (-j).bit_length(), (-j+1).bit_length())

View File

@ -1,14 +1,14 @@
######## ########
object <function> is of type function object <function> is of type function
object <class 'int'> is of type type object <class 'int'> is of type type
bit_length -- <function>
from_bytes -- <classmethod> from_bytes -- <classmethod>
to_bytes -- <function> to_bytes -- <function>
object 1 is of type int object 1 is of type int
bit_length -- <function>
from_bytes -- <classmethod> from_bytes -- <classmethod>
to_bytes -- <function> to_bytes -- <function>
object <module 'micropython'> is of type module object <module 'micropython'> is of type module
__name__ -- micropython __name__ -- micropython
const -- <function>
opt_level -- <function>
######## ########
done done