modmath.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  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: factorial, 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, "division 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. STATIC const mp_rom_map_elem_t mp_module_math_globals_table[] = {
  213. { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_math) },
  214. { MP_ROM_QSTR(MP_QSTR_e), mp_const_float_e },
  215. { MP_ROM_QSTR(MP_QSTR_pi), mp_const_float_pi },
  216. { MP_ROM_QSTR(MP_QSTR_sqrt), MP_ROM_PTR(&mp_math_sqrt_obj) },
  217. { MP_ROM_QSTR(MP_QSTR_pow), MP_ROM_PTR(&mp_math_pow_obj) },
  218. { MP_ROM_QSTR(MP_QSTR_exp), MP_ROM_PTR(&mp_math_exp_obj) },
  219. #if MICROPY_PY_MATH_SPECIAL_FUNCTIONS
  220. { MP_ROM_QSTR(MP_QSTR_expm1), MP_ROM_PTR(&mp_math_expm1_obj) },
  221. #endif
  222. { MP_ROM_QSTR(MP_QSTR_log), MP_ROM_PTR(&mp_math_log_obj) },
  223. #if MICROPY_PY_MATH_SPECIAL_FUNCTIONS
  224. { MP_ROM_QSTR(MP_QSTR_log2), MP_ROM_PTR(&mp_math_log2_obj) },
  225. { MP_ROM_QSTR(MP_QSTR_log10), MP_ROM_PTR(&mp_math_log10_obj) },
  226. { MP_ROM_QSTR(MP_QSTR_cosh), MP_ROM_PTR(&mp_math_cosh_obj) },
  227. { MP_ROM_QSTR(MP_QSTR_sinh), MP_ROM_PTR(&mp_math_sinh_obj) },
  228. { MP_ROM_QSTR(MP_QSTR_tanh), MP_ROM_PTR(&mp_math_tanh_obj) },
  229. { MP_ROM_QSTR(MP_QSTR_acosh), MP_ROM_PTR(&mp_math_acosh_obj) },
  230. { MP_ROM_QSTR(MP_QSTR_asinh), MP_ROM_PTR(&mp_math_asinh_obj) },
  231. { MP_ROM_QSTR(MP_QSTR_atanh), MP_ROM_PTR(&mp_math_atanh_obj) },
  232. #endif
  233. { MP_ROM_QSTR(MP_QSTR_cos), MP_ROM_PTR(&mp_math_cos_obj) },
  234. { MP_ROM_QSTR(MP_QSTR_sin), MP_ROM_PTR(&mp_math_sin_obj) },
  235. { MP_ROM_QSTR(MP_QSTR_tan), MP_ROM_PTR(&mp_math_tan_obj) },
  236. { MP_ROM_QSTR(MP_QSTR_acos), MP_ROM_PTR(&mp_math_acos_obj) },
  237. { MP_ROM_QSTR(MP_QSTR_asin), MP_ROM_PTR(&mp_math_asin_obj) },
  238. { MP_ROM_QSTR(MP_QSTR_atan), MP_ROM_PTR(&mp_math_atan_obj) },
  239. { MP_ROM_QSTR(MP_QSTR_atan2), MP_ROM_PTR(&mp_math_atan2_obj) },
  240. { MP_ROM_QSTR(MP_QSTR_ceil), MP_ROM_PTR(&mp_math_ceil_obj) },
  241. { MP_ROM_QSTR(MP_QSTR_copysign), MP_ROM_PTR(&mp_math_copysign_obj) },
  242. { MP_ROM_QSTR(MP_QSTR_fabs), MP_ROM_PTR(&mp_math_fabs_obj) },
  243. { MP_ROM_QSTR(MP_QSTR_floor), MP_ROM_PTR(&mp_math_floor_obj) },
  244. { MP_ROM_QSTR(MP_QSTR_fmod), MP_ROM_PTR(&mp_math_fmod_obj) },
  245. { MP_ROM_QSTR(MP_QSTR_frexp), MP_ROM_PTR(&mp_math_frexp_obj) },
  246. { MP_ROM_QSTR(MP_QSTR_ldexp), MP_ROM_PTR(&mp_math_ldexp_obj) },
  247. { MP_ROM_QSTR(MP_QSTR_modf), MP_ROM_PTR(&mp_math_modf_obj) },
  248. { MP_ROM_QSTR(MP_QSTR_isfinite), MP_ROM_PTR(&mp_math_isfinite_obj) },
  249. { MP_ROM_QSTR(MP_QSTR_isinf), MP_ROM_PTR(&mp_math_isinf_obj) },
  250. { MP_ROM_QSTR(MP_QSTR_isnan), MP_ROM_PTR(&mp_math_isnan_obj) },
  251. { MP_ROM_QSTR(MP_QSTR_trunc), MP_ROM_PTR(&mp_math_trunc_obj) },
  252. { MP_ROM_QSTR(MP_QSTR_radians), MP_ROM_PTR(&mp_math_radians_obj) },
  253. { MP_ROM_QSTR(MP_QSTR_degrees), MP_ROM_PTR(&mp_math_degrees_obj) },
  254. #if MICROPY_PY_MATH_SPECIAL_FUNCTIONS
  255. { MP_ROM_QSTR(MP_QSTR_erf), MP_ROM_PTR(&mp_math_erf_obj) },
  256. { MP_ROM_QSTR(MP_QSTR_erfc), MP_ROM_PTR(&mp_math_erfc_obj) },
  257. { MP_ROM_QSTR(MP_QSTR_gamma), MP_ROM_PTR(&mp_math_gamma_obj) },
  258. { MP_ROM_QSTR(MP_QSTR_lgamma), MP_ROM_PTR(&mp_math_lgamma_obj) },
  259. #endif
  260. };
  261. STATIC MP_DEFINE_CONST_DICT(mp_module_math_globals, mp_module_math_globals_table);
  262. const mp_obj_module_t mp_module_math = {
  263. .base = { &mp_type_module },
  264. .globals = (mp_obj_dict_t*)&mp_module_math_globals,
  265. };
  266. #endif // MICROPY_PY_BUILTINS_FLOAT && MICROPY_PY_MATH