modmath.c 15 KB

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