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
50typedef struct _mp_obj_float_t {
51 mp_obj_base_t base;
52 mp_float_t value;
53} mp_obj_float_t;
54
55const mp_obj_float_t mp_const_float_e_obj = {{&mp_type_float}, (mp_float_t)M_E};
56const 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
64mp_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
97STATIC 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
119STATIC 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
144STATIC 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
167STATIC 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
177const 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
189mp_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
196mp_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
204STATIC 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
239mp_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