Branch data Line data Source code
1 : : /*
2 : : * This file is part of the MicroPython project, http://micropython.org/
3 : : *
4 : : * The MIT License (MIT)
5 : : *
6 : : * Copyright (c) 2013, 2014 Damien P. George
7 : : *
8 : : * Permission is hereby granted, free of charge, to any person obtaining a copy
9 : : * of this software and associated documentation files (the "Software"), to deal
10 : : * in the Software without restriction, including without limitation the rights
11 : : * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 : : * copies of the Software, and to permit persons to whom the Software is
13 : : * furnished to do so, subject to the following conditions:
14 : : *
15 : : * The above copyright notice and this permission notice shall be included in
16 : : * all copies or substantial portions of the Software.
17 : : *
18 : : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 : : * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 : : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 : : * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 : : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 : : * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 : : * THE SOFTWARE.
25 : : */
26 : :
27 : : #include <stdlib.h>
28 : : #include <stdio.h>
29 : : #include <string.h>
30 : : #include <assert.h>
31 : :
32 : : #include "py/parsenum.h"
33 : : #include "py/runtime.h"
34 : :
35 : : #if MICROPY_PY_BUILTINS_FLOAT
36 : :
37 : : #include <math.h>
38 : : #include "py/formatfloat.h"
39 : :
40 : : #if MICROPY_OBJ_REPR != MICROPY_OBJ_REPR_C && MICROPY_OBJ_REPR != MICROPY_OBJ_REPR_D
41 : :
42 : : // M_E and M_PI are not part of the math.h standard and may not be defined
43 : : #ifndef M_E
44 : : #define M_E (2.7182818284590452354)
45 : : #endif
46 : : #ifndef M_PI
47 : : #define M_PI (3.14159265358979323846)
48 : : #endif
49 : :
50 : : // Workaround a bug in recent MSVC where NAN is no longer constant.
51 : : // (By redefining back to the previous MSVC definition of NAN)
52 : : #if defined(_MSC_VER) && _MSC_VER >= 1942
53 : : #undef NAN
54 : : #define NAN (-(float)(((float)(1e+300 * 1e+300)) * 0.0F))
55 : : #endif
56 : :
57 : : typedef struct _mp_obj_float_t {
58 : : mp_obj_base_t base;
59 : : mp_float_t value;
60 : : } mp_obj_float_t;
61 : :
62 : : const mp_obj_float_t mp_const_float_e_obj = {{&mp_type_float}, (mp_float_t)M_E};
63 : : const mp_obj_float_t mp_const_float_pi_obj = {{&mp_type_float}, (mp_float_t)M_PI};
64 : : #if MICROPY_PY_MATH_CONSTANTS
65 : : #ifndef NAN
66 : : #error NAN macro is not defined
67 : : #endif
68 : : const mp_obj_float_t mp_const_float_tau_obj = {{&mp_type_float}, (mp_float_t)(2.0 * M_PI)};
69 : : const mp_obj_float_t mp_const_float_inf_obj = {{&mp_type_float}, (mp_float_t)INFINITY};
70 : : const mp_obj_float_t mp_const_float_nan_obj = {{&mp_type_float}, (mp_float_t)NAN};
71 : : #endif
72 : :
73 : : #endif
74 : :
75 : : #define MICROPY_FLOAT_ZERO MICROPY_FLOAT_CONST(0.0)
76 : :
77 : : #if MICROPY_FLOAT_HIGH_QUALITY_HASH
78 : : // must return actual integer value if it fits in mp_int_t
79 : 290 : mp_int_t mp_float_hash(mp_float_t src) {
80 : 290 : mp_float_union_t u = {.f = src};
81 : 290 : mp_int_t val;
82 : 290 : const int adj_exp = (int)u.p.exp - MP_FLOAT_EXP_BIAS;
83 [ + + ]: 290 : if (adj_exp < 0) {
84 : : // value < 1; must be sure to handle 0.0 correctly (ie return 0)
85 : 24 : val = u.i;
86 : : } else {
87 : : // if adj_exp is max then: u.p.frc==0 indicates inf, else NaN
88 : : // else: 1 <= value
89 : 266 : mp_float_uint_t frc = u.p.frc | ((mp_float_uint_t)1 << MP_FLOAT_FRAC_BITS);
90 : :
91 [ + + ]: 266 : if (adj_exp <= MP_FLOAT_FRAC_BITS) {
92 : : // number may have a fraction; xor the integer part with the fractional part
93 : 250 : val = (frc >> (MP_FLOAT_FRAC_BITS - adj_exp))
94 : 250 : ^ (frc & (((mp_float_uint_t)1 << (MP_FLOAT_FRAC_BITS - adj_exp)) - 1));
95 [ + + ]: 16 : } else if ((unsigned int)adj_exp < MP_BITS_PER_BYTE * sizeof(mp_int_t) - 1) {
96 : : // the number is a (big) whole integer and will fit in val's signed-width
97 : 4 : val = (mp_int_t)frc << (adj_exp - MP_FLOAT_FRAC_BITS);
98 : : } else {
99 : : // integer part will overflow val's width so just use what bits we can
100 : 12 : val = frc;
101 : : }
102 : : }
103 : :
104 [ + + ]: 290 : if (u.p.sgn) {
105 : 16 : val = -(mp_uint_t)val;
106 : : }
107 : :
108 : 290 : return val;
109 : : }
110 : : #endif
111 : :
112 : 2850 : static void float_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) {
113 : 2850 : (void)kind;
114 : 2850 : mp_float_t o_val = mp_obj_float_get(o_in);
115 : : #if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT
116 : : char buf[16];
117 : : #if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_C
118 : : const int precision = 6;
119 : : #else
120 : : const int precision = 7;
121 : : #endif
122 : : #else
123 : 2850 : char buf[32];
124 : 2850 : const int precision = 16;
125 : : #endif
126 : 2850 : mp_format_float(o_val, buf, sizeof(buf), 'g', precision, '\0');
127 : 2850 : mp_print_str(print, buf);
128 [ + + + + : 2850 : if (strchr(buf, '.') == NULL && strchr(buf, 'e') == NULL && strchr(buf, 'n') == NULL) {
+ + ]
129 : : // Python floats always have decimal point (unless inf or nan)
130 : 504 : mp_print_str(print, ".0");
131 : : }
132 : 2850 : }
133 : :
134 : 21472 : static mp_obj_t float_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
135 : 21472 : (void)type_in;
136 : 21472 : mp_arg_check_num(n_args, n_kw, 0, 1, false);
137 : :
138 [ + + ]: 21472 : switch (n_args) {
139 : 4 : case 0:
140 : 4 : return mp_obj_new_float(0);
141 : :
142 : 21468 : case 1:
143 : : default: {
144 : 21468 : mp_buffer_info_t bufinfo;
145 [ + + ]: 21468 : if (mp_get_buffer(args[0], &bufinfo, MP_BUFFER_READ)) {
146 : : // a textual representation, parse it
147 : 21436 : return mp_parse_num_float(bufinfo.buf, bufinfo.len, false, NULL);
148 [ + + + + ]: 32 : } else if (mp_obj_is_float(args[0])) {
149 : : // a float, just return it
150 : : return args[0];
151 : : } else {
152 : : // something else, try to cast it to a float
153 : 28 : return mp_obj_new_float(mp_obj_get_float(args[0]));
154 : : }
155 : : }
156 : : }
157 : : }
158 : :
159 : 187858 : static mp_obj_t float_unary_op(mp_unary_op_t op, mp_obj_t o_in) {
160 : 187858 : mp_float_t val = mp_obj_float_get(o_in);
161 [ + + + + : 187858 : switch (op) {
+ + ]
162 : 10 : case MP_UNARY_OP_BOOL:
163 [ + + ]: 10 : return mp_obj_new_bool(val != 0);
164 : 274 : case MP_UNARY_OP_HASH:
165 : 274 : return MP_OBJ_NEW_SMALL_INT(mp_float_hash(val));
166 : : case MP_UNARY_OP_POSITIVE:
167 : : return o_in;
168 : 2758 : case MP_UNARY_OP_NEGATIVE:
169 : 2758 : return mp_obj_new_float(-val);
170 : 28400 : case MP_UNARY_OP_ABS: {
171 [ + + ]: 28400 : if (signbit(val)) {
172 : 5014 : return mp_obj_new_float(-val);
173 : : } else {
174 : : return o_in;
175 : : }
176 : : }
177 : 156412 : default:
178 : 156412 : return MP_OBJ_NULL; // op not supported
179 : : }
180 : : }
181 : :
182 : 569664 : static mp_obj_t float_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
183 : 569664 : mp_float_t lhs_val = mp_obj_float_get(lhs_in);
184 : : #if MICROPY_PY_BUILTINS_COMPLEX
185 [ - + - + : 569664 : if (mp_obj_is_type(rhs_in, &mp_type_complex)) {
- + - + +
+ + + ]
186 : 24 : return mp_obj_complex_binary_op(op, lhs_val, 0, rhs_in);
187 : : }
188 : : #endif
189 : 569640 : return mp_obj_float_binary_op(op, lhs_val, rhs_in);
190 : : }
191 : :
192 : : MP_DEFINE_CONST_OBJ_TYPE(
193 : : mp_type_float, MP_QSTR_float, MP_TYPE_FLAG_EQ_NOT_REFLEXIVE | MP_TYPE_FLAG_EQ_CHECKS_OTHER_TYPE,
194 : : make_new, float_make_new,
195 : : print, float_print,
196 : : unary_op, float_unary_op,
197 : : binary_op, float_binary_op
198 : : );
199 : :
200 : : #if MICROPY_OBJ_REPR != MICROPY_OBJ_REPR_C && MICROPY_OBJ_REPR != MICROPY_OBJ_REPR_D
201 : :
202 : 375640 : mp_obj_t mp_obj_new_float(mp_float_t value) {
203 : : // Don't use mp_obj_malloc here to avoid extra function call overhead.
204 : 375640 : mp_obj_float_t *o = m_new_obj(mp_obj_float_t);
205 : 375636 : o->base.type = &mp_type_float;
206 : 375636 : o->value = value;
207 : 375636 : return MP_OBJ_FROM_PTR(o);
208 : : }
209 : :
210 : 1170328 : mp_float_t mp_obj_float_get(mp_obj_t self_in) {
211 [ + - - + ]: 1170328 : assert(mp_obj_is_float(self_in));
212 : 1170328 : mp_obj_float_t *self = MP_OBJ_TO_PTR(self_in);
213 : 1170328 : return self->value;
214 : : }
215 : :
216 : : #endif
217 : :
218 : 12668 : static void mp_obj_float_divmod(mp_float_t *x, mp_float_t *y) {
219 : : // logic here follows that of CPython
220 : : // https://docs.python.org/3/reference/expressions.html#binary-arithmetic-operations
221 : : // x == (x//y)*y + (x%y)
222 : : // divmod(x, y) == (x//y, x%y)
223 : 12668 : mp_float_t mod = MICROPY_FLOAT_C_FUN(fmod)(*x, *y);
224 : 12668 : mp_float_t div = (*x - mod) / *y;
225 : :
226 : : // Python specs require that mod has same sign as second operand
227 [ + + ]: 12668 : if (mod == MICROPY_FLOAT_ZERO) {
228 : 1224 : mod = MICROPY_FLOAT_C_FUN(copysign)(MICROPY_FLOAT_ZERO, *y);
229 : : } else {
230 [ + + ]: 11444 : if ((mod < MICROPY_FLOAT_ZERO) != (*y < MICROPY_FLOAT_ZERO)) {
231 : 5720 : mod += *y;
232 : 5720 : div -= MICROPY_FLOAT_CONST(1.0);
233 : : }
234 : : }
235 : :
236 : 12668 : mp_float_t floordiv;
237 [ + + ]: 12668 : if (div == MICROPY_FLOAT_ZERO) {
238 : : // if division is zero, take the correct sign of zero
239 : 2884 : floordiv = MICROPY_FLOAT_C_FUN(copysign)(MICROPY_FLOAT_ZERO, *x / *y);
240 : : } else {
241 : : // Python specs require that x == (x//y)*y + (x%y)
242 : 9784 : floordiv = MICROPY_FLOAT_C_FUN(floor)(div);
243 [ + + ]: 9784 : if (div - floordiv > MICROPY_FLOAT_CONST(0.5)) {
244 : 60 : floordiv += MICROPY_FLOAT_CONST(1.0);
245 : : }
246 : : }
247 : :
248 : : // return results
249 : 12668 : *x = floordiv;
250 : 12668 : *y = mod;
251 : 12668 : }
252 : :
253 : 576436 : mp_obj_t mp_obj_float_binary_op(mp_binary_op_t op, mp_float_t lhs_val, mp_obj_t rhs_in) {
254 : 576436 : mp_float_t rhs_val;
255 [ + + ]: 576436 : if (!mp_obj_get_float_maybe(rhs_in, &rhs_val)) {
256 : : return MP_OBJ_NULL; // op not supported
257 : : }
258 : :
259 [ + + + + : 576412 : switch (op) {
+ + + + +
+ + + +
+ ]
260 : 34928 : case MP_BINARY_OP_ADD:
261 : : case MP_BINARY_OP_INPLACE_ADD:
262 : 34928 : lhs_val += rhs_val;
263 : 34928 : break;
264 : 32088 : case MP_BINARY_OP_SUBTRACT:
265 : : case MP_BINARY_OP_INPLACE_SUBTRACT:
266 : 32088 : lhs_val -= rhs_val;
267 : 32088 : break;
268 : 201166 : case MP_BINARY_OP_MULTIPLY:
269 : : case MP_BINARY_OP_INPLACE_MULTIPLY:
270 : 201166 : lhs_val *= rhs_val;
271 : 201166 : break;
272 : 7608 : case MP_BINARY_OP_FLOOR_DIVIDE:
273 : : case MP_BINARY_OP_INPLACE_FLOOR_DIVIDE:
274 [ + + ]: 7608 : if (rhs_val == 0) {
275 : 4 : zero_division_error:
276 : 44 : mp_raise_msg(&mp_type_ZeroDivisionError, MP_ERROR_TEXT("divide by zero"));
277 : : }
278 : : // Python specs require that x == (x//y)*y + (x%y) so we must
279 : : // call divmod to compute the correct floor division, which
280 : : // returns the floor divide in lhs_val.
281 : 7604 : mp_obj_float_divmod(&lhs_val, &rhs_val);
282 : 7604 : break;
283 : 25190 : case MP_BINARY_OP_TRUE_DIVIDE:
284 : : case MP_BINARY_OP_INPLACE_TRUE_DIVIDE:
285 [ + + ]: 25190 : if (rhs_val == 0) {
286 : 16 : goto zero_division_error;
287 : : }
288 : 25174 : lhs_val /= rhs_val;
289 : 25174 : break;
290 : 7608 : case MP_BINARY_OP_MODULO:
291 : : case MP_BINARY_OP_INPLACE_MODULO:
292 [ + + ]: 7608 : if (rhs_val == MICROPY_FLOAT_ZERO) {
293 : 4 : goto zero_division_error;
294 : : }
295 : 7604 : lhs_val = MICROPY_FLOAT_C_FUN(fmod)(lhs_val, rhs_val);
296 : : // Python specs require that mod has same sign as second operand
297 [ + + ]: 7604 : if (lhs_val == MICROPY_FLOAT_ZERO) {
298 : 732 : lhs_val = MICROPY_FLOAT_C_FUN(copysign)(0.0, rhs_val);
299 : : } else {
300 [ + + ]: 6872 : if ((lhs_val < MICROPY_FLOAT_ZERO) != (rhs_val < MICROPY_FLOAT_ZERO)) {
301 : 3432 : lhs_val += rhs_val;
302 : : }
303 : : }
304 : : break;
305 : 19480 : case MP_BINARY_OP_POWER:
306 : : case MP_BINARY_OP_INPLACE_POWER:
307 [ + + + + : 19480 : if (lhs_val == 0 && rhs_val < 0 && !isinf(rhs_val)) {
+ + ]
308 : 16 : goto zero_division_error;
309 : : }
310 [ + + + + : 19464 : if (lhs_val < 0 && rhs_val != MICROPY_FLOAT_C_FUN(floor)(rhs_val) && !isnan(rhs_val)) {
+ + ]
311 : : #if MICROPY_PY_BUILTINS_COMPLEX
312 : 8 : return mp_obj_complex_binary_op(MP_BINARY_OP_POWER, lhs_val, 0, rhs_in);
313 : : #else
314 : : mp_raise_ValueError(MP_ERROR_TEXT("complex values not supported"));
315 : : #endif
316 : : }
317 : : #if MICROPY_PY_MATH_POW_FIX_NAN // Also see modmath.c.
318 : : if (lhs_val == MICROPY_FLOAT_CONST(1.0) || rhs_val == MICROPY_FLOAT_CONST(0.0)) {
319 : : lhs_val = MICROPY_FLOAT_CONST(1.0);
320 : : break;
321 : : }
322 : : #endif
323 : 19456 : lhs_val = MICROPY_FLOAT_C_FUN(pow)(lhs_val, rhs_val);
324 : 19456 : break;
325 : 5068 : case MP_BINARY_OP_DIVMOD: {
326 [ + + ]: 5068 : if (rhs_val == 0) {
327 : 4 : goto zero_division_error;
328 : : }
329 : 5064 : mp_obj_float_divmod(&lhs_val, &rhs_val);
330 : 15192 : mp_obj_t tuple[2] = {
331 : 5064 : mp_obj_new_float(lhs_val),
332 : 5064 : mp_obj_new_float(rhs_val),
333 : : };
334 : 5064 : return mp_obj_new_tuple(2, tuple);
335 : : }
336 : 6544 : case MP_BINARY_OP_LESS:
337 [ + + ]: 6544 : return mp_obj_new_bool(lhs_val < rhs_val);
338 : 182592 : case MP_BINARY_OP_MORE:
339 [ + + ]: 182592 : return mp_obj_new_bool(lhs_val > rhs_val);
340 : 53076 : case MP_BINARY_OP_EQUAL:
341 [ + + ]: 53076 : return mp_obj_new_bool(lhs_val == rhs_val);
342 : 888 : case MP_BINARY_OP_LESS_EQUAL:
343 [ + + ]: 888 : return mp_obj_new_bool(lhs_val <= rhs_val);
344 : 168 : case MP_BINARY_OP_MORE_EQUAL:
345 [ + + ]: 168 : return mp_obj_new_bool(lhs_val >= rhs_val);
346 : :
347 : : default:
348 : : return MP_OBJ_NULL; // op not supported
349 : : }
350 : 328020 : return mp_obj_new_float(lhs_val);
351 : : }
352 : :
353 : : #endif // MICROPY_PY_BUILTINS_FLOAT
|