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 : : typedef struct _mp_obj_float_t {
51 : : mp_obj_base_t base;
52 : : mp_float_t value;
53 : : } mp_obj_float_t;
54 : :
55 : : const mp_obj_float_t mp_const_float_e_obj = {{&mp_type_float}, (mp_float_t)M_E};
56 : : const mp_obj_float_t mp_const_float_pi_obj = {{&mp_type_float}, (mp_float_t)M_PI};
57 : : #if MICROPY_PY_MATH_CONSTANTS
58 : : #ifndef NAN
59 : : #error NAN macro is not defined
60 : : #endif
61 : : const mp_obj_float_t mp_const_float_tau_obj = {{&mp_type_float}, (mp_float_t)(2.0 * M_PI)};
62 : : const mp_obj_float_t mp_const_float_inf_obj = {{&mp_type_float}, (mp_float_t)INFINITY};
63 : : const mp_obj_float_t mp_const_float_nan_obj = {{&mp_type_float}, (mp_float_t)NAN};
64 : : #endif
65 : :
66 : : #endif
67 : :
68 : : #define MICROPY_FLOAT_ZERO MICROPY_FLOAT_CONST(0.0)
69 : :
70 : : #if MICROPY_FLOAT_HIGH_QUALITY_HASH
71 : : // must return actual integer value if it fits in mp_int_t
72 : 290 : mp_int_t mp_float_hash(mp_float_t src) {
73 : 290 : mp_float_union_t u = {.f = src};
74 : 290 : mp_int_t val;
75 : 290 : const int adj_exp = (int)u.p.exp - MP_FLOAT_EXP_BIAS;
76 [ + + ]: 290 : if (adj_exp < 0) {
77 : : // value < 1; must be sure to handle 0.0 correctly (ie return 0)
78 : 24 : val = u.i;
79 : : } else {
80 : : // if adj_exp is max then: u.p.frc==0 indicates inf, else NaN
81 : : // else: 1 <= value
82 : 266 : mp_float_uint_t frc = u.p.frc | ((mp_float_uint_t)1 << MP_FLOAT_FRAC_BITS);
83 : :
84 [ + + ]: 266 : if (adj_exp <= MP_FLOAT_FRAC_BITS) {
85 : : // number may have a fraction; xor the integer part with the fractional part
86 : 250 : val = (frc >> (MP_FLOAT_FRAC_BITS - adj_exp))
87 : 250 : ^ (frc & (((mp_float_uint_t)1 << (MP_FLOAT_FRAC_BITS - adj_exp)) - 1));
88 [ + + ]: 16 : } else if ((unsigned int)adj_exp < MP_BITS_PER_BYTE * sizeof(mp_int_t) - 1) {
89 : : // the number is a (big) whole integer and will fit in val's signed-width
90 : 4 : val = (mp_int_t)frc << (adj_exp - MP_FLOAT_FRAC_BITS);
91 : : } else {
92 : : // integer part will overflow val's width so just use what bits we can
93 : 12 : val = frc;
94 : : }
95 : : }
96 : :
97 [ + + ]: 290 : if (u.p.sgn) {
98 : 16 : val = -(mp_uint_t)val;
99 : : }
100 : :
101 : 290 : return val;
102 : : }
103 : : #endif
104 : :
105 : 2850 : static void float_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) {
106 : 2850 : (void)kind;
107 : 2850 : mp_float_t o_val = mp_obj_float_get(o_in);
108 : : #if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT
109 : : char buf[16];
110 : : #if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_C
111 : : const int precision = 6;
112 : : #else
113 : : const int precision = 7;
114 : : #endif
115 : : #else
116 : 2850 : char buf[32];
117 : 2850 : const int precision = 16;
118 : : #endif
119 : 2850 : mp_format_float(o_val, buf, sizeof(buf), 'g', precision, '\0');
120 : 2850 : mp_print_str(print, buf);
121 [ + + + + : 2850 : if (strchr(buf, '.') == NULL && strchr(buf, 'e') == NULL && strchr(buf, 'n') == NULL) {
+ + ]
122 : : // Python floats always have decimal point (unless inf or nan)
123 : 504 : mp_print_str(print, ".0");
124 : : }
125 : 2850 : }
126 : :
127 : 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) {
128 : 21472 : (void)type_in;
129 : 21472 : mp_arg_check_num(n_args, n_kw, 0, 1, false);
130 : :
131 [ + + ]: 21472 : switch (n_args) {
132 : 4 : case 0:
133 : 4 : return mp_obj_new_float(0);
134 : :
135 : 21468 : case 1:
136 : : default: {
137 : 21468 : mp_buffer_info_t bufinfo;
138 [ + + ]: 21468 : if (mp_get_buffer(args[0], &bufinfo, MP_BUFFER_READ)) {
139 : : // a textual representation, parse it
140 : 21436 : return mp_parse_num_float(bufinfo.buf, bufinfo.len, false, NULL);
141 [ + + + + ]: 32 : } else if (mp_obj_is_float(args[0])) {
142 : : // a float, just return it
143 : : return args[0];
144 : : } else {
145 : : // something else, try to cast it to a float
146 : 28 : return mp_obj_new_float(mp_obj_get_float(args[0]));
147 : : }
148 : : }
149 : : }
150 : : }
151 : :
152 : 195953 : static mp_obj_t float_unary_op(mp_unary_op_t op, mp_obj_t o_in) {
153 : 195953 : mp_float_t val = mp_obj_float_get(o_in);
154 [ + + + + : 195953 : switch (op) {
+ + ]
155 : 10 : case MP_UNARY_OP_BOOL:
156 [ + + ]: 10 : return mp_obj_new_bool(val != 0);
157 : 274 : case MP_UNARY_OP_HASH:
158 : 274 : return MP_OBJ_NEW_SMALL_INT(mp_float_hash(val));
159 : : case MP_UNARY_OP_POSITIVE:
160 : : return o_in;
161 : 2758 : case MP_UNARY_OP_NEGATIVE:
162 : 2758 : return mp_obj_new_float(-val);
163 : 28400 : case MP_UNARY_OP_ABS: {
164 [ + + ]: 28400 : if (signbit(val)) {
165 : 5014 : return mp_obj_new_float(-val);
166 : : } else {
167 : : return o_in;
168 : : }
169 : : }
170 : 164507 : default:
171 : 164507 : return MP_OBJ_NULL; // op not supported
172 : : }
173 : : }
174 : :
175 : 585851 : static mp_obj_t float_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
176 : 585851 : mp_float_t lhs_val = mp_obj_float_get(lhs_in);
177 : : #if MICROPY_PY_BUILTINS_COMPLEX
178 [ - + - + : 585851 : if (mp_obj_is_type(rhs_in, &mp_type_complex)) {
- + - + +
+ + + ]
179 : 24 : return mp_obj_complex_binary_op(op, lhs_val, 0, rhs_in);
180 : : }
181 : : #endif
182 : 585827 : return mp_obj_float_binary_op(op, lhs_val, rhs_in);
183 : : }
184 : :
185 : : MP_DEFINE_CONST_OBJ_TYPE(
186 : : mp_type_float, MP_QSTR_float, MP_TYPE_FLAG_EQ_NOT_REFLEXIVE | MP_TYPE_FLAG_EQ_CHECKS_OTHER_TYPE,
187 : : make_new, float_make_new,
188 : : print, float_print,
189 : : unary_op, float_unary_op,
190 : : binary_op, float_binary_op
191 : : );
192 : :
193 : : #if MICROPY_OBJ_REPR != MICROPY_OBJ_REPR_C && MICROPY_OBJ_REPR != MICROPY_OBJ_REPR_D
194 : :
195 : 383735 : mp_obj_t mp_obj_new_float(mp_float_t value) {
196 : : // Don't use mp_obj_malloc here to avoid extra function call overhead.
197 : 383735 : mp_obj_float_t *o = m_new_obj(mp_obj_float_t);
198 : 383731 : o->base.type = &mp_type_float;
199 : 383731 : o->value = value;
200 : 383731 : return MP_OBJ_FROM_PTR(o);
201 : : }
202 : :
203 : 1202702 : mp_float_t mp_obj_float_get(mp_obj_t self_in) {
204 [ + - - + ]: 1202702 : assert(mp_obj_is_float(self_in));
205 : 1202702 : mp_obj_float_t *self = MP_OBJ_TO_PTR(self_in);
206 : 1202702 : return self->value;
207 : : }
208 : :
209 : : #endif
210 : :
211 : 12668 : static void mp_obj_float_divmod(mp_float_t *x, mp_float_t *y) {
212 : : // logic here follows that of CPython
213 : : // https://docs.python.org/3/reference/expressions.html#binary-arithmetic-operations
214 : : // x == (x//y)*y + (x%y)
215 : : // divmod(x, y) == (x//y, x%y)
216 : 12668 : mp_float_t mod = MICROPY_FLOAT_C_FUN(fmod)(*x, *y);
217 : 12668 : mp_float_t div = (*x - mod) / *y;
218 : :
219 : : // Python specs require that mod has same sign as second operand
220 [ + + ]: 12668 : if (mod == MICROPY_FLOAT_ZERO) {
221 : 1224 : mod = MICROPY_FLOAT_C_FUN(copysign)(MICROPY_FLOAT_ZERO, *y);
222 : : } else {
223 [ + + ]: 11444 : if ((mod < MICROPY_FLOAT_ZERO) != (*y < MICROPY_FLOAT_ZERO)) {
224 : 5720 : mod += *y;
225 : 5720 : div -= MICROPY_FLOAT_CONST(1.0);
226 : : }
227 : : }
228 : :
229 : 12668 : mp_float_t floordiv;
230 [ + + ]: 12668 : if (div == MICROPY_FLOAT_ZERO) {
231 : : // if division is zero, take the correct sign of zero
232 : 2884 : floordiv = MICROPY_FLOAT_C_FUN(copysign)(MICROPY_FLOAT_ZERO, *x / *y);
233 : : } else {
234 : : // Python specs require that x == (x//y)*y + (x%y)
235 : 9784 : floordiv = MICROPY_FLOAT_C_FUN(floor)(div);
236 [ + + ]: 9784 : if (div - floordiv > MICROPY_FLOAT_CONST(0.5)) {
237 : 60 : floordiv += MICROPY_FLOAT_CONST(1.0);
238 : : }
239 : : }
240 : :
241 : : // return results
242 : 12668 : *x = floordiv;
243 : 12668 : *y = mod;
244 : 12668 : }
245 : :
246 : 592623 : mp_obj_t mp_obj_float_binary_op(mp_binary_op_t op, mp_float_t lhs_val, mp_obj_t rhs_in) {
247 : 592623 : mp_float_t rhs_val;
248 [ + + ]: 592623 : if (!mp_obj_get_float_maybe(rhs_in, &rhs_val)) {
249 : : return MP_OBJ_NULL; // op not supported
250 : : }
251 : :
252 [ + + + + : 592599 : switch (op) {
+ + + + +
+ + + +
+ ]
253 : 34928 : case MP_BINARY_OP_ADD:
254 : : case MP_BINARY_OP_INPLACE_ADD:
255 : 34928 : lhs_val += rhs_val;
256 : 34928 : break;
257 : 32088 : case MP_BINARY_OP_SUBTRACT:
258 : : case MP_BINARY_OP_INPLACE_SUBTRACT:
259 : 32088 : lhs_val -= rhs_val;
260 : 32088 : break;
261 : 209261 : case MP_BINARY_OP_MULTIPLY:
262 : : case MP_BINARY_OP_INPLACE_MULTIPLY:
263 : 209261 : lhs_val *= rhs_val;
264 : 209261 : break;
265 : 7608 : case MP_BINARY_OP_FLOOR_DIVIDE:
266 : : case MP_BINARY_OP_INPLACE_FLOOR_DIVIDE:
267 [ + + ]: 7608 : if (rhs_val == 0) {
268 : 4 : zero_division_error:
269 : 44 : mp_raise_msg(&mp_type_ZeroDivisionError, MP_ERROR_TEXT("divide by zero"));
270 : : }
271 : : // Python specs require that x == (x//y)*y + (x%y) so we must
272 : : // call divmod to compute the correct floor division, which
273 : : // returns the floor divide in lhs_val.
274 : 7604 : mp_obj_float_divmod(&lhs_val, &rhs_val);
275 : 7604 : break;
276 : 25190 : case MP_BINARY_OP_TRUE_DIVIDE:
277 : : case MP_BINARY_OP_INPLACE_TRUE_DIVIDE:
278 [ + + ]: 25190 : if (rhs_val == 0) {
279 : 16 : goto zero_division_error;
280 : : }
281 : 25174 : lhs_val /= rhs_val;
282 : 25174 : break;
283 : 7608 : case MP_BINARY_OP_MODULO:
284 : : case MP_BINARY_OP_INPLACE_MODULO:
285 [ + + ]: 7608 : if (rhs_val == MICROPY_FLOAT_ZERO) {
286 : 4 : goto zero_division_error;
287 : : }
288 : 7604 : lhs_val = MICROPY_FLOAT_C_FUN(fmod)(lhs_val, rhs_val);
289 : : // Python specs require that mod has same sign as second operand
290 [ + + ]: 7604 : if (lhs_val == MICROPY_FLOAT_ZERO) {
291 : 732 : lhs_val = MICROPY_FLOAT_C_FUN(copysign)(0.0, rhs_val);
292 : : } else {
293 [ + + ]: 6872 : if ((lhs_val < MICROPY_FLOAT_ZERO) != (rhs_val < MICROPY_FLOAT_ZERO)) {
294 : 3432 : lhs_val += rhs_val;
295 : : }
296 : : }
297 : : break;
298 : 19480 : case MP_BINARY_OP_POWER:
299 : : case MP_BINARY_OP_INPLACE_POWER:
300 [ + + + + : 19480 : if (lhs_val == 0 && rhs_val < 0 && !isinf(rhs_val)) {
+ + ]
301 : 16 : goto zero_division_error;
302 : : }
303 [ + + + + : 19464 : if (lhs_val < 0 && rhs_val != MICROPY_FLOAT_C_FUN(floor)(rhs_val) && !isnan(rhs_val)) {
+ + ]
304 : : #if MICROPY_PY_BUILTINS_COMPLEX
305 : 8 : return mp_obj_complex_binary_op(MP_BINARY_OP_POWER, lhs_val, 0, rhs_in);
306 : : #else
307 : : mp_raise_ValueError(MP_ERROR_TEXT("complex values not supported"));
308 : : #endif
309 : : }
310 : : #if MICROPY_PY_MATH_POW_FIX_NAN // Also see modmath.c.
311 : : if (lhs_val == MICROPY_FLOAT_CONST(1.0) || rhs_val == MICROPY_FLOAT_CONST(0.0)) {
312 : : lhs_val = MICROPY_FLOAT_CONST(1.0);
313 : : break;
314 : : }
315 : : #endif
316 : 19456 : lhs_val = MICROPY_FLOAT_C_FUN(pow)(lhs_val, rhs_val);
317 : 19456 : break;
318 : 5068 : case MP_BINARY_OP_DIVMOD: {
319 [ + + ]: 5068 : if (rhs_val == 0) {
320 : 4 : goto zero_division_error;
321 : : }
322 : 5064 : mp_obj_float_divmod(&lhs_val, &rhs_val);
323 : 15192 : mp_obj_t tuple[2] = {
324 : 5064 : mp_obj_new_float(lhs_val),
325 : 5064 : mp_obj_new_float(rhs_val),
326 : : };
327 : 5064 : return mp_obj_new_tuple(2, tuple);
328 : : }
329 : 6544 : case MP_BINARY_OP_LESS:
330 [ + + ]: 6544 : return mp_obj_new_bool(lhs_val < rhs_val);
331 : 190687 : case MP_BINARY_OP_MORE:
332 [ + + ]: 190687 : return mp_obj_new_bool(lhs_val > rhs_val);
333 : 53073 : case MP_BINARY_OP_EQUAL:
334 [ + + ]: 53073 : return mp_obj_new_bool(lhs_val == rhs_val);
335 : 888 : case MP_BINARY_OP_LESS_EQUAL:
336 [ + + ]: 888 : return mp_obj_new_bool(lhs_val <= rhs_val);
337 : 168 : case MP_BINARY_OP_MORE_EQUAL:
338 [ + + ]: 168 : return mp_obj_new_bool(lhs_val >= rhs_val);
339 : :
340 : : default:
341 : : return MP_OBJ_NULL; // op not supported
342 : : }
343 : 336115 : return mp_obj_new_float(lhs_val);
344 : : }
345 : :
346 : : #endif // MICROPY_PY_BUILTINS_FLOAT
|