modmath.c 16 KB

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