Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. #include <math.h>
  2. #include "tinypy.h"
  3.  
  4. #ifndef M_E
  5.  #define M_E     2.7182818284590452354
  6. #endif
  7. #ifndef M_PI
  8.  #define M_PI    3.14159265358979323846
  9. #endif
  10.  
  11. #include <errno.h>
  12.  
  13. /*
  14.  * template for tinypy math functions
  15.  * with one parameter.
  16.  *
  17.  * @cfunc is the coresponding function name in C
  18.  * math library.
  19.  */
  20. #define TP_MATH_FUNC1(cfunc)                        \
  21.     static tp_obj math_##cfunc(TP) {                \
  22.         double x = TP_NUM();                        \
  23.         double r = 0.0;                             \
  24.                                                     \
  25.         errno = 0;                                  \
  26.         r = cfunc(x);                               \
  27.         if (errno == EDOM || errno == ERANGE) {     \
  28.             tp_raise(tp_None, tp_printf(tp, "%s(x): x=%f "              \
  29.                                         "out of range", __func__, x));  \
  30.         }                                           \
  31.                                                     \
  32.         return (tp_number(r));                      \
  33.     }
  34.  
  35. /*
  36.  * template for tinypy math functions
  37.  * with two parameters.
  38.  *
  39.  * @cfunc is the coresponding function name in C
  40.  * math library.
  41.  */
  42. #define TP_MATH_FUNC2(cfunc)                        \
  43.     static tp_obj math_##cfunc(TP) {                \
  44.         double x = TP_NUM();                        \
  45.         double y = TP_NUM();                        \
  46.         double r = 0.0;                             \
  47.                                                     \
  48.         errno = 0;                                  \
  49.         r = cfunc(x, y);                            \
  50.         if (errno == EDOM || errno == ERANGE) {     \
  51.             tp_raise(tp_None, tp_printf(tp, "%s(x, y): x=%f,y=%f "      \
  52.                                         "out of range", __func__, x, y)); \
  53.         }                                           \
  54.                                                     \
  55.         return (tp_number(r));                      \
  56.     }
  57.  
  58.  
  59. /*
  60.  * PI definition: 3.1415926535897931
  61.  */
  62. static tp_obj   math_pi;
  63.  
  64. /*
  65.  * E definition: 2.7182818284590451
  66.  */
  67. static tp_obj   math_e;
  68.  
  69. /*
  70.  * acos(x)
  71.  *
  72.  * return arc cosine of x, return value is measured in radians.
  73.  * if x falls out -1 to 1, raise out-of-range exception.
  74.  */
  75. TP_MATH_FUNC1(acos)
  76.  
  77. /*
  78.  * asin(x)
  79.  *
  80.  * return arc sine of x, measured in radians, actually [-PI/2, PI/2]
  81.  * if x falls out of -1 to 1, raise out-of-range exception
  82.  */
  83. TP_MATH_FUNC1(asin)
  84.  
  85. /*
  86.  * atan(x)
  87.  *
  88.  * return arc tangent of x, measured in radians,
  89.  */
  90. TP_MATH_FUNC1(atan)
  91.  
  92. /*
  93.  * atan2(x, y)
  94.  *
  95.  * return arc tangent of x/y, measured in radians.
  96.  * unlike atan(x/y), both the signs of x and y
  97.  * are considered to determine the quaderant of
  98.  * the result.
  99.  */
  100. TP_MATH_FUNC2(atan2)
  101.  
  102. /*
  103.  * ceil(x)
  104.  *
  105.  * return the ceiling of x, i.e, the smallest
  106.  * integer >= x.
  107.  */
  108. TP_MATH_FUNC1(ceil)
  109.  
  110. /*
  111.  * cos(x)
  112.  *
  113.  * return cosine of x. x is measured in radians.
  114.  */
  115. TP_MATH_FUNC1(cos)
  116.  
  117. /*
  118.  * cosh(x)
  119.  *
  120.  * return hyperbolic cosine of x.
  121.  */
  122. TP_MATH_FUNC1(cosh)
  123.  
  124. /*
  125.  * degrees(x)
  126.  *
  127.  * converts angle x from radians to degrees.
  128.  * NOTE: this function is introduced by python,
  129.  * so we cannot wrap it directly in TP_MATH_FUNC1(),
  130.  * here the solution is defining a new
  131.  * C function - degrees().
  132.  */
  133. static const double degToRad =
  134.                 3.141592653589793238462643383 / 180.0;
  135. static double degrees(double x)
  136. {
  137.     return (x / degToRad);
  138. }
  139.  
  140. TP_MATH_FUNC1(degrees)
  141.  
  142. /*
  143.  * exp(x)
  144.  *
  145.  * return the value e raised to power of x.
  146.  * e is the base of natural logarithms.
  147.  */
  148. TP_MATH_FUNC1(exp)
  149.  
  150. /*
  151.  * fabs(x)
  152.  *
  153.  * return the absolute value of x.
  154.  */
  155. TP_MATH_FUNC1(fabs)
  156.  
  157. /*
  158.  * floor(x)
  159.  *
  160.  * return the floor of x, i.e, the largest integer <= x
  161.  */
  162. TP_MATH_FUNC1(floor)
  163.  
  164. /*
  165.  * fmod(x, y)
  166.  *
  167.  * return the remainder of dividing x by y. that is,
  168.  * return x - n * y, where n is the quotient of x/y.
  169.  * NOTE: this function relies on the underlying platform.
  170.  */
  171. TP_MATH_FUNC2(fmod)
  172.  
  173. /*
  174.  * frexp(x)
  175.  *
  176.  * return a pair (r, y), which satisfies:
  177.  * x = r * (2 ** y), and r is normalized fraction
  178.  * which is laid between 1/2 <= abs(r) < 1.
  179.  * if x = 0, the (r, y) = (0, 0).
  180.  */
  181. static tp_obj math_frexp(TP) {
  182.     double x = TP_NUM();
  183.     int    y = 0;  
  184.     double r = 0.0;
  185.     tp_obj rList = tp_list(tp);
  186.  
  187.     errno = 0;
  188.     r = frexp(x, &y);
  189.     if (errno == EDOM || errno == ERANGE) {
  190.         tp_raise(tp_None, tp_printf(tp, "%s(x): x=%f, "
  191.                                     "out of range", __func__, x));
  192.     }
  193.  
  194.     _tp_list_append(tp, rList.list.val, tp_number(r));
  195.     _tp_list_append(tp, rList.list.val, tp_number((tp_num)y));
  196.     return (rList);
  197. }
  198.  
  199.  
  200. /*
  201.  * hypot(x, y)
  202.  *
  203.  * return Euclidean distance, namely,
  204.  * sqrt(x*x + y*y)
  205.  */
  206. TP_MATH_FUNC2(hypot)
  207.  
  208.  
  209. /*
  210.  * ldexp(x, y)
  211.  *
  212.  * return the result of multiplying x by 2
  213.  * raised to y.
  214.  */
  215. TP_MATH_FUNC2(ldexp)
  216.  
  217. /*
  218.  * log(x, [base])
  219.  *
  220.  * return logarithm of x to given base. If base is
  221.  * not given, return the natural logarithm of x.
  222.  * Note: common logarithm(log10) is used to compute
  223.  * the denominator and numerator. based on fomula:
  224.  * log(x, base) = log10(x) / log10(base).
  225.  */
  226. static tp_obj math_log(TP) {
  227.     double x = TP_NUM();
  228.     tp_obj b = TP_DEFAULT(tp_None);
  229.     double y = 0.0;
  230.     double den = 0.0;   /* denominator */
  231.     double num = 0.0;   /* numinator */
  232.     double r = 0.0;     /* result */
  233.  
  234.     if (b.type == TP_NONE)
  235.         y = M_E;
  236.     else if (b.type == TP_NUMBER)
  237.         y = (double)b.number.val;
  238.     else
  239.         tp_raise(tp_None, tp_printf(tp, "%s(x, [base]): base invalid", __func__));
  240.  
  241.     errno = 0;
  242.     num = log10(x);
  243.     if (errno == EDOM || errno == ERANGE)
  244.         goto excep;
  245.  
  246.     errno = 0;
  247.     den = log10(y);
  248.     if (errno == EDOM || errno == ERANGE)
  249.         goto excep;
  250.  
  251.     r = num / den;
  252.  
  253.     return (tp_number(r));
  254.  
  255. excep:
  256.     tp_raise(tp_None, tp_printf(tp, "%s(x, y): x=%f,y=%f "
  257.                                 "out of range", __func__, x, y));
  258. }
  259.  
  260. /*
  261.  * log10(x)
  262.  *
  263.  * return 10-based logarithm of x.
  264.  */
  265. TP_MATH_FUNC1(log10)
  266.  
  267. /*
  268.  * modf(x)
  269.  *
  270.  * return a pair (r, y). r is the integral part of
  271.  * x and y is the fractional part of x, both holds
  272.  * the same sign as x.
  273.  */
  274. static tp_obj math_modf(TP) {
  275.     double x = TP_NUM();
  276.     double y = 0.0;
  277.     double r = 0.0;
  278.     tp_obj rList = tp_list(tp);
  279.  
  280.     errno = 0;
  281.     r = modf(x, &y);
  282.     if (errno == EDOM || errno == ERANGE) {
  283.         tp_raise(tp_None, tp_printf(tp, "%s(x): x=%f, "
  284.                                     "out of range", __func__, x));
  285.     }
  286.  
  287.     _tp_list_append(tp, rList.list.val, tp_number(r));
  288.     _tp_list_append(tp, rList.list.val, tp_number(y));
  289.     return (rList);
  290. }
  291.  
  292. /*
  293.  * pow(x, y)
  294.  *
  295.  * return value of x raised to y. equivalence of x ** y.
  296.  * NOTE: conventionally, tp_pow() is the implementation
  297.  * of builtin function pow(); whilst, math_pow() is an
  298.  * alternative in math module.
  299.  */
  300. static tp_obj math_pow(TP) {
  301.     double x = TP_NUM();
  302.     double y = TP_NUM();
  303.     double r = 0.0;
  304.  
  305.     errno = 0;
  306.     r = pow(x, y);
  307.     if (errno == EDOM || errno == ERANGE) {
  308.         tp_raise(tp_None, tp_printf(tp, "%s(x, y): x=%f,y=%f "
  309.                                     "out of range", __func__, x, y));
  310.     }
  311.  
  312.     return (tp_number(r));
  313. }
  314.  
  315.  
  316. /*
  317.  * radians(x)
  318.  *
  319.  * converts angle x from degrees to radians.
  320.  * NOTE: this function is introduced by python,
  321.  * adopt same solution as degrees(x).
  322.  */
  323. static double radians(double x)
  324. {
  325.     return (x * degToRad);
  326. }
  327.  
  328. TP_MATH_FUNC1(radians)
  329.  
  330. /*
  331.  * sin(x)
  332.  *
  333.  * return sine of x, x is measured in radians.
  334.  */
  335. TP_MATH_FUNC1(sin)
  336.  
  337. /*
  338.  * sinh(x)
  339.  *
  340.  * return hyperbolic sine of x.
  341.  * mathematically, sinh(x) = (exp(x) - exp(-x)) / 2.
  342.  */
  343. TP_MATH_FUNC1(sinh)
  344.  
  345. /*
  346.  * sqrt(x)
  347.  *
  348.  * return square root of x.
  349.  * if x is negtive, raise out-of-range exception.
  350.  */
  351. TP_MATH_FUNC1(sqrt)
  352.  
  353. /*
  354.  * tan(x)
  355.  *
  356.  * return tangent of x, x is measured in radians.
  357.  */
  358. TP_MATH_FUNC1(tan)
  359.  
  360. /*
  361.  * tanh(x)
  362.  *
  363.  * return hyperbolic tangent of x.
  364.  * mathematically, tanh(x) = sinh(x) / cosh(x).
  365.  */
  366. TP_MATH_FUNC1(tanh)
  367.