modmath.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359
  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. // Function that takes a variable number of arguments
  160. // log(x[, base])
  161. STATIC mp_obj_t mp_math_log(size_t n_args, const mp_obj_t *args) {
  162. mp_float_t x = mp_obj_get_float(args[0]);
  163. if (x <= (mp_float_t)0.0) {
  164. math_error();
  165. }
  166. mp_float_t l = MICROPY_FLOAT_C_FUN(log)(x);
  167. if (n_args == 1) {
  168. return mp_obj_new_float(l);
  169. } else {
  170. mp_float_t base = mp_obj_get_float(args[1]);
  171. if (base <= (mp_float_t)0.0) {
  172. math_error();
  173. } else if (base == (mp_float_t)1.0) {
  174. mp_raise_msg(&mp_type_ZeroDivisionError, "divide by zero");
  175. }
  176. return mp_obj_new_float(l / MICROPY_FLOAT_C_FUN(log)(base));
  177. }
  178. }
  179. STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_math_log_obj, 1, 2, mp_math_log);
  180. // Functions that return a tuple
  181. // frexp(x): converts a floating-point number to fractional and integral components
  182. STATIC mp_obj_t mp_math_frexp(mp_obj_t x_obj) {
  183. int int_exponent = 0;
  184. mp_float_t significand = MICROPY_FLOAT_C_FUN(frexp)(mp_obj_get_float(x_obj), &int_exponent);
  185. mp_obj_t tuple[2];
  186. tuple[0] = mp_obj_new_float(significand);
  187. tuple[1] = mp_obj_new_int(int_exponent);
  188. return mp_obj_new_tuple(2, tuple);
  189. }
  190. STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_frexp_obj, mp_math_frexp);
  191. // modf(x)
  192. STATIC mp_obj_t mp_math_modf(mp_obj_t x_obj) {
  193. mp_float_t int_part = 0.0;
  194. mp_float_t fractional_part = MICROPY_FLOAT_C_FUN(modf)(mp_obj_get_float(x_obj), &int_part);
  195. mp_obj_t tuple[2];
  196. tuple[0] = mp_obj_new_float(fractional_part);
  197. tuple[1] = mp_obj_new_float(int_part);
  198. return mp_obj_new_tuple(2, tuple);
  199. }
  200. STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_modf_obj, mp_math_modf);
  201. // Angular conversions
  202. // radians(x)
  203. STATIC mp_obj_t mp_math_radians(mp_obj_t x_obj) {
  204. return mp_obj_new_float(mp_obj_get_float(x_obj) * (MP_PI / MICROPY_FLOAT_CONST(180.0)));
  205. }
  206. STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_radians_obj, mp_math_radians);
  207. // degrees(x)
  208. STATIC mp_obj_t mp_math_degrees(mp_obj_t x_obj) {
  209. return mp_obj_new_float(mp_obj_get_float(x_obj) * (MICROPY_FLOAT_CONST(180.0) / MP_PI));
  210. }
  211. STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_degrees_obj, mp_math_degrees);
  212. #if MICROPY_PY_MATH_FACTORIAL
  213. #if MICROPY_OPT_MATH_FACTORIAL
  214. // factorial(x): slightly efficient recursive implementation
  215. STATIC mp_obj_t mp_math_factorial_inner(mp_uint_t start, mp_uint_t end) {
  216. if (start == end) {
  217. return mp_obj_new_int(start);
  218. } else if (end - start == 1) {
  219. return mp_binary_op(MP_BINARY_OP_MULTIPLY, MP_OBJ_NEW_SMALL_INT(start), MP_OBJ_NEW_SMALL_INT(end));
  220. } else if (end - start == 2) {
  221. mp_obj_t left = MP_OBJ_NEW_SMALL_INT(start);
  222. mp_obj_t middle = MP_OBJ_NEW_SMALL_INT(start + 1);
  223. mp_obj_t right = MP_OBJ_NEW_SMALL_INT(end);
  224. mp_obj_t tmp = mp_binary_op(MP_BINARY_OP_MULTIPLY, left, middle);
  225. return mp_binary_op(MP_BINARY_OP_MULTIPLY, tmp, right);
  226. } else {
  227. mp_uint_t middle = start + ((end - start) >> 1);
  228. mp_obj_t left = mp_math_factorial_inner(start, middle);
  229. mp_obj_t right = mp_math_factorial_inner(middle + 1, end);
  230. return mp_binary_op(MP_BINARY_OP_MULTIPLY, left, right);
  231. }
  232. }
  233. STATIC mp_obj_t mp_math_factorial(mp_obj_t x_obj) {
  234. mp_int_t max = mp_obj_get_int(x_obj);
  235. if (max < 0) {
  236. mp_raise_msg(&mp_type_ValueError, "negative factorial");
  237. } else if (max == 0) {
  238. return MP_OBJ_NEW_SMALL_INT(1);
  239. }
  240. return mp_math_factorial_inner(1, max);
  241. }
  242. #else
  243. // factorial(x): squared difference implementation
  244. // based on http://www.luschny.de/math/factorial/index.html
  245. STATIC mp_obj_t mp_math_factorial(mp_obj_t x_obj) {
  246. mp_int_t max = mp_obj_get_int(x_obj);
  247. if (max < 0) {
  248. mp_raise_msg(&mp_type_ValueError, "negative factorial");
  249. } else if (max <= 1) {
  250. return MP_OBJ_NEW_SMALL_INT(1);
  251. }
  252. mp_int_t h = max >> 1;
  253. mp_int_t q = h * h;
  254. mp_int_t r = q << 1;
  255. if (max & 1) {
  256. r *= max;
  257. }
  258. mp_obj_t prod = MP_OBJ_NEW_SMALL_INT(r);
  259. for (mp_int_t num = 1; num < max - 2; num += 2) {
  260. q -= num;
  261. prod = mp_binary_op(MP_BINARY_OP_MULTIPLY, prod, MP_OBJ_NEW_SMALL_INT(q));
  262. }
  263. return prod;
  264. }
  265. #endif
  266. STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_math_factorial_obj, mp_math_factorial);
  267. #endif
  268. STATIC const mp_rom_map_elem_t mp_module_math_globals_table[] = {
  269. { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_math) },
  270. { MP_ROM_QSTR(MP_QSTR_e), mp_const_float_e },
  271. { MP_ROM_QSTR(MP_QSTR_pi), mp_const_float_pi },
  272. { MP_ROM_QSTR(MP_QSTR_sqrt), MP_ROM_PTR(&mp_math_sqrt_obj) },
  273. { MP_ROM_QSTR(MP_QSTR_pow), MP_ROM_PTR(&mp_math_pow_obj) },
  274. { MP_ROM_QSTR(MP_QSTR_exp), MP_ROM_PTR(&mp_math_exp_obj) },
  275. #if MICROPY_PY_MATH_SPECIAL_FUNCTIONS
  276. { MP_ROM_QSTR(MP_QSTR_expm1), MP_ROM_PTR(&mp_math_expm1_obj) },
  277. #endif
  278. { MP_ROM_QSTR(MP_QSTR_log), MP_ROM_PTR(&mp_math_log_obj) },
  279. #if MICROPY_PY_MATH_SPECIAL_FUNCTIONS
  280. { MP_ROM_QSTR(MP_QSTR_log2), MP_ROM_PTR(&mp_math_log2_obj) },
  281. { MP_ROM_QSTR(MP_QSTR_log10), MP_ROM_PTR(&mp_math_log10_obj) },
  282. { MP_ROM_QSTR(MP_QSTR_cosh), MP_ROM_PTR(&mp_math_cosh_obj) },
  283. { MP_ROM_QSTR(MP_QSTR_sinh), MP_ROM_PTR(&mp_math_sinh_obj) },
  284. { MP_ROM_QSTR(MP_QSTR_tanh), MP_ROM_PTR(&mp_math_tanh_obj) },
  285. { MP_ROM_QSTR(MP_QSTR_acosh), MP_ROM_PTR(&mp_math_acosh_obj) },
  286. { MP_ROM_QSTR(MP_QSTR_asinh), MP_ROM_PTR(&mp_math_asinh_obj) },
  287. { MP_ROM_QSTR(MP_QSTR_atanh), MP_ROM_PTR(&mp_math_atanh_obj) },
  288. #endif
  289. { MP_ROM_QSTR(MP_QSTR_cos), MP_ROM_PTR(&mp_math_cos_obj) },
  290. { MP_ROM_QSTR(MP_QSTR_sin), MP_ROM_PTR(&mp_math_sin_obj) },
  291. { MP_ROM_QSTR(MP_QSTR_tan), MP_ROM_PTR(&mp_math_tan_obj) },
  292. { MP_ROM_QSTR(MP_QSTR_acos), MP_ROM_PTR(&mp_math_acos_obj) },
  293. { MP_ROM_QSTR(MP_QSTR_asin), MP_ROM_PTR(&mp_math_asin_obj) },
  294. { MP_ROM_QSTR(MP_QSTR_atan), MP_ROM_PTR(&mp_math_atan_obj) },
  295. { MP_ROM_QSTR(MP_QSTR_atan2), MP_ROM_PTR(&mp_math_atan2_obj) },
  296. { MP_ROM_QSTR(MP_QSTR_ceil), MP_ROM_PTR(&mp_math_ceil_obj) },
  297. { MP_ROM_QSTR(MP_QSTR_copysign), MP_ROM_PTR(&mp_math_copysign_obj) },
  298. { MP_ROM_QSTR(MP_QSTR_fabs), MP_ROM_PTR(&mp_math_fabs_obj) },
  299. { MP_ROM_QSTR(MP_QSTR_floor), MP_ROM_PTR(&mp_math_floor_obj) },
  300. { MP_ROM_QSTR(MP_QSTR_fmod), MP_ROM_PTR(&mp_math_fmod_obj) },
  301. { MP_ROM_QSTR(MP_QSTR_frexp), MP_ROM_PTR(&mp_math_frexp_obj) },
  302. { MP_ROM_QSTR(MP_QSTR_ldexp), MP_ROM_PTR(&mp_math_ldexp_obj) },
  303. { MP_ROM_QSTR(MP_QSTR_modf), MP_ROM_PTR(&mp_math_modf_obj) },
  304. { MP_ROM_QSTR(MP_QSTR_isfinite), MP_ROM_PTR(&mp_math_isfinite_obj) },
  305. { MP_ROM_QSTR(MP_QSTR_isinf), MP_ROM_PTR(&mp_math_isinf_obj) },
  306. { MP_ROM_QSTR(MP_QSTR_isnan), MP_ROM_PTR(&mp_math_isnan_obj) },
  307. { MP_ROM_QSTR(MP_QSTR_trunc), MP_ROM_PTR(&mp_math_trunc_obj) },
  308. { MP_ROM_QSTR(MP_QSTR_radians), MP_ROM_PTR(&mp_math_radians_obj) },
  309. { MP_ROM_QSTR(MP_QSTR_degrees), MP_ROM_PTR(&mp_math_degrees_obj) },
  310. #if MICROPY_PY_MATH_FACTORIAL
  311. { MP_ROM_QSTR(MP_QSTR_factorial), MP_ROM_PTR(&mp_math_factorial_obj) },
  312. #endif
  313. #if MICROPY_PY_MATH_SPECIAL_FUNCTIONS
  314. { MP_ROM_QSTR(MP_QSTR_erf), MP_ROM_PTR(&mp_math_erf_obj) },
  315. { MP_ROM_QSTR(MP_QSTR_erfc), MP_ROM_PTR(&mp_math_erfc_obj) },
  316. { MP_ROM_QSTR(MP_QSTR_gamma), MP_ROM_PTR(&mp_math_gamma_obj) },
  317. { MP_ROM_QSTR(MP_QSTR_lgamma), MP_ROM_PTR(&mp_math_lgamma_obj) },
  318. #endif
  319. };
  320. STATIC MP_DEFINE_CONST_DICT(mp_module_math_globals, mp_module_math_globals_table);
  321. const mp_obj_module_t mp_module_math = {
  322. .base = { &mp_type_module },
  323. .globals = (mp_obj_dict_t*)&mp_module_math_globals,
  324. };
  325. #endif // MICROPY_PY_BUILTINS_FLOAT && MICROPY_PY_MATH