mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-19 19:10:17 +00:00
205 lines
6.2 KiB
C
205 lines
6.2 KiB
C
#include "pocketpy/pocketpy.h"
|
|
|
|
#include "pocketpy/common/utils.h"
|
|
#include "pocketpy/objects/object.h"
|
|
#include "pocketpy/common/sstream.h"
|
|
#include "pocketpy/interpreter/vm.h"
|
|
|
|
#include <math.h>
|
|
|
|
#define ONE_ARG_FUNC(name, func) \
|
|
static bool math_##name(int argc, py_Ref argv) { \
|
|
PY_CHECK_ARGC(1); \
|
|
double x; \
|
|
if(!py_castfloat(py_arg(0), &x)) return false; \
|
|
py_newfloat(py_retval(), func(x)); \
|
|
return true; \
|
|
}
|
|
|
|
#define TWO_ARG_FUNC(name, func) \
|
|
static bool math_##name(int argc, py_Ref argv) { \
|
|
PY_CHECK_ARGC(2); \
|
|
double x, y; \
|
|
if(!py_castfloat(py_arg(0), &x)) return false; \
|
|
if(!py_castfloat(py_arg(1), &y)) return false; \
|
|
py_newfloat(py_retval(), func(x, y)); \
|
|
return true; \
|
|
}
|
|
|
|
ONE_ARG_FUNC(ceil, ceil)
|
|
ONE_ARG_FUNC(fabs, fabs)
|
|
ONE_ARG_FUNC(floor, floor)
|
|
ONE_ARG_FUNC(trunc, trunc)
|
|
|
|
static bool math_fsum(int argc, py_Ref argv) {
|
|
PY_CHECK_ARGC(1);
|
|
PY_CHECK_ARG_TYPE(0, tp_list);
|
|
py_Ref list = py_arg(0);
|
|
double sum = 0;
|
|
double c = 0;
|
|
for(int i = 0; i < py_list_len(list); i++) {
|
|
py_Ref item = py_list_getitem(list, i);
|
|
double x;
|
|
if(!py_castfloat(item, &x)) return false;
|
|
double y = x - c;
|
|
double t = sum + y;
|
|
c = (t - sum) - y;
|
|
sum = t;
|
|
}
|
|
py_newfloat(py_retval(), sum);
|
|
return true;
|
|
}
|
|
|
|
static bool math_gcd(int argc, py_Ref argv) {
|
|
PY_CHECK_ARGC(2);
|
|
PY_CHECK_ARG_TYPE(0, tp_int);
|
|
PY_CHECK_ARG_TYPE(1, tp_int);
|
|
py_i64 a = py_toint(py_arg(0));
|
|
py_i64 b = py_toint(py_arg(1));
|
|
if(a < 0) a = -a;
|
|
if(b < 0) b = -b;
|
|
while(b != 0) {
|
|
py_i64 t = b;
|
|
b = a % b;
|
|
a = t;
|
|
}
|
|
py_newint(py_retval(), a);
|
|
return true;
|
|
}
|
|
|
|
ONE_ARG_FUNC(isfinite, isfinite)
|
|
ONE_ARG_FUNC(isinf, isinf)
|
|
ONE_ARG_FUNC(isnan, isnan)
|
|
|
|
static bool math_isclose(int argc, py_Ref argv) {
|
|
PY_CHECK_ARGC(2);
|
|
double a, b;
|
|
if(!py_castfloat(py_arg(0), &a)) return false;
|
|
if(!py_castfloat(py_arg(1), &b)) return false;
|
|
py_newbool(py_retval(), fabs(a - b) < 1e-9);
|
|
return true;
|
|
}
|
|
|
|
ONE_ARG_FUNC(exp, exp)
|
|
|
|
static bool math_log(int argc, py_Ref argv) {
|
|
double x;
|
|
if(!py_castfloat(py_arg(0), &x)) return false;
|
|
if(argc == 1) {
|
|
py_newfloat(py_retval(), log(x));
|
|
} else if(argc == 2) {
|
|
double base;
|
|
if(!py_castfloat(py_arg(1), &base)) return false;
|
|
py_newfloat(py_retval(), log(x) / log(base));
|
|
} else {
|
|
return TypeError("log() takes 1 or 2 arguments");
|
|
}
|
|
return true;
|
|
}
|
|
|
|
ONE_ARG_FUNC(log2, log2)
|
|
ONE_ARG_FUNC(log10, log10)
|
|
|
|
TWO_ARG_FUNC(pow, pow)
|
|
|
|
ONE_ARG_FUNC(sqrt, sqrt)
|
|
|
|
ONE_ARG_FUNC(acos, acos)
|
|
ONE_ARG_FUNC(asin, asin)
|
|
ONE_ARG_FUNC(atan, atan)
|
|
|
|
ONE_ARG_FUNC(cos, cos)
|
|
ONE_ARG_FUNC(sin, sin)
|
|
ONE_ARG_FUNC(tan, tan)
|
|
|
|
TWO_ARG_FUNC(atan2, atan2)
|
|
|
|
static bool math_degrees(int argc, py_Ref argv) {
|
|
PY_CHECK_ARGC(1);
|
|
double x;
|
|
if(!py_castfloat(py_arg(0), &x)) return false;
|
|
py_newfloat(py_retval(), x * PK_M_RAD2DEG);
|
|
return true;
|
|
}
|
|
|
|
static bool math_radians(int argc, py_Ref argv) {
|
|
PY_CHECK_ARGC(1);
|
|
double x;
|
|
if(!py_castfloat(py_arg(0), &x)) return false;
|
|
py_newfloat(py_retval(), x * PK_M_DEG2RAD);
|
|
return true;
|
|
}
|
|
|
|
TWO_ARG_FUNC(fmod, fmod)
|
|
|
|
static bool math_modf(int argc, py_Ref argv) {
|
|
PY_CHECK_ARGC(1);
|
|
double i;
|
|
double f = modf(py_tofloat(py_arg(0)), &i);
|
|
py_Ref p = py_newtuple(py_retval(), 2);
|
|
py_newfloat(&p[0], f);
|
|
py_newfloat(&p[1], i);
|
|
return true;
|
|
}
|
|
|
|
static bool math_factorial(int argc, py_Ref argv) {
|
|
PY_CHECK_ARGC(1);
|
|
PY_CHECK_ARG_TYPE(0, tp_int);
|
|
py_i64 n = py_toint(py_arg(0));
|
|
if(n < 0) return ValueError("factorial() not defined for negative values");
|
|
py_i64 r = 1;
|
|
for(py_i64 i = 2; i <= n; i++)
|
|
r *= i;
|
|
py_newint(py_retval(), r);
|
|
return true;
|
|
}
|
|
|
|
void pk__add_module_math() {
|
|
py_Ref mod = py_newmodule("math");
|
|
|
|
py_newfloat(py_emplacedict(mod, py_name("pi")), PK_M_PI);
|
|
py_newfloat(py_emplacedict(mod, py_name("e")), PK_M_E);
|
|
py_newfloat(py_emplacedict(mod, py_name("inf")), INFINITY);
|
|
py_newfloat(py_emplacedict(mod, py_name("nan")), NAN);
|
|
|
|
py_bindfunc(mod, "ceil", math_ceil);
|
|
py_bindfunc(mod, "fabs", math_fabs);
|
|
py_bindfunc(mod, "floor", math_floor);
|
|
py_bindfunc(mod, "trunc", math_trunc);
|
|
|
|
py_bindfunc(mod, "fsum", math_fsum);
|
|
py_bindfunc(mod, "gcd", math_gcd);
|
|
|
|
py_bindfunc(mod, "isfinite", math_isfinite);
|
|
py_bindfunc(mod, "isinf", math_isinf);
|
|
py_bindfunc(mod, "isnan", math_isnan);
|
|
py_bindfunc(mod, "isclose", math_isclose);
|
|
|
|
py_bindfunc(mod, "exp", math_exp);
|
|
py_bindfunc(mod, "log", math_log);
|
|
py_bindfunc(mod, "log2", math_log2);
|
|
py_bindfunc(mod, "log10", math_log10);
|
|
|
|
py_bindfunc(mod, "pow", math_pow);
|
|
py_bindfunc(mod, "sqrt", math_sqrt);
|
|
|
|
py_bindfunc(mod, "acos", math_acos);
|
|
py_bindfunc(mod, "asin", math_asin);
|
|
py_bindfunc(mod, "atan", math_atan);
|
|
|
|
py_bindfunc(mod, "cos", math_cos);
|
|
py_bindfunc(mod, "sin", math_sin);
|
|
py_bindfunc(mod, "tan", math_tan);
|
|
|
|
py_bindfunc(mod, "atan2", math_atan2);
|
|
|
|
py_bindfunc(mod, "degrees", math_degrees);
|
|
py_bindfunc(mod, "radians", math_radians);
|
|
|
|
py_bindfunc(mod, "fmod", math_fmod);
|
|
py_bindfunc(mod, "modf", math_modf);
|
|
py_bindfunc(mod, "factorial", math_factorial);
|
|
}
|
|
|
|
#undef ONE_ARG_FUNC
|
|
#undef TWO_ARG_FUNC |