all: Fix implicit floating point promotion.
Initially some of these were found building the unix coverage variant on MacOS because that build uses clang and has -Wdouble-promotion enabled, and clang performs more vigorous promotion checks than gcc. Additionally the codebase has been compiled with clang and msvc (the latter with warning level 3), and with MICROPY_FLOAT_IMPL_FLOAT to find the rest of the conversions. Fixes are implemented either as explicit casts, or by using the correct type, or by using one of the utility functions to handle floating point casting; these have been moved from nativeglue.c to the public API.
This commit is contained in:
parent
b909e8b2dd
commit
0ba68f8a1d
|
@ -360,7 +360,7 @@ STATIC mp_obj_t get_aligned(uint val_type, void *p, mp_int_t index) {
|
|||
return mp_obj_new_int_from_ll(((int64_t *)p)[index]);
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
case FLOAT32:
|
||||
return mp_obj_new_float(((float *)p)[index]);
|
||||
return mp_obj_new_float_from_f(((float *)p)[index]);
|
||||
case FLOAT64:
|
||||
return mp_obj_new_float(((double *)p)[index]);
|
||||
#endif
|
||||
|
@ -373,11 +373,10 @@ STATIC mp_obj_t get_aligned(uint val_type, void *p, mp_int_t index) {
|
|||
STATIC void set_aligned(uint val_type, void *p, mp_int_t index, mp_obj_t val) {
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
if (val_type == FLOAT32 || val_type == FLOAT64) {
|
||||
mp_float_t v = mp_obj_get_float(val);
|
||||
if (val_type == FLOAT32) {
|
||||
((float *)p)[index] = v;
|
||||
((float *)p)[index] = mp_obj_get_float_to_f(val);
|
||||
} else {
|
||||
((double *)p)[index] = v;
|
||||
((double *)p)[index] = mp_obj_get_float_to_d(val);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -125,7 +125,7 @@ STATIC mp_obj_t select_select(size_t n_args, const mp_obj_t *args) {
|
|||
if (n_args == 4) {
|
||||
if (args[3] != mp_const_none) {
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
float timeout_f = mp_obj_get_float(args[3]);
|
||||
float timeout_f = mp_obj_get_float_to_f(args[3]);
|
||||
if (timeout_f >= 0) {
|
||||
timeout = (mp_uint_t)(timeout_f * 1000);
|
||||
}
|
||||
|
|
|
@ -167,7 +167,7 @@ STATIC mp_obj_t return_ffi_value(ffi_arg val, char type) {
|
|||
union { ffi_arg ffi;
|
||||
float flt;
|
||||
} val_union = { .ffi = val };
|
||||
return mp_obj_new_float(val_union.flt);
|
||||
return mp_obj_new_float_from_f(val_union.flt);
|
||||
}
|
||||
case 'd': {
|
||||
double *p = (double *)&val;
|
||||
|
@ -381,7 +381,7 @@ STATIC mp_obj_t ffifunc_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const
|
|||
*p = mp_obj_get_float(a);
|
||||
} else if (*argtype == 'd') {
|
||||
double *p = (double *)&values[i];
|
||||
*p = mp_obj_get_float(a);
|
||||
*p = mp_obj_get_float_to_d(a);
|
||||
#endif
|
||||
} else if (a == mp_const_none) {
|
||||
values[i] = 0;
|
||||
|
|
|
@ -61,7 +61,7 @@ static inline int msec_sleep_tv(struct timeval *tv) {
|
|||
#endif
|
||||
|
||||
#if defined(MP_CLOCKS_PER_SEC)
|
||||
#define CLOCK_DIV (MP_CLOCKS_PER_SEC / 1000.0F)
|
||||
#define CLOCK_DIV (MP_CLOCKS_PER_SEC / MICROPY_FLOAT_CONST(1000.0))
|
||||
#else
|
||||
#error Unsupported clock() implementation
|
||||
#endif
|
||||
|
@ -84,7 +84,7 @@ STATIC mp_obj_t mod_time_clock(void) {
|
|||
// float cannot represent full range of int32 precisely, so we pre-divide
|
||||
// int to reduce resolution, and then actually do float division hoping
|
||||
// to preserve integer part resolution.
|
||||
return mp_obj_new_float((float)(clock() / 1000) / CLOCK_DIV);
|
||||
return mp_obj_new_float((clock() / 1000) / CLOCK_DIV);
|
||||
#else
|
||||
return mp_obj_new_int((mp_int_t)clock());
|
||||
#endif
|
||||
|
@ -95,8 +95,8 @@ STATIC mp_obj_t mod_time_sleep(mp_obj_t arg) {
|
|||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
struct timeval tv;
|
||||
mp_float_t val = mp_obj_get_float(arg);
|
||||
double ipart;
|
||||
tv.tv_usec = round(modf(val, &ipart) * 1000000);
|
||||
mp_float_t ipart;
|
||||
tv.tv_usec = MICROPY_FLOAT_C_FUN(round)(MICROPY_FLOAT_C_FUN(modf)(val, &ipart) * MICROPY_FLOAT_CONST(1000000.));
|
||||
tv.tv_sec = ipart;
|
||||
int res;
|
||||
while (1) {
|
||||
|
|
|
@ -378,8 +378,8 @@ STATIC mp_obj_t socket_settimeout(mp_obj_t self_in, mp_obj_t timeout_in) {
|
|||
if (timeout_in != mp_const_none) {
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
mp_float_t val = mp_obj_get_float(timeout_in);
|
||||
double ipart;
|
||||
tv.tv_usec = round(modf(val, &ipart) * 1000000);
|
||||
mp_float_t ipart;
|
||||
tv.tv_usec = MICROPY_FLOAT_C_FUN(round)(MICROPY_FLOAT_C_FUN(modf)(val, &ipart) * MICROPY_FLOAT_CONST(1000000.));
|
||||
tv.tv_sec = ipart;
|
||||
#else
|
||||
tv.tv_sec = mp_obj_get_int(timeout_in);
|
||||
|
|
|
@ -176,7 +176,7 @@ mp_obj_t mp_binary_get_val_array(char typecode, void *p, size_t index) {
|
|||
#endif
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
case 'f':
|
||||
return mp_obj_new_float(((float *)p)[index]);
|
||||
return mp_obj_new_float_from_f(((float *)p)[index]);
|
||||
case 'd':
|
||||
return mp_obj_new_float(((double *)p)[index]);
|
||||
#endif
|
||||
|
@ -244,7 +244,7 @@ mp_obj_t mp_binary_get_val(char struct_type, char val_type, byte *p_base, byte *
|
|||
union { uint32_t i;
|
||||
float f;
|
||||
} fpu = {val};
|
||||
return mp_obj_new_float(fpu.f);
|
||||
return mp_obj_new_float_from_f(fpu.f);
|
||||
} else if (val_type == 'd') {
|
||||
union { uint64_t i;
|
||||
double f;
|
||||
|
@ -320,7 +320,7 @@ void mp_binary_set_val(char struct_type, char val_type, mp_obj_t val_in, byte *p
|
|||
uint32_t i32[2];
|
||||
double f;
|
||||
} fp_dp;
|
||||
fp_dp.f = mp_obj_get_float(val_in);
|
||||
fp_dp.f = mp_obj_get_float_to_d(val_in);
|
||||
if (BYTES_PER_WORD == 8) {
|
||||
val = fp_dp.i64;
|
||||
} else {
|
||||
|
@ -362,7 +362,7 @@ void mp_binary_set_val_array(char typecode, void *p, size_t index, mp_obj_t val_
|
|||
((float *)p)[index] = mp_obj_get_float(val_in);
|
||||
break;
|
||||
case 'd':
|
||||
((double *)p)[index] = mp_obj_get_float(val_in);
|
||||
((double *)p)[index] = mp_obj_get_float_to_d(val_in);
|
||||
break;
|
||||
#endif
|
||||
// Extension to CPython: array of objects
|
||||
|
|
|
@ -72,7 +72,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_cmath_exp_obj, mp_cmath_exp);
|
|||
STATIC mp_obj_t mp_cmath_log(mp_obj_t z_obj) {
|
||||
mp_float_t real, imag;
|
||||
mp_obj_get_complex(z_obj, &real, &imag);
|
||||
return mp_obj_new_complex(0.5 * MICROPY_FLOAT_C_FUN(log)(real * real + imag * imag), MICROPY_FLOAT_C_FUN(atan2)(imag, real));
|
||||
return mp_obj_new_complex(MICROPY_FLOAT_CONST(0.5) * MICROPY_FLOAT_C_FUN(log)(real * real + imag * imag), MICROPY_FLOAT_C_FUN(atan2)(imag, real));
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_cmath_log_obj, mp_cmath_log);
|
||||
|
||||
|
@ -81,7 +81,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_cmath_log_obj, mp_cmath_log);
|
|||
STATIC mp_obj_t mp_cmath_log10(mp_obj_t z_obj) {
|
||||
mp_float_t real, imag;
|
||||
mp_obj_get_complex(z_obj, &real, &imag);
|
||||
return mp_obj_new_complex(0.5 * MICROPY_FLOAT_C_FUN(log10)(real * real + imag * imag), 0.4342944819032518 * MICROPY_FLOAT_C_FUN(atan2)(imag, real));
|
||||
return mp_obj_new_complex(MICROPY_FLOAT_CONST(0.5) * MICROPY_FLOAT_C_FUN(log10)(real * real + imag * imag), MICROPY_FLOAT_CONST(0.4342944819032518) * MICROPY_FLOAT_C_FUN(atan2)(imag, real));
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_cmath_log10_obj, mp_cmath_log10);
|
||||
#endif
|
||||
|
@ -90,8 +90,8 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_cmath_log10_obj, mp_cmath_log10);
|
|||
STATIC mp_obj_t mp_cmath_sqrt(mp_obj_t z_obj) {
|
||||
mp_float_t real, imag;
|
||||
mp_obj_get_complex(z_obj, &real, &imag);
|
||||
mp_float_t sqrt_abs = MICROPY_FLOAT_C_FUN(pow)(real * real + imag * imag, 0.25);
|
||||
mp_float_t theta = 0.5 * MICROPY_FLOAT_C_FUN(atan2)(imag, real);
|
||||
mp_float_t sqrt_abs = MICROPY_FLOAT_C_FUN(pow)(real * real + imag * imag, MICROPY_FLOAT_CONST(0.25));
|
||||
mp_float_t theta = MICROPY_FLOAT_CONST(0.5) * MICROPY_FLOAT_C_FUN(atan2)(imag, real);
|
||||
return mp_obj_new_complex(sqrt_abs * MICROPY_FLOAT_C_FUN(cos)(theta), sqrt_abs * MICROPY_FLOAT_C_FUN(sin)(theta));
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_cmath_sqrt_obj, mp_cmath_sqrt);
|
||||
|
|
|
@ -227,25 +227,7 @@ STATIC bool mp_native_yield_from(mp_obj_t gen, mp_obj_t send_value, mp_obj_t *re
|
|||
return false;
|
||||
}
|
||||
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
|
||||
STATIC mp_obj_t mp_obj_new_float_from_f(float f) {
|
||||
return mp_obj_new_float((mp_float_t)f);
|
||||
}
|
||||
|
||||
STATIC mp_obj_t mp_obj_new_float_from_d(double d) {
|
||||
return mp_obj_new_float((mp_float_t)d);
|
||||
}
|
||||
|
||||
STATIC float mp_obj_get_float_to_f(mp_obj_t o) {
|
||||
return (float)mp_obj_get_float(o);
|
||||
}
|
||||
|
||||
STATIC double mp_obj_get_float_to_d(mp_obj_t o) {
|
||||
return (double)mp_obj_get_float(o);
|
||||
}
|
||||
|
||||
#else
|
||||
#if !MICROPY_PY_BUILTINS_FLOAT
|
||||
|
||||
STATIC mp_obj_t mp_obj_new_float_from_f(float f) {
|
||||
(void)f;
|
||||
|
|
33
py/obj.h
33
py/obj.h
|
@ -820,6 +820,39 @@ void mp_str_print_quoted(const mp_print_t *print, const byte *str_data, size_t s
|
|||
|
||||
#if MICROPY_PY_BUILTINS_FLOAT
|
||||
// float
|
||||
#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT
|
||||
static inline float mp_obj_get_float_to_f(mp_obj_t o) {
|
||||
return mp_obj_get_float(o);
|
||||
}
|
||||
|
||||
static inline double mp_obj_get_float_to_d(mp_obj_t o) {
|
||||
return (double)mp_obj_get_float(o);
|
||||
}
|
||||
|
||||
static inline mp_obj_t mp_obj_new_float_from_f(float o) {
|
||||
return mp_obj_new_float(o);
|
||||
}
|
||||
|
||||
static inline mp_obj_t mp_obj_new_float_from_d(double o) {
|
||||
return mp_obj_new_float((mp_float_t)o);
|
||||
}
|
||||
#elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE
|
||||
static inline float mp_obj_get_float_to_f(mp_obj_t o) {
|
||||
return (float)mp_obj_get_float(o);
|
||||
}
|
||||
|
||||
static inline double mp_obj_get_float_to_d(mp_obj_t o) {
|
||||
return mp_obj_get_float(o);
|
||||
}
|
||||
|
||||
static inline mp_obj_t mp_obj_new_float_from_f(float o) {
|
||||
return mp_obj_new_float((mp_float_t)o);
|
||||
}
|
||||
|
||||
static inline mp_obj_t mp_obj_new_float_from_d(double o) {
|
||||
return mp_obj_new_float(o);
|
||||
}
|
||||
#endif
|
||||
#if MICROPY_FLOAT_HIGH_QUALITY_HASH
|
||||
mp_int_t mp_float_hash(mp_float_t val);
|
||||
#else
|
||||
|
|
|
@ -52,11 +52,13 @@ typedef struct _mp_obj_float_t {
|
|||
mp_float_t value;
|
||||
} mp_obj_float_t;
|
||||
|
||||
const mp_obj_float_t mp_const_float_e_obj = {{&mp_type_float}, M_E};
|
||||
const mp_obj_float_t mp_const_float_pi_obj = {{&mp_type_float}, M_PI};
|
||||
const mp_obj_float_t mp_const_float_e_obj = {{&mp_type_float}, (mp_float_t)M_E};
|
||||
const mp_obj_float_t mp_const_float_pi_obj = {{&mp_type_float}, (mp_float_t)M_PI};
|
||||
|
||||
#endif
|
||||
|
||||
#define MICROPY_FLOAT_ZERO MICROPY_FLOAT_CONST(0.0)
|
||||
|
||||
#if MICROPY_FLOAT_HIGH_QUALITY_HASH
|
||||
// must return actual integer value if it fits in mp_int_t
|
||||
mp_int_t mp_float_hash(mp_float_t src) {
|
||||
|
@ -208,24 +210,24 @@ STATIC void mp_obj_float_divmod(mp_float_t *x, mp_float_t *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);
|
||||
if (mod == MICROPY_FLOAT_ZERO) {
|
||||
mod = MICROPY_FLOAT_C_FUN(copysign)(MICROPY_FLOAT_ZERO, *y);
|
||||
} else {
|
||||
if ((mod < 0.0) != (*y < 0.0)) {
|
||||
if ((mod < MICROPY_FLOAT_ZERO) != (*y < MICROPY_FLOAT_ZERO)) {
|
||||
mod += *y;
|
||||
div -= 1.0;
|
||||
div -= MICROPY_FLOAT_CONST(1.0);
|
||||
}
|
||||
}
|
||||
|
||||
mp_float_t floordiv;
|
||||
if (div == 0.0) {
|
||||
if (div == MICROPY_FLOAT_ZERO) {
|
||||
// if division is zero, take the correct sign of zero
|
||||
floordiv = MICROPY_FLOAT_C_FUN(copysign)(0.0, *x / *y);
|
||||
floordiv = MICROPY_FLOAT_C_FUN(copysign)(MICROPY_FLOAT_ZERO, *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;
|
||||
if (div - floordiv > MICROPY_FLOAT_CONST(0.5)) {
|
||||
floordiv += MICROPY_FLOAT_CONST(1.0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -273,15 +275,15 @@ mp_obj_t mp_obj_float_binary_op(mp_binary_op_t op, mp_float_t lhs_val, mp_obj_t
|
|||
break;
|
||||
case MP_BINARY_OP_MODULO:
|
||||
case MP_BINARY_OP_INPLACE_MODULO:
|
||||
if (rhs_val == 0) {
|
||||
if (rhs_val == MICROPY_FLOAT_ZERO) {
|
||||
goto zero_division_error;
|
||||
}
|
||||
lhs_val = MICROPY_FLOAT_C_FUN(fmod)(lhs_val, rhs_val);
|
||||
// Python specs require that mod has same sign as second operand
|
||||
if (lhs_val == 0.0) {
|
||||
if (lhs_val == MICROPY_FLOAT_ZERO) {
|
||||
lhs_val = MICROPY_FLOAT_C_FUN(copysign)(0.0, rhs_val);
|
||||
} else {
|
||||
if ((lhs_val < 0.0) != (rhs_val < 0.0)) {
|
||||
if ((lhs_val < MICROPY_FLOAT_ZERO) != (rhs_val < MICROPY_FLOAT_ZERO)) {
|
||||
lhs_val += rhs_val;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -220,7 +220,7 @@ mp_obj_t mp_parse_num_decimal(const char *str, size_t len, bool allow_imag, bool
|
|||
if (str + 2 < top && (str[1] | 0x20) == 'n' && (str[2] | 0x20) == 'f') {
|
||||
// inf
|
||||
str += 3;
|
||||
dec_val = INFINITY;
|
||||
dec_val = (mp_float_t)INFINITY;
|
||||
if (str + 4 < top && (str[0] | 0x20) == 'i' && (str[1] | 0x20) == 'n' && (str[2] | 0x20) == 'i' && (str[3] | 0x20) == 't' && (str[4] | 0x20) == 'y') {
|
||||
// infinity
|
||||
str += 5;
|
||||
|
|
Loading…
Reference in New Issue