0,0 → 1,366 |
#include <math.h> |
#include "tinypy.h" |
|
#ifndef M_E |
#define M_E 2.7182818284590452354 |
#endif |
#ifndef M_PI |
#define M_PI 3.14159265358979323846 |
#endif |
|
#include <errno.h> |
|
/* |
* template for tinypy math functions |
* with one parameter. |
* |
* @cfunc is the coresponding function name in C |
* math library. |
*/ |
#define TP_MATH_FUNC1(cfunc) \ |
static tp_obj math_##cfunc(TP) { \ |
double x = TP_NUM(); \ |
double r = 0.0; \ |
\ |
errno = 0; \ |
r = cfunc(x); \ |
if (errno == EDOM || errno == ERANGE) { \ |
tp_raise(tp_None, tp_printf(tp, "%s(x): x=%f " \ |
"out of range", __func__, x)); \ |
} \ |
\ |
return (tp_number(r)); \ |
} |
|
/* |
* template for tinypy math functions |
* with two parameters. |
* |
* @cfunc is the coresponding function name in C |
* math library. |
*/ |
#define TP_MATH_FUNC2(cfunc) \ |
static tp_obj math_##cfunc(TP) { \ |
double x = TP_NUM(); \ |
double y = TP_NUM(); \ |
double r = 0.0; \ |
\ |
errno = 0; \ |
r = cfunc(x, y); \ |
if (errno == EDOM || errno == ERANGE) { \ |
tp_raise(tp_None, tp_printf(tp, "%s(x, y): x=%f,y=%f " \ |
"out of range", __func__, x, y)); \ |
} \ |
\ |
return (tp_number(r)); \ |
} |
|
|
/* |
* PI definition: 3.1415926535897931 |
*/ |
static tp_obj math_pi; |
|
/* |
* E definition: 2.7182818284590451 |
*/ |
static tp_obj math_e; |
|
/* |
* acos(x) |
* |
* return arc cosine of x, return value is measured in radians. |
* if x falls out -1 to 1, raise out-of-range exception. |
*/ |
TP_MATH_FUNC1(acos) |
|
/* |
* asin(x) |
* |
* return arc sine of x, measured in radians, actually [-PI/2, PI/2] |
* if x falls out of -1 to 1, raise out-of-range exception |
*/ |
TP_MATH_FUNC1(asin) |
|
/* |
* atan(x) |
* |
* return arc tangent of x, measured in radians, |
*/ |
TP_MATH_FUNC1(atan) |
|
/* |
* atan2(x, y) |
* |
* return arc tangent of x/y, measured in radians. |
* unlike atan(x/y), both the signs of x and y |
* are considered to determine the quaderant of |
* the result. |
*/ |
TP_MATH_FUNC2(atan2) |
|
/* |
* ceil(x) |
* |
* return the ceiling of x, i.e, the smallest |
* integer >= x. |
*/ |
TP_MATH_FUNC1(ceil) |
|
/* |
* cos(x) |
* |
* return cosine of x. x is measured in radians. |
*/ |
TP_MATH_FUNC1(cos) |
|
/* |
* cosh(x) |
* |
* return hyperbolic cosine of x. |
*/ |
TP_MATH_FUNC1(cosh) |
|
/* |
* degrees(x) |
* |
* converts angle x from radians to degrees. |
* NOTE: this function is introduced by python, |
* so we cannot wrap it directly in TP_MATH_FUNC1(), |
* here the solution is defining a new |
* C function - degrees(). |
*/ |
static const double degToRad = |
3.141592653589793238462643383 / 180.0; |
static double degrees(double x) |
{ |
return (x / degToRad); |
} |
|
TP_MATH_FUNC1(degrees) |
|
/* |
* exp(x) |
* |
* return the value e raised to power of x. |
* e is the base of natural logarithms. |
*/ |
TP_MATH_FUNC1(exp) |
|
/* |
* fabs(x) |
* |
* return the absolute value of x. |
*/ |
TP_MATH_FUNC1(fabs) |
|
/* |
* floor(x) |
* |
* return the floor of x, i.e, the largest integer <= x |
*/ |
TP_MATH_FUNC1(floor) |
|
/* |
* fmod(x, y) |
* |
* return the remainder of dividing x by y. that is, |
* return x - n * y, where n is the quotient of x/y. |
* NOTE: this function relies on the underlying platform. |
*/ |
TP_MATH_FUNC2(fmod) |
|
/* |
* frexp(x) |
* |
* return a pair (r, y), which satisfies: |
* x = r * (2 ** y), and r is normalized fraction |
* which is laid between 1/2 <= abs(r) < 1. |
* if x = 0, the (r, y) = (0, 0). |
*/ |
static tp_obj math_frexp(TP) { |
double x = TP_NUM(); |
int y = 0; |
double r = 0.0; |
tp_obj rList = tp_list(tp); |
|
errno = 0; |
r = frexp(x, &y); |
if (errno == EDOM || errno == ERANGE) { |
tp_raise(tp_None, tp_printf(tp, "%s(x): x=%f, " |
"out of range", __func__, x)); |
} |
|
_tp_list_append(tp, rList.list.val, tp_number(r)); |
_tp_list_append(tp, rList.list.val, tp_number((tp_num)y)); |
return (rList); |
} |
|
|
/* |
* hypot(x, y) |
* |
* return Euclidean distance, namely, |
* sqrt(x*x + y*y) |
*/ |
TP_MATH_FUNC2(hypot) |
|
|
/* |
* ldexp(x, y) |
* |
* return the result of multiplying x by 2 |
* raised to y. |
*/ |
TP_MATH_FUNC2(ldexp) |
|
/* |
* log(x, [base]) |
* |
* return logarithm of x to given base. If base is |
* not given, return the natural logarithm of x. |
* Note: common logarithm(log10) is used to compute |
* the denominator and numerator. based on fomula: |
* log(x, base) = log10(x) / log10(base). |
*/ |
static tp_obj math_log(TP) { |
double x = TP_NUM(); |
tp_obj b = TP_DEFAULT(tp_None); |
double y = 0.0; |
double den = 0.0; /* denominator */ |
double num = 0.0; /* numinator */ |
double r = 0.0; /* result */ |
|
if (b.type == TP_NONE) |
y = M_E; |
else if (b.type == TP_NUMBER) |
y = (double)b.number.val; |
else |
tp_raise(tp_None, tp_printf(tp, "%s(x, [base]): base invalid", __func__)); |
|
errno = 0; |
num = log10(x); |
if (errno == EDOM || errno == ERANGE) |
goto excep; |
|
errno = 0; |
den = log10(y); |
if (errno == EDOM || errno == ERANGE) |
goto excep; |
|
r = num / den; |
|
return (tp_number(r)); |
|
excep: |
tp_raise(tp_None, tp_printf(tp, "%s(x, y): x=%f,y=%f " |
"out of range", __func__, x, y)); |
} |
|
/* |
* log10(x) |
* |
* return 10-based logarithm of x. |
*/ |
TP_MATH_FUNC1(log10) |
|
/* |
* modf(x) |
* |
* return a pair (r, y). r is the integral part of |
* x and y is the fractional part of x, both holds |
* the same sign as x. |
*/ |
static tp_obj math_modf(TP) { |
double x = TP_NUM(); |
double y = 0.0; |
double r = 0.0; |
tp_obj rList = tp_list(tp); |
|
errno = 0; |
r = modf(x, &y); |
if (errno == EDOM || errno == ERANGE) { |
tp_raise(tp_None, tp_printf(tp, "%s(x): x=%f, " |
"out of range", __func__, x)); |
} |
|
_tp_list_append(tp, rList.list.val, tp_number(r)); |
_tp_list_append(tp, rList.list.val, tp_number(y)); |
return (rList); |
} |
|
/* |
* pow(x, y) |
* |
* return value of x raised to y. equivalence of x ** y. |
* NOTE: conventionally, tp_pow() is the implementation |
* of builtin function pow(); whilst, math_pow() is an |
* alternative in math module. |
*/ |
static tp_obj math_pow(TP) { |
double x = TP_NUM(); |
double y = TP_NUM(); |
double r = 0.0; |
|
errno = 0; |
r = pow(x, y); |
if (errno == EDOM || errno == ERANGE) { |
tp_raise(tp_None, tp_printf(tp, "%s(x, y): x=%f,y=%f " |
"out of range", __func__, x, y)); |
} |
|
return (tp_number(r)); |
} |
|
|
/* |
* radians(x) |
* |
* converts angle x from degrees to radians. |
* NOTE: this function is introduced by python, |
* adopt same solution as degrees(x). |
*/ |
static double radians(double x) |
{ |
return (x * degToRad); |
} |
|
TP_MATH_FUNC1(radians) |
|
/* |
* sin(x) |
* |
* return sine of x, x is measured in radians. |
*/ |
TP_MATH_FUNC1(sin) |
|
/* |
* sinh(x) |
* |
* return hyperbolic sine of x. |
* mathematically, sinh(x) = (exp(x) - exp(-x)) / 2. |
*/ |
TP_MATH_FUNC1(sinh) |
|
/* |
* sqrt(x) |
* |
* return square root of x. |
* if x is negtive, raise out-of-range exception. |
*/ |
TP_MATH_FUNC1(sqrt) |
|
/* |
* tan(x) |
* |
* return tangent of x, x is measured in radians. |
*/ |
TP_MATH_FUNC1(tan) |
|
/* |
* tanh(x) |
* |
* return hyperbolic tangent of x. |
* mathematically, tanh(x) = sinh(x) / cosh(x). |
*/ |
TP_MATH_FUNC1(tanh) |