LCOV - code coverage report
Current view: top level - py - modmath.c (source / functions) Hit Total Coverage
Test: unix_coverage_v1.19.1-724-gfb7d21153.info Lines: 124 124 100.0 %
Date: 2022-12-01 09:37:31 Functions: 46 46 100.0 %
Branches: 54 54 100.0 %

           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-2017 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 "py/builtin.h"
      28                 :            : #include "py/runtime.h"
      29                 :            : 
      30                 :            : #if MICROPY_PY_BUILTINS_FLOAT && MICROPY_PY_MATH
      31                 :            : 
      32                 :            : #include <math.h>
      33                 :            : 
      34                 :            : // M_PI is not part of the math.h standard and may not be defined
      35                 :            : // And by defining our own we can ensure it uses the correct const format.
      36                 :            : #define MP_PI MICROPY_FLOAT_CONST(3.14159265358979323846)
      37                 :            : #define MP_PI_4 MICROPY_FLOAT_CONST(0.78539816339744830962)
      38                 :            : #define MP_3_PI_4 MICROPY_FLOAT_CONST(2.35619449019234492885)
      39                 :            : 
      40                 :        244 : STATIC NORETURN void math_error(void) {
      41                 :        244 :     mp_raise_ValueError(MP_ERROR_TEXT("math domain error"));
      42                 :            : }
      43                 :            : 
      44                 :       1028 : STATIC mp_obj_t math_generic_1(mp_obj_t x_obj, mp_float_t (*f)(mp_float_t)) {
      45                 :       1028 :     mp_float_t x = mp_obj_get_float(x_obj);
      46                 :       1028 :     mp_float_t ans = f(x);
      47   [ +  +  +  +  :       1028 :     if ((isnan(ans) && !isnan(x)) || (isinf(ans) && !isinf(x))) {
                   +  + ]
      48                 :        176 :         math_error();
      49                 :            :     }
      50                 :        852 :     return mp_obj_new_float(ans);
      51                 :            : }
      52                 :            : 
      53                 :        236 : STATIC mp_obj_t math_generic_2(mp_obj_t x_obj, mp_obj_t y_obj, mp_float_t (*f)(mp_float_t, mp_float_t)) {
      54                 :        236 :     mp_float_t x = mp_obj_get_float(x_obj);
      55                 :        236 :     mp_float_t y = mp_obj_get_float(y_obj);
      56                 :        236 :     mp_float_t ans = f(x, y);
      57   [ +  +  +  +  :        236 :     if ((isnan(ans) && !isnan(x) && !isnan(y)) || (isinf(ans) && !isinf(x))) {
             +  +  +  + ]
      58                 :         24 :         math_error();
      59                 :            :     }
      60                 :        212 :     return mp_obj_new_float(ans);
      61                 :            : }
      62                 :            : 
      63                 :            : #define MATH_FUN_1(py_name, c_name) \
      64                 :            :     STATIC mp_obj_t mp_math_##py_name(mp_obj_t x_obj) { \
      65                 :            :         return math_generic_1(x_obj, MICROPY_FLOAT_C_FUN(c_name)); \
      66                 :            :     } \
      67                 :            :     STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_##py_name##_obj, mp_math_##py_name);
      68                 :            : 
      69                 :            : #define MATH_FUN_1_TO_BOOL(py_name, c_name) \
      70                 :            :     STATIC mp_obj_t mp_math_##py_name(mp_obj_t x_obj) { return mp_obj_new_bool(c_name(mp_obj_get_float(x_obj))); } \
      71                 :            :     STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_##py_name##_obj, mp_math_##py_name);
      72                 :            : 
      73                 :            : #define MATH_FUN_1_TO_INT(py_name, c_name) \
      74                 :            :     STATIC mp_obj_t mp_math_##py_name(mp_obj_t x_obj) { return mp_obj_new_int_from_float(MICROPY_FLOAT_C_FUN(c_name)(mp_obj_get_float(x_obj))); } \
      75                 :            :     STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_##py_name##_obj, mp_math_##py_name);
      76                 :            : 
      77                 :            : #define MATH_FUN_2(py_name, c_name) \
      78                 :            :     STATIC mp_obj_t mp_math_##py_name(mp_obj_t x_obj, mp_obj_t y_obj) { \
      79                 :            :         return math_generic_2(x_obj, y_obj, MICROPY_FLOAT_C_FUN(c_name)); \
      80                 :            :     } \
      81                 :            :     STATIC MP_DEFINE_CONST_FUN_OBJ_2(mp_math_##py_name##_obj, mp_math_##py_name);
      82                 :            : 
      83                 :            : #define MATH_FUN_2_FLT_INT(py_name, c_name) \
      84                 :            :     STATIC mp_obj_t mp_math_##py_name(mp_obj_t x_obj, mp_obj_t y_obj) { \
      85                 :            :         return mp_obj_new_float(MICROPY_FLOAT_C_FUN(c_name)(mp_obj_get_float(x_obj), mp_obj_get_int(y_obj))); \
      86                 :            :     } \
      87                 :            :     STATIC MP_DEFINE_CONST_FUN_OBJ_2(mp_math_##py_name##_obj, mp_math_##py_name);
      88                 :            : 
      89                 :            : #if MP_NEED_LOG2
      90                 :            : #undef log2
      91                 :            : #undef log2f
      92                 :            : // 1.442695040888963407354163704 is 1/_M_LN2
      93                 :            : mp_float_t MICROPY_FLOAT_C_FUN(log2)(mp_float_t x) {
      94                 :            :     return MICROPY_FLOAT_C_FUN(log)(x) * MICROPY_FLOAT_CONST(1.442695040888963407354163704);
      95                 :            : }
      96                 :            : #endif
      97                 :            : 
      98                 :            : // sqrt(x): returns the square root of x
      99                 :         48 : MATH_FUN_1(sqrt, sqrt)
     100                 :            : // pow(x, y): returns x to the power of y
     101                 :            : #if MICROPY_PY_MATH_POW_FIX_NAN
     102                 :            : mp_float_t pow_func(mp_float_t x, mp_float_t y) {
     103                 :            :     // pow(base, 0) returns 1 for any base, even when base is NaN
     104                 :            :     // pow(+1, exponent) returns 1 for any exponent, even when exponent is NaN
     105                 :            :     if (x == MICROPY_FLOAT_CONST(1.0) || y == MICROPY_FLOAT_CONST(0.0)) {
     106                 :            :         return MICROPY_FLOAT_CONST(1.0);
     107                 :            :     }
     108                 :            :     return MICROPY_FLOAT_C_FUN(pow)(x, y);
     109                 :            : }
     110                 :            : MATH_FUN_2(pow, pow_func)
     111                 :            : #else
     112                 :         68 : MATH_FUN_2(pow, pow)
     113                 :            : #endif
     114                 :            : // exp(x)
     115                 :         60 : MATH_FUN_1(exp, exp)
     116                 :            : #if MICROPY_PY_MATH_SPECIAL_FUNCTIONS
     117                 :            : // expm1(x)
     118                 :         32 : MATH_FUN_1(expm1, expm1)
     119                 :            : // log2(x)
     120                 :         52 : MATH_FUN_1(log2, log2)
     121                 :            : // log10(x)
     122                 :         52 : MATH_FUN_1(log10, log10)
     123                 :            : // cosh(x)
     124                 :         44 : MATH_FUN_1(cosh, cosh)
     125                 :            : // sinh(x)
     126                 :         44 : MATH_FUN_1(sinh, sinh)
     127                 :            : // tanh(x)
     128                 :         60 : MATH_FUN_1(tanh, tanh)
     129                 :            : // acosh(x)
     130                 :         36 : MATH_FUN_1(acosh, acosh)
     131                 :            : // asinh(x)
     132                 :         44 : MATH_FUN_1(asinh, asinh)
     133                 :            : // atanh(x)
     134                 :         40 : MATH_FUN_1(atanh, atanh)
     135                 :            : #endif
     136                 :            : // cos(x)
     137                 :         44 : MATH_FUN_1(cos, cos)
     138                 :            : // sin(x)
     139                 :         40 : MATH_FUN_1(sin, sin)
     140                 :            : // tan(x)
     141                 :         40 : MATH_FUN_1(tan, tan)
     142                 :            : // acos(x)
     143                 :         56 : MATH_FUN_1(acos, acos)
     144                 :            : // asin(x)
     145                 :         56 : MATH_FUN_1(asin, asin)
     146                 :            : // atan(x)
     147                 :         40 : MATH_FUN_1(atan, atan)
     148                 :            : // atan2(y, x)
     149                 :            : #if MICROPY_PY_MATH_ATAN2_FIX_INFNAN
     150                 :            : mp_float_t atan2_func(mp_float_t x, mp_float_t y) {
     151                 :            :     if (isinf(x) && isinf(y)) {
     152                 :            :         return copysign(y < 0 ? MP_3_PI_4 : MP_PI_4, x);
     153                 :            :     }
     154                 :            :     return atan2(x, y);
     155                 :            : }
     156                 :            : MATH_FUN_2(atan2, atan2_func)
     157                 :            : #else
     158                 :         60 : MATH_FUN_2(atan2, atan2)
     159                 :            : #endif
     160                 :            : // ceil(x)
     161                 :         76 : MATH_FUN_1_TO_INT(ceil, ceil)
     162                 :            : // copysign(x, y)
     163                 :         48 : STATIC mp_float_t MICROPY_FLOAT_C_FUN(copysign_func)(mp_float_t x, mp_float_t y) {
     164                 :         48 :     return MICROPY_FLOAT_C_FUN(copysign)(x, y);
     165                 :            : }
     166                 :         48 : MATH_FUN_2(copysign, copysign_func)
     167                 :            : // fabs(x)
     168                 :         40 : STATIC mp_float_t MICROPY_FLOAT_C_FUN(fabs_func)(mp_float_t x) {
     169                 :         40 :     return MICROPY_FLOAT_C_FUN(fabs)(x);
     170                 :            : }
     171                 :         40 : MATH_FUN_1(fabs, fabs_func)
     172                 :            : // floor(x)
     173                 :         76 : MATH_FUN_1_TO_INT(floor, floor) // TODO: delegate to x.__floor__() if x is not a float
     174                 :            : // fmod(x, y)
     175                 :            : #if MICROPY_PY_MATH_FMOD_FIX_INFNAN
     176                 :            : mp_float_t fmod_func(mp_float_t x, mp_float_t y) {
     177                 :            :     return (!isinf(x) && isinf(y)) ? x : fmod(x, y);
     178                 :            : }
     179                 :            : MATH_FUN_2(fmod, fmod_func)
     180                 :            : #else
     181                 :         60 : MATH_FUN_2(fmod, fmod)
     182                 :            : #endif
     183                 :            : // isfinite(x)
     184         [ +  + ]:         40 : MATH_FUN_1_TO_BOOL(isfinite, isfinite)
     185                 :            : // isinf(x)
     186         [ +  + ]:         40 : MATH_FUN_1_TO_BOOL(isinf, isinf)
     187                 :            : // isnan(x)
     188         [ +  + ]:         48 : MATH_FUN_1_TO_BOOL(isnan, isnan)
     189                 :            : // trunc(x)
     190                 :         76 : MATH_FUN_1_TO_INT(trunc, trunc)
     191                 :            : // ldexp(x, exp)
     192                 :         28 : MATH_FUN_2_FLT_INT(ldexp, ldexp)
     193                 :            : #if MICROPY_PY_MATH_SPECIAL_FUNCTIONS
     194                 :            : // erf(x): return the error function of x
     195                 :         44 : MATH_FUN_1(erf, erf)
     196                 :            : // erfc(x): return the complementary error function of x
     197                 :         44 : MATH_FUN_1(erfc, erfc)
     198                 :            : // gamma(x): return the gamma function of x
     199                 :         52 : MATH_FUN_1(gamma, tgamma)
     200                 :            : // lgamma(x): return the natural logarithm of the gamma function of x
     201                 :         60 : MATH_FUN_1(lgamma, lgamma)
     202                 :            : #endif
     203                 :            : // TODO: fsum
     204                 :            : 
     205                 :            : #if MICROPY_PY_MATH_ISCLOSE
     206                 :        108 : STATIC mp_obj_t mp_math_isclose(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
     207                 :        108 :     enum { ARG_rel_tol, ARG_abs_tol };
     208                 :        108 :     static const mp_arg_t allowed_args[] = {
     209                 :            :         {MP_QSTR_rel_tol, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}},
     210                 :            :         {MP_QSTR_abs_tol, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NEW_SMALL_INT(0)}},
     211                 :            :     };
     212                 :        108 :     mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
     213                 :        108 :     mp_arg_parse_all(n_args - 2, pos_args + 2, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
     214                 :        108 :     const mp_float_t a = mp_obj_get_float(pos_args[0]);
     215                 :        108 :     const mp_float_t b = mp_obj_get_float(pos_args[1]);
     216                 :        216 :     const mp_float_t rel_tol = args[ARG_rel_tol].u_obj == MP_OBJ_NULL
     217         [ +  + ]:        108 :         ? (mp_float_t)1e-9 : mp_obj_get_float(args[ARG_rel_tol].u_obj);
     218                 :        108 :     const mp_float_t abs_tol = mp_obj_get_float(args[ARG_abs_tol].u_obj);
     219   [ +  +  +  + ]:        108 :     if (rel_tol < (mp_float_t)0.0 || abs_tol < (mp_float_t)0.0) {
     220                 :          8 :         math_error();
     221                 :            :     }
     222         [ +  + ]:        100 :     if (a == b) {
     223                 :            :         return mp_const_true;
     224                 :            :     }
     225                 :         60 :     const mp_float_t difference = MICROPY_FLOAT_C_FUN(fabs)(a - b);
     226         [ +  + ]:         60 :     if (isinf(difference)) { // Either a or b is inf
     227                 :            :         return mp_const_false;
     228                 :            :     }
     229         [ +  + ]:         44 :     if ((difference <= abs_tol) ||
     230         [ +  + ]:         40 :         (difference <= MICROPY_FLOAT_C_FUN(fabs)(rel_tol * a)) ||
     231         [ +  + ]:         28 :         (difference <= MICROPY_FLOAT_C_FUN(fabs)(rel_tol * b))) {
     232                 :         20 :         return mp_const_true;
     233                 :            :     }
     234                 :            :     return mp_const_false;
     235                 :            : }
     236                 :            : MP_DEFINE_CONST_FUN_OBJ_KW(mp_math_isclose_obj, 2, mp_math_isclose);
     237                 :            : #endif
     238                 :            : 
     239                 :            : // Function that takes a variable number of arguments
     240                 :            : 
     241                 :            : // log(x[, base])
     242                 :         66 : STATIC mp_obj_t mp_math_log(size_t n_args, const mp_obj_t *args) {
     243                 :         66 :     mp_float_t x = mp_obj_get_float(args[0]);
     244         [ +  + ]:         66 :     if (x <= (mp_float_t)0.0) {
     245                 :         28 :         math_error();
     246                 :            :     }
     247                 :         38 :     mp_float_t l = MICROPY_FLOAT_C_FUN(log)(x);
     248         [ +  + ]:         38 :     if (n_args == 1) {
     249                 :         14 :         return mp_obj_new_float(l);
     250                 :            :     } else {
     251                 :         24 :         mp_float_t base = mp_obj_get_float(args[1]);
     252         [ +  + ]:         24 :         if (base <= (mp_float_t)0.0) {
     253                 :          8 :             math_error();
     254         [ +  + ]:         16 :         } else if (base == (mp_float_t)1.0) {
     255                 :          4 :             mp_raise_msg(&mp_type_ZeroDivisionError, MP_ERROR_TEXT("divide by zero"));
     256                 :            :         }
     257                 :         12 :         return mp_obj_new_float(l / MICROPY_FLOAT_C_FUN(log)(base));
     258                 :            :     }
     259                 :            : }
     260                 :            : STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_math_log_obj, 1, 2, mp_math_log);
     261                 :            : 
     262                 :            : // Functions that return a tuple
     263                 :            : 
     264                 :            : // frexp(x): converts a floating-point number to fractional and integral components
     265                 :         32 : STATIC mp_obj_t mp_math_frexp(mp_obj_t x_obj) {
     266                 :         32 :     int int_exponent = 0;
     267                 :         32 :     mp_float_t significand = MICROPY_FLOAT_C_FUN(frexp)(mp_obj_get_float(x_obj), &int_exponent);
     268                 :         32 :     mp_obj_t tuple[2];
     269                 :         32 :     tuple[0] = mp_obj_new_float(significand);
     270                 :         32 :     tuple[1] = mp_obj_new_int(int_exponent);
     271                 :         32 :     return mp_obj_new_tuple(2, tuple);
     272                 :            : }
     273                 :            : STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_frexp_obj, mp_math_frexp);
     274                 :            : 
     275                 :            : // modf(x)
     276                 :         32 : STATIC mp_obj_t mp_math_modf(mp_obj_t x_obj) {
     277                 :         32 :     mp_float_t int_part = 0.0;
     278                 :         32 :     mp_float_t x = mp_obj_get_float(x_obj);
     279                 :         32 :     mp_float_t fractional_part = MICROPY_FLOAT_C_FUN(modf)(x, &int_part);
     280                 :            :     #if MICROPY_PY_MATH_MODF_FIX_NEGZERO
     281                 :            :     if (fractional_part == MICROPY_FLOAT_CONST(0.0)) {
     282                 :            :         fractional_part = copysign(fractional_part, x);
     283                 :            :     }
     284                 :            :     #endif
     285                 :         32 :     mp_obj_t tuple[2];
     286                 :         32 :     tuple[0] = mp_obj_new_float(fractional_part);
     287                 :         32 :     tuple[1] = mp_obj_new_float(int_part);
     288                 :         32 :     return mp_obj_new_tuple(2, tuple);
     289                 :            : }
     290                 :            : STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_modf_obj, mp_math_modf);
     291                 :            : 
     292                 :            : // Angular conversions
     293                 :            : 
     294                 :            : // radians(x)
     295                 :         40 : STATIC mp_obj_t mp_math_radians(mp_obj_t x_obj) {
     296                 :         40 :     return mp_obj_new_float(mp_obj_get_float(x_obj) * (MP_PI / MICROPY_FLOAT_CONST(180.0)));
     297                 :            : }
     298                 :            : STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_radians_obj, mp_math_radians);
     299                 :            : 
     300                 :            : // degrees(x)
     301                 :         40 : STATIC mp_obj_t mp_math_degrees(mp_obj_t x_obj) {
     302                 :         40 :     return mp_obj_new_float(mp_obj_get_float(x_obj) * (MICROPY_FLOAT_CONST(180.0) / MP_PI));
     303                 :            : }
     304                 :            : STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_degrees_obj, mp_math_degrees);
     305                 :            : 
     306                 :            : #if MICROPY_PY_MATH_FACTORIAL
     307                 :            : 
     308                 :            : #if MICROPY_OPT_MATH_FACTORIAL
     309                 :            : 
     310                 :            : // factorial(x): slightly efficient recursive implementation
     311                 :       1300 : STATIC mp_obj_t mp_math_factorial_inner(mp_uint_t start, mp_uint_t end) {
     312         [ +  + ]:       1300 :     if (start == end) {
     313                 :          4 :         return mp_obj_new_int(start);
     314         [ +  + ]:       1296 :     } else if (end - start == 1) {
     315                 :        376 :         return mp_binary_op(MP_BINARY_OP_MULTIPLY, MP_OBJ_NEW_SMALL_INT(start), MP_OBJ_NEW_SMALL_INT(end));
     316         [ +  + ]:        920 :     } else if (end - start == 2) {
     317                 :        328 :         mp_obj_t left = MP_OBJ_NEW_SMALL_INT(start);
     318                 :        328 :         mp_obj_t middle = MP_OBJ_NEW_SMALL_INT(start + 1);
     319                 :        328 :         mp_obj_t right = MP_OBJ_NEW_SMALL_INT(end);
     320                 :        328 :         mp_obj_t tmp = mp_binary_op(MP_BINARY_OP_MULTIPLY, left, middle);
     321                 :        328 :         return mp_binary_op(MP_BINARY_OP_MULTIPLY, tmp, right);
     322                 :            :     } else {
     323                 :        592 :         mp_uint_t middle = start + ((end - start) >> 1);
     324                 :        592 :         mp_obj_t left = mp_math_factorial_inner(start, middle);
     325                 :        592 :         mp_obj_t right = mp_math_factorial_inner(middle + 1, end);
     326                 :        592 :         return mp_binary_op(MP_BINARY_OP_MULTIPLY, left, right);
     327                 :            :     }
     328                 :            : }
     329                 :        124 : STATIC mp_obj_t mp_math_factorial(mp_obj_t x_obj) {
     330                 :        124 :     mp_int_t max = mp_obj_get_int(x_obj);
     331         [ +  + ]:        124 :     if (max < 0) {
     332                 :          4 :         mp_raise_ValueError(MP_ERROR_TEXT("negative factorial"));
     333         [ +  + ]:        120 :     } else if (max == 0) {
     334                 :            :         return MP_OBJ_NEW_SMALL_INT(1);
     335                 :            :     }
     336                 :        116 :     return mp_math_factorial_inner(1, max);
     337                 :            : }
     338                 :            : 
     339                 :            : #else
     340                 :            : 
     341                 :            : // factorial(x): squared difference implementation
     342                 :            : // based on http://www.luschny.de/math/factorial/index.html
     343                 :            : STATIC mp_obj_t mp_math_factorial(mp_obj_t x_obj) {
     344                 :            :     mp_int_t max = mp_obj_get_int(x_obj);
     345                 :            :     if (max < 0) {
     346                 :            :         mp_raise_ValueError(MP_ERROR_TEXT("negative factorial"));
     347                 :            :     } else if (max <= 1) {
     348                 :            :         return MP_OBJ_NEW_SMALL_INT(1);
     349                 :            :     }
     350                 :            :     mp_int_t h = max >> 1;
     351                 :            :     mp_int_t q = h * h;
     352                 :            :     mp_int_t r = q << 1;
     353                 :            :     if (max & 1) {
     354                 :            :         r *= max;
     355                 :            :     }
     356                 :            :     mp_obj_t prod = MP_OBJ_NEW_SMALL_INT(r);
     357                 :            :     for (mp_int_t num = 1; num < max - 2; num += 2) {
     358                 :            :         q -= num;
     359                 :            :         prod = mp_binary_op(MP_BINARY_OP_MULTIPLY, prod, MP_OBJ_NEW_SMALL_INT(q));
     360                 :            :     }
     361                 :            :     return prod;
     362                 :            : }
     363                 :            : 
     364                 :            : #endif
     365                 :            : 
     366                 :            : STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_factorial_obj, mp_math_factorial);
     367                 :            : 
     368                 :            : #endif
     369                 :            : 
     370                 :            : STATIC const mp_rom_map_elem_t mp_module_math_globals_table[] = {
     371                 :            :     { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_math) },
     372                 :            :     { MP_ROM_QSTR(MP_QSTR_e), mp_const_float_e },
     373                 :            :     { MP_ROM_QSTR(MP_QSTR_pi), mp_const_float_pi },
     374                 :            :     #if MICROPY_PY_MATH_CONSTANTS
     375                 :            :     { MP_ROM_QSTR(MP_QSTR_tau), mp_const_float_tau },
     376                 :            :     { MP_ROM_QSTR(MP_QSTR_inf), mp_const_float_inf },
     377                 :            :     { MP_ROM_QSTR(MP_QSTR_nan), mp_const_float_nan },
     378                 :            :     #endif
     379                 :            :     { MP_ROM_QSTR(MP_QSTR_sqrt), MP_ROM_PTR(&mp_math_sqrt_obj) },
     380                 :            :     { MP_ROM_QSTR(MP_QSTR_pow), MP_ROM_PTR(&mp_math_pow_obj) },
     381                 :            :     { MP_ROM_QSTR(MP_QSTR_exp), MP_ROM_PTR(&mp_math_exp_obj) },
     382                 :            :     #if MICROPY_PY_MATH_SPECIAL_FUNCTIONS
     383                 :            :     { MP_ROM_QSTR(MP_QSTR_expm1), MP_ROM_PTR(&mp_math_expm1_obj) },
     384                 :            :     #endif
     385                 :            :     { MP_ROM_QSTR(MP_QSTR_log), MP_ROM_PTR(&mp_math_log_obj) },
     386                 :            :     #if MICROPY_PY_MATH_SPECIAL_FUNCTIONS
     387                 :            :     { MP_ROM_QSTR(MP_QSTR_log2), MP_ROM_PTR(&mp_math_log2_obj) },
     388                 :            :     { MP_ROM_QSTR(MP_QSTR_log10), MP_ROM_PTR(&mp_math_log10_obj) },
     389                 :            :     { MP_ROM_QSTR(MP_QSTR_cosh), MP_ROM_PTR(&mp_math_cosh_obj) },
     390                 :            :     { MP_ROM_QSTR(MP_QSTR_sinh), MP_ROM_PTR(&mp_math_sinh_obj) },
     391                 :            :     { MP_ROM_QSTR(MP_QSTR_tanh), MP_ROM_PTR(&mp_math_tanh_obj) },
     392                 :            :     { MP_ROM_QSTR(MP_QSTR_acosh), MP_ROM_PTR(&mp_math_acosh_obj) },
     393                 :            :     { MP_ROM_QSTR(MP_QSTR_asinh), MP_ROM_PTR(&mp_math_asinh_obj) },
     394                 :            :     { MP_ROM_QSTR(MP_QSTR_atanh), MP_ROM_PTR(&mp_math_atanh_obj) },
     395                 :            :     #endif
     396                 :            :     { MP_ROM_QSTR(MP_QSTR_cos), MP_ROM_PTR(&mp_math_cos_obj) },
     397                 :            :     { MP_ROM_QSTR(MP_QSTR_sin), MP_ROM_PTR(&mp_math_sin_obj) },
     398                 :            :     { MP_ROM_QSTR(MP_QSTR_tan), MP_ROM_PTR(&mp_math_tan_obj) },
     399                 :            :     { MP_ROM_QSTR(MP_QSTR_acos), MP_ROM_PTR(&mp_math_acos_obj) },
     400                 :            :     { MP_ROM_QSTR(MP_QSTR_asin), MP_ROM_PTR(&mp_math_asin_obj) },
     401                 :            :     { MP_ROM_QSTR(MP_QSTR_atan), MP_ROM_PTR(&mp_math_atan_obj) },
     402                 :            :     { MP_ROM_QSTR(MP_QSTR_atan2), MP_ROM_PTR(&mp_math_atan2_obj) },
     403                 :            :     { MP_ROM_QSTR(MP_QSTR_ceil), MP_ROM_PTR(&mp_math_ceil_obj) },
     404                 :            :     { MP_ROM_QSTR(MP_QSTR_copysign), MP_ROM_PTR(&mp_math_copysign_obj) },
     405                 :            :     { MP_ROM_QSTR(MP_QSTR_fabs), MP_ROM_PTR(&mp_math_fabs_obj) },
     406                 :            :     { MP_ROM_QSTR(MP_QSTR_floor), MP_ROM_PTR(&mp_math_floor_obj) },
     407                 :            :     { MP_ROM_QSTR(MP_QSTR_fmod), MP_ROM_PTR(&mp_math_fmod_obj) },
     408                 :            :     { MP_ROM_QSTR(MP_QSTR_frexp), MP_ROM_PTR(&mp_math_frexp_obj) },
     409                 :            :     { MP_ROM_QSTR(MP_QSTR_ldexp), MP_ROM_PTR(&mp_math_ldexp_obj) },
     410                 :            :     { MP_ROM_QSTR(MP_QSTR_modf), MP_ROM_PTR(&mp_math_modf_obj) },
     411                 :            :     { MP_ROM_QSTR(MP_QSTR_isfinite), MP_ROM_PTR(&mp_math_isfinite_obj) },
     412                 :            :     { MP_ROM_QSTR(MP_QSTR_isinf), MP_ROM_PTR(&mp_math_isinf_obj) },
     413                 :            :     { MP_ROM_QSTR(MP_QSTR_isnan), MP_ROM_PTR(&mp_math_isnan_obj) },
     414                 :            :     #if MICROPY_PY_MATH_ISCLOSE
     415                 :            :     { MP_ROM_QSTR(MP_QSTR_isclose), MP_ROM_PTR(&mp_math_isclose_obj) },
     416                 :            :     #endif
     417                 :            :     { MP_ROM_QSTR(MP_QSTR_trunc), MP_ROM_PTR(&mp_math_trunc_obj) },
     418                 :            :     { MP_ROM_QSTR(MP_QSTR_radians), MP_ROM_PTR(&mp_math_radians_obj) },
     419                 :            :     { MP_ROM_QSTR(MP_QSTR_degrees), MP_ROM_PTR(&mp_math_degrees_obj) },
     420                 :            :     #if MICROPY_PY_MATH_FACTORIAL
     421                 :            :     { MP_ROM_QSTR(MP_QSTR_factorial), MP_ROM_PTR(&mp_math_factorial_obj) },
     422                 :            :     #endif
     423                 :            :     #if MICROPY_PY_MATH_SPECIAL_FUNCTIONS
     424                 :            :     { MP_ROM_QSTR(MP_QSTR_erf), MP_ROM_PTR(&mp_math_erf_obj) },
     425                 :            :     { MP_ROM_QSTR(MP_QSTR_erfc), MP_ROM_PTR(&mp_math_erfc_obj) },
     426                 :            :     { MP_ROM_QSTR(MP_QSTR_gamma), MP_ROM_PTR(&mp_math_gamma_obj) },
     427                 :            :     { MP_ROM_QSTR(MP_QSTR_lgamma), MP_ROM_PTR(&mp_math_lgamma_obj) },
     428                 :            :     #endif
     429                 :            : };
     430                 :            : 
     431                 :            : STATIC MP_DEFINE_CONST_DICT(mp_module_math_globals, mp_module_math_globals_table);
     432                 :            : 
     433                 :            : const mp_obj_module_t mp_module_math = {
     434                 :            :     .base = { &mp_type_module },
     435                 :            :     .globals = (mp_obj_dict_t *)&mp_module_math_globals,
     436                 :            : };
     437                 :            : 
     438                 :            : MP_REGISTER_MODULE(MP_QSTR_math, mp_module_math);
     439                 :            : 
     440                 :            : #endif // MICROPY_PY_BUILTINS_FLOAT && MICROPY_PY_MATH

Generated by: LCOV version 1.15-5-g462f71d