Skip to content

Commit 6837d46

Browse files
committed
py: Fix builtin abs so it works for bools and bignum.
1 parent 26a9975 commit 6837d46

6 files changed

Lines changed: 75 additions & 8 deletions

File tree

py/modbuiltins.c

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929

3030
#include "py/nlr.h"
3131
#include "py/smallint.h"
32+
#include "py/objint.h"
3233
#include "py/objstr.h"
3334
#include "py/runtime0.h"
3435
#include "py/runtime.h"
@@ -86,12 +87,8 @@ STATIC mp_obj_t mp_builtin___build_class__(mp_uint_t n_args, const mp_obj_t *arg
8687
MP_DEFINE_CONST_FUN_OBJ_VAR(mp_builtin___build_class___obj, 2, mp_builtin___build_class__);
8788

8889
STATIC mp_obj_t mp_builtin_abs(mp_obj_t o_in) {
89-
if (MP_OBJ_IS_SMALL_INT(o_in)) {
90-
mp_int_t val = MP_OBJ_SMALL_INT_VALUE(o_in);
91-
if (val < 0) {
92-
val = -val;
93-
}
94-
return MP_OBJ_NEW_SMALL_INT(val);
90+
if (0) {
91+
// dummy
9592
#if MICROPY_PY_BUILTINS_FLOAT
9693
} else if (MP_OBJ_IS_TYPE(o_in, &mp_type_float)) {
9794
mp_float_t value = mp_obj_float_get(o_in);
@@ -109,8 +106,8 @@ STATIC mp_obj_t mp_builtin_abs(mp_obj_t o_in) {
109106
#endif
110107
#endif
111108
} else {
112-
assert(0);
113-
return mp_const_none;
109+
// this will raise a TypeError if the argument is not integral
110+
return mp_obj_int_abs(o_in);
114111
}
115112
}
116113
MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_abs_obj, mp_builtin_abs);

py/objint.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,16 @@ bool mp_obj_int_is_positive(mp_obj_t self_in) {
266266
return mp_obj_get_int(self_in) >= 0;
267267
}
268268

269+
// This must handle int and bool types, and must raise a
270+
// TypeError if the argument is not integral
271+
mp_obj_t mp_obj_int_abs(mp_obj_t self_in) {
272+
mp_int_t val = mp_obj_get_int(self_in);
273+
if (val < 0) {
274+
val = -val;
275+
}
276+
return MP_OBJ_NEW_SMALL_INT(val);
277+
}
278+
269279
// This is called for operations on SMALL_INT that are not handled by mp_unary_op
270280
mp_obj_t mp_obj_int_unary_op(mp_uint_t op, mp_obj_t o_in) {
271281
return MP_OBJ_NULL; // op not supported

py/objint.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ char *mp_obj_int_formatted_impl(char **buf, mp_uint_t *buf_size, mp_uint_t *fmt_
5757
int base, const char *prefix, char base_char, char comma);
5858
mp_int_t mp_obj_int_hash(mp_obj_t self_in);
5959
bool mp_obj_int_is_positive(mp_obj_t self_in);
60+
mp_obj_t mp_obj_int_abs(mp_obj_t self_in);
6061
mp_obj_t mp_obj_int_unary_op(mp_uint_t op, mp_obj_t o_in);
6162
mp_obj_t mp_obj_int_binary_op(mp_uint_t op, mp_obj_t lhs_in, mp_obj_t rhs_in);
6263
mp_obj_t mp_obj_int_binary_op_extra_cases(mp_uint_t op, mp_obj_t lhs_in, mp_obj_t rhs_in);

py/objint_longlong.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,30 @@ bool mp_obj_int_is_positive(mp_obj_t self_in) {
7171
return self->val >= 0;
7272
}
7373

74+
// This must handle int and bool types, and must raise a
75+
// TypeError if the argument is not integral
76+
mp_obj_t mp_obj_int_abs(mp_obj_t self_in) {
77+
if (MP_OBJ_IS_TYPE(self_in, &mp_type_int)) {
78+
mp_obj_int_t *self = self_in;
79+
self = mp_obj_new_int_from_ll(self->val);
80+
if (self->val < 0) {
81+
// TODO could overflow long long
82+
self->val = -self->val;
83+
}
84+
return self;
85+
} else {
86+
mp_int_t val = mp_obj_get_int(self_in);
87+
if (val == MP_SMALL_INT_MIN) {
88+
return mp_obj_new_int_from_ll(-val);
89+
} else {
90+
if (val < 0) {
91+
val = -val;
92+
}
93+
return MP_OBJ_NEW_SMALL_INT(val);
94+
}
95+
}
96+
}
97+
7498
mp_obj_t mp_obj_int_unary_op(mp_uint_t op, mp_obj_t o_in) {
7599
mp_obj_int_t *o = o_in;
76100
switch (op) {

py/objint_mpz.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,27 @@ bool mp_obj_int_is_positive(mp_obj_t self_in) {
112112
return !self->mpz.neg;
113113
}
114114

115+
// This must handle int and bool types, and must raise a
116+
// TypeError if the argument is not integral
117+
mp_obj_t mp_obj_int_abs(mp_obj_t self_in) {
118+
if (MP_OBJ_IS_TYPE(self_in, &mp_type_int)) {
119+
mp_obj_int_t *self = self_in;
120+
mp_obj_int_t *self2 = mp_obj_int_new_mpz();
121+
mpz_abs_inpl(&self2->mpz, &self->mpz);
122+
return self2;
123+
} else {
124+
mp_int_t val = mp_obj_get_int(self_in);
125+
if (val == MP_SMALL_INT_MIN) {
126+
return mp_obj_new_int_from_ll(-val);
127+
} else {
128+
if (val < 0) {
129+
val = -val;
130+
}
131+
return MP_OBJ_NEW_SMALL_INT(val);
132+
}
133+
}
134+
}
135+
115136
mp_obj_t mp_obj_int_unary_op(mp_uint_t op, mp_obj_t o_in) {
116137
mp_obj_int_t *o = o_in;
117138
switch (op) {

tests/basics/builtin_abs.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# test builtin abs
2+
3+
print(abs(False))
4+
print(abs(True))
5+
print(abs(1))
6+
print(abs(-1))
7+
8+
# bignum
9+
print(abs(123456789012345678901234567890))
10+
print(abs(-123456789012345678901234567890))
11+
12+
# edge cases for 32 and 64 bit archs (small int overflow when negating)
13+
print(abs(-0x3fffffff - 1))
14+
print(abs(-0x3fffffffffffffff - 1))

0 commit comments

Comments
 (0)