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