py: Add MP_BINARY_OP_DIVMOD to simplify and consolidate divmod builtin.

pull/1315/merge
Damien George 2015-06-13 22:00:10 +01:00
rodzic 6f49520042
commit c5029bcbf3
10 zmienionych plików z 71 dodań i 85 usunięć

Wyświetl plik

@ -117,6 +117,6 @@
#define MP_BC_LOAD_FAST_MULTI (0xb0) // + N(16)
#define MP_BC_STORE_FAST_MULTI (0xc0) // + N(16)
#define MP_BC_UNARY_OP_MULTI (0xd0) // + op(6)
#define MP_BC_BINARY_OP_MULTI (0xd6) // + op(35)
#define MP_BC_BINARY_OP_MULTI (0xd6) // + op(36)
#endif // __MICROPY_INCLUDED_PY_BC0_H__

Wyświetl plik

@ -230,44 +230,7 @@ STATIC mp_obj_t mp_builtin_dir(mp_uint_t n_args, const mp_obj_t *args) {
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_dir_obj, 0, 1, mp_builtin_dir);
STATIC mp_obj_t mp_builtin_divmod(mp_obj_t o1_in, mp_obj_t o2_in) {
// TODO handle big int
if (MP_OBJ_IS_SMALL_INT(o1_in) && MP_OBJ_IS_SMALL_INT(o2_in)) {
mp_int_t i1 = MP_OBJ_SMALL_INT_VALUE(o1_in);
mp_int_t i2 = MP_OBJ_SMALL_INT_VALUE(o2_in);
if (i2 == 0) {
#if MICROPY_PY_BUILTINS_FLOAT
zero_division_error:
#endif
nlr_raise(mp_obj_new_exception_msg(&mp_type_ZeroDivisionError, "division by zero"));
}
mp_obj_t args[2];
args[0] = MP_OBJ_NEW_SMALL_INT(mp_small_int_floor_divide(i1, i2));
args[1] = MP_OBJ_NEW_SMALL_INT(mp_small_int_modulo(i1, i2));
return mp_obj_new_tuple(2, args);
#if MICROPY_PY_BUILTINS_FLOAT
} else if (MP_OBJ_IS_TYPE(o1_in, &mp_type_float) || MP_OBJ_IS_TYPE(o2_in, &mp_type_float)) {
mp_float_t f1 = mp_obj_get_float(o1_in);
mp_float_t f2 = mp_obj_get_float(o2_in);
if (f2 == 0.0) {
goto zero_division_error;
}
mp_obj_float_divmod(&f1, &f2);
mp_obj_t tuple[2] = {
mp_obj_new_float(f1),
mp_obj_new_float(f2),
};
return mp_obj_new_tuple(2, tuple);
#endif
} else {
if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError,
"unsupported operand type(s) for divmod()"));
} else {
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
"unsupported operand type(s) for divmod(): '%s' and '%s'",
mp_obj_get_type_str(o1_in), mp_obj_get_type_str(o2_in)));
}
}
return mp_binary_op(MP_BINARY_OP_DIVMOD, o1_in, o2_in);
}
MP_DEFINE_CONST_FUN_OBJ_2(mp_builtin_divmod_obj, mp_builtin_divmod);

Wyświetl plik

@ -575,7 +575,6 @@ typedef struct _mp_obj_float_t {
} mp_obj_float_t;
mp_float_t mp_obj_float_get(mp_obj_t self_in);
mp_obj_t mp_obj_float_binary_op(mp_uint_t op, mp_float_t lhs_val, mp_obj_t rhs); // can return MP_OBJ_NULL if op not supported
void mp_obj_float_divmod(mp_float_t *x, mp_float_t *y);
// complex
void mp_obj_complex_get(mp_obj_t self_in, mp_float_t *real, mp_float_t *imag);

Wyświetl plik

@ -126,6 +126,41 @@ mp_float_t mp_obj_float_get(mp_obj_t self_in) {
return self->value;
}
STATIC void mp_obj_float_divmod(mp_float_t *x, mp_float_t *y) {
// logic here follows that of CPython
// https://docs.python.org/3/reference/expressions.html#binary-arithmetic-operations
// x == (x//y)*y + (x%y)
// divmod(x, y) == (x//y, x%y)
mp_float_t mod = MICROPY_FLOAT_C_FUN(fmod)(*x, *y);
mp_float_t div = (*x - mod) / *y;
// Python specs require that mod has same sign as second operand
if (mod == 0.0) {
mod = MICROPY_FLOAT_C_FUN(copysign)(0.0, *y);
} else {
if ((mod < 0.0) != (*y < 0.0)) {
mod += *y;
div -= 1.0;
}
}
mp_float_t floordiv;
if (div == 0.0) {
// if division is zero, take the correct sign of zero
floordiv = MICROPY_FLOAT_C_FUN(copysign)(0.0, *x / *y);
} else {
// Python specs require that x == (x//y)*y + (x%y)
floordiv = MICROPY_FLOAT_C_FUN(floor)(div);
if (div - floordiv > 0.5) {
floordiv += 1.0;
}
}
// return results
*x = floordiv;
*y = mod;
}
mp_obj_t mp_obj_float_binary_op(mp_uint_t op, mp_float_t lhs_val, mp_obj_t rhs_in) {
mp_float_t rhs_val = mp_obj_get_float(rhs_in); // can be any type, this function will convert to float (if possible)
switch (op) {
@ -170,6 +205,17 @@ mp_obj_t mp_obj_float_binary_op(mp_uint_t op, mp_float_t lhs_val, mp_obj_t rhs_i
break;
case MP_BINARY_OP_POWER:
case MP_BINARY_OP_INPLACE_POWER: lhs_val = MICROPY_FLOAT_C_FUN(pow)(lhs_val, rhs_val); break;
case MP_BINARY_OP_DIVMOD: {
if (rhs_val == 0) {
goto zero_division_error;
}
mp_obj_float_divmod(&lhs_val, &rhs_val);
mp_obj_t tuple[2] = {
mp_obj_new_float(lhs_val),
mp_obj_new_float(rhs_val),
};
return mp_obj_new_tuple(2, tuple);
}
case MP_BINARY_OP_LESS: return MP_BOOL(lhs_val < rhs_val);
case MP_BINARY_OP_MORE: return MP_BOOL(lhs_val > rhs_val);
case MP_BINARY_OP_EQUAL: return MP_BOOL(lhs_val == rhs_val);
@ -182,39 +228,4 @@ mp_obj_t mp_obj_float_binary_op(mp_uint_t op, mp_float_t lhs_val, mp_obj_t rhs_i
return mp_obj_new_float(lhs_val);
}
void mp_obj_float_divmod(mp_float_t *x, mp_float_t *y) {
// logic here follows that of CPython
// https://docs.python.org/3/reference/expressions.html#binary-arithmetic-operations
// x == (x//y)*y + (x%y)
// divmod(x, y) == (x//y, x%y)
mp_float_t mod = MICROPY_FLOAT_C_FUN(fmod)(*x, *y);
mp_float_t div = (*x - mod) / *y;
// Python specs require that mod has same sign as second operand
if (mod == 0.0) {
mod = MICROPY_FLOAT_C_FUN(copysign)(0.0, *y);
} else {
if ((mod < 0.0) != (*y < 0.0)) {
mod += *y;
div -= 1.0;
}
}
mp_float_t floordiv;
if (div == 0.0) {
// if division is zero, take the correct sign of zero
floordiv = MICROPY_FLOAT_C_FUN(copysign)(0.0, *x / *y);
} else {
// Python specs require that x == (x//y)*y + (x%y)
floordiv = MICROPY_FLOAT_C_FUN(floor)(div);
if (div - floordiv > 0.5) {
floordiv += 1.0;
}
}
// return results
*x = floordiv;
*y = mod;
}
#endif // MICROPY_PY_BUILTINS_FLOAT

Wyświetl plik

@ -400,6 +400,7 @@ const qstr mp_binary_op_method_name[] = {
/*
MP_BINARY_OP_MODULO,
MP_BINARY_OP_POWER,
MP_BINARY_OP_DIVMOD,
MP_BINARY_OP_INPLACE_OR,
MP_BINARY_OP_INPLACE_XOR,
MP_BINARY_OP_INPLACE_AND,

Wyświetl plik

@ -441,6 +441,17 @@ mp_obj_t mp_binary_op(mp_uint_t op, mp_obj_t lhs, mp_obj_t rhs) {
lhs = mp_obj_new_int_from_ll(MP_OBJ_SMALL_INT_VALUE(lhs));
goto generic_binary_op;
case MP_BINARY_OP_DIVMOD: {
if (rhs_val == 0) {
goto zero_division;
}
// to reduce stack usage we don't pass a temp array of the 2 items
mp_obj_tuple_t *tuple = mp_obj_new_tuple(2, NULL);
tuple->items[0] = MP_OBJ_NEW_SMALL_INT(mp_small_int_floor_divide(lhs_val, rhs_val));
tuple->items[1] = MP_OBJ_NEW_SMALL_INT(mp_small_int_modulo(lhs_val, rhs_val));
return tuple;
}
case MP_BINARY_OP_LESS: return MP_BOOL(lhs_val < rhs_val); break;
case MP_BINARY_OP_MORE: return MP_BOOL(lhs_val > rhs_val); break;
case MP_BINARY_OP_LESS_EQUAL: return MP_BOOL(lhs_val <= rhs_val); break;

Wyświetl plik

@ -74,29 +74,30 @@ typedef enum {
MP_BINARY_OP_MODULO,
MP_BINARY_OP_POWER,
MP_BINARY_OP_DIVMOD, // not emitted by the compiler but supported by the runtime
MP_BINARY_OP_INPLACE_OR,
MP_BINARY_OP_INPLACE_XOR,
MP_BINARY_OP_INPLACE_AND,
MP_BINARY_OP_INPLACE_AND,
MP_BINARY_OP_INPLACE_LSHIFT,
MP_BINARY_OP_INPLACE_RSHIFT,
MP_BINARY_OP_INPLACE_ADD,
MP_BINARY_OP_INPLACE_SUBTRACT,
MP_BINARY_OP_INPLACE_MULTIPLY,
MP_BINARY_OP_INPLACE_MULTIPLY,
MP_BINARY_OP_INPLACE_FLOOR_DIVIDE,
MP_BINARY_OP_INPLACE_TRUE_DIVIDE,
MP_BINARY_OP_INPLACE_MODULO,
MP_BINARY_OP_INPLACE_POWER,
// these should return a bool
MP_BINARY_OP_LESS,
MP_BINARY_OP_MORE,
MP_BINARY_OP_EQUAL,
MP_BINARY_OP_LESS_EQUAL,
MP_BINARY_OP_MORE_EQUAL,
MP_BINARY_OP_NOT_EQUAL,
MP_BINARY_OP_NOT_EQUAL,
MP_BINARY_OP_IN,
MP_BINARY_OP_IS,
MP_BINARY_OP_EXCEPTION_MATCH,

Wyświetl plik

@ -1199,7 +1199,7 @@ yield:
} else if (ip[-1] < MP_BC_UNARY_OP_MULTI + 6) {
SET_TOP(mp_unary_op(ip[-1] - MP_BC_UNARY_OP_MULTI, TOP()));
DISPATCH();
} else if (ip[-1] < MP_BC_BINARY_OP_MULTI + 35) {
} else if (ip[-1] < MP_BC_BINARY_OP_MULTI + 36) {
mp_obj_t rhs = POP();
mp_obj_t lhs = TOP();
SET_TOP(mp_binary_op(ip[-1] - MP_BC_BINARY_OP_MULTI, lhs, rhs));

Wyświetl plik

@ -112,7 +112,7 @@ static void* entry_table[256] = {
[MP_BC_LOAD_FAST_MULTI ... MP_BC_LOAD_FAST_MULTI + 15] = &&entry_MP_BC_LOAD_FAST_MULTI,
[MP_BC_STORE_FAST_MULTI ... MP_BC_STORE_FAST_MULTI + 15] = &&entry_MP_BC_STORE_FAST_MULTI,
[MP_BC_UNARY_OP_MULTI ... MP_BC_UNARY_OP_MULTI + 5] = &&entry_MP_BC_UNARY_OP_MULTI,
[MP_BC_BINARY_OP_MULTI ... MP_BC_BINARY_OP_MULTI + 34] = &&entry_MP_BC_BINARY_OP_MULTI,
[MP_BC_BINARY_OP_MULTI ... MP_BC_BINARY_OP_MULTI + 35] = &&entry_MP_BC_BINARY_OP_MULTI,
};
#if __clang__

Wyświetl plik

@ -93,21 +93,21 @@ arg names:
69 LOAD_DEREF 14
71 DUP_TOP
72 ROT_THREE
73 BINARY_OP 26 __eq__
73 BINARY_OP 27 __eq__
74 JUMP_IF_FALSE_OR_POP 82
77 LOAD_FAST 1
78 BINARY_OP 26 __eq__
78 BINARY_OP 27 __eq__
79 JUMP 84
82 ROT_TWO
83 POP_TOP
84 STORE_FAST 10
85 LOAD_FAST 0
86 LOAD_DEREF 14
88 BINARY_OP 26 __eq__
88 BINARY_OP 27 __eq__
89 JUMP_IF_FALSE_OR_POP 96
92 LOAD_DEREF 14
94 LOAD_FAST 1
95 BINARY_OP 26 __eq__
95 BINARY_OP 27 __eq__
96 UNARY_OP 0
97 NOT
98 STORE_FAST 10