diff options
Diffstat (limited to 'source/luametatex/source/luarest/lmtxdecimallib.c')
-rw-r--r-- | source/luametatex/source/luarest/lmtxdecimallib.c | 503 |
1 files changed, 503 insertions, 0 deletions
diff --git a/source/luametatex/source/luarest/lmtxdecimallib.c b/source/luametatex/source/luarest/lmtxdecimallib.c new file mode 100644 index 000000000..5f3673821 --- /dev/null +++ b/source/luametatex/source/luarest/lmtxdecimallib.c @@ -0,0 +1,503 @@ +/* + See license.txt in the root of this project. +*/ + +/* + decNumberCompare(decNumber *, const decNumber *, const decNumber *, decContext *); + + decNumberRemainder(decNumber *, const decNumber *, const decNumber *, decContext *); + decNumberRemainderNear(decNumber *, const decNumber *, const decNumber *, decContext *); + + # define decNumberIsCanonical(dn) + # define decNumberIsFinite(dn) + # define decNumberIsInfinite(dn) + # define decNumberIsNaN(dn) + # define decNumberIsNegative(dn) + # define decNumberIsQNaN(dn) + # define decNumberIsSNaN(dn) + # define decNumberIsSpecial(dn) + # define decNumberIsZero(dn) + # define decNumberRadix(dn) + + The main reason why we have this module is that we already load the library in \METAPOST\ + so it was a trivial extension to make. Because it is likely that we keep decimal support + there, it is also quite likely that we keep this module, even if it's rarely used. The binary + number system used in \METAPOST\ is not included. It is even less likely to be used and adds + much to the binary. Some more functions might be added here so that we become more compatible + with the other math libraries that are present. + +*/ + +# include <luametatex.h> + +# include <decContext.h> +# include <decNumber.h> + +# define DECIMAL_METATABLE "decimal number" + +typedef decNumber *decimal; + +static decContext context; + +# define min_precision 25 +# define default_precision 50 +# define max_precision 2500 + +static void xdecimallib_initialize(void) +{ + decContextDefault(&context, DEC_INIT_BASE); + context.traps = 0; + context.emax = 999999; + context.emin = -999999; + context.digits = default_precision; +} + +/*tex + Todo: Use metatable at the top. But we're not going to crunch numbers anyway so for now there + is no need for it. Anyway, the overhade of calculations is much larger than that of locating + a metatable. +*/ + +inline static decimal xdecimallib_push(lua_State *L) +{ + decimal p = lua_newuserdatauv(L, sizeof(decNumber), 0); + luaL_setmetatable(L, DECIMAL_METATABLE); + return p; +} + +static void decNumberFromDouble(decNumber *A, double B, decContext *C) /* from mplib, extra arg */ +{ + char buf[1000]; + char *c; + snprintf(buf, 1000, "%-650.325lf", B); + c = buf; + while (*c++) { + if (*c == ' ') { + *c = '\0'; + break; + } + } + decNumberFromString(A, buf, C); +} + +inline static int xdecimallib_new(lua_State *L) +{ + decimal p = xdecimallib_push(L); + switch (lua_type(L, 1)) { + case LUA_TSTRING: + decNumberFromString(p, lua_tostring(L, 1), &context); + break; + case LUA_TNUMBER: + if (lua_isinteger(L, 1)) { + decNumberFromInt32(p, (int32_t) lua_tointeger(L, 1)); + } else { + decNumberFromDouble(p, lua_tonumber(L, 1), &context); + } + break; + default: + decNumberZero(p); + break; + } + return 1; +} + +/* + This is nicer for the user. Beware, we create a userdata object on the stack so we need to + replace the original non userdata. +*/ + +static decimal xdecimallib_get(lua_State *L, int i) +{ + switch (lua_type(L, i)) { + case LUA_TUSERDATA: + return (decimal) luaL_checkudata(L, i, DECIMAL_METATABLE); + case LUA_TSTRING: + { + decimal p = xdecimallib_push(L); + decNumberFromString(p, lua_tostring(L, i), &context); + lua_replace(L, i); + return p; + } + case LUA_TNUMBER: + { + decimal p = xdecimallib_push(L); + if (lua_isinteger(L, i)) { + decNumberFromInt32(p, (int32_t) lua_tointeger(L, i)); + } else { + decNumberFromDouble(p, lua_tonumber(L, i), &context); + } + lua_replace(L, i); + return p; + } + default: + { + decimal p = xdecimallib_push(L); + decNumberZero(p); + lua_replace(L, i); + return p; + } + } +} + +static int xdecimallib_tostring(lua_State *L) +{ + decimal a = xdecimallib_get(L, 1); + luaL_Buffer buffer; + char *b = luaL_buffinitsize(L, &buffer, (size_t) a->digits + 14); + decNumberToString(a, b); + luaL_addsize(&buffer, strlen(b)); + luaL_pushresult(&buffer); + return 1; +} + +static int xdecimallib_toengstring(lua_State *L) +{ + decimal a = xdecimallib_get(L, 1); + luaL_Buffer buffer; + char *b = luaL_buffinitsize(L, &buffer, (size_t) a->digits + 14); + decNumberToEngString(a, b); + luaL_addsize(&buffer, strlen(b)); + luaL_pushresult(&buffer); + return 1; +} + +static int xdecimallib_tonumber(lua_State *L) +{ + decimal a = xdecimallib_get(L, 1); + char *buffer = lmt_memory_malloc((size_t) a->digits + 14); /* could be shared */ + if (buffer) { + double result = 0.0; + decNumberToString(a, buffer); + if (sscanf(buffer, "%lf", &result)) { + lua_pushnumber(L, result); + } else { + lua_pushnil(L); + } + lmt_memory_free(buffer); + return 1; + } else { + return 0; + } +} + +static int xdecimallib_copy(lua_State *L) +{ + decimal a = xdecimallib_get(L, 1); + decimal p = xdecimallib_push(L); + decNumberCopy(p, a); + return 1; +} + +static int xdecimallib_eq(lua_State *L) +{ + decNumber result; + decimal a = xdecimallib_get(L, 1); + decimal b = xdecimallib_get(L, 2); + decNumberCompare(&result, a, b, &context); + lua_pushboolean(L, decNumberIsZero(&result)); + return 1; +} + +static int xdecimallib_le(lua_State *L) +{ + decNumber result; + decimal a = xdecimallib_get(L, 1); + decimal b = xdecimallib_get(L, 2); /* todo: also number or string */ + decNumberCompare(&result, a, b, &context); + lua_pushboolean(L, decNumberIsNegative(&result) || decNumberIsZero(&result)); + return 1; +} + +static int xdecimallib_lt(lua_State *L) +{ + decNumber result; + decimal a = xdecimallib_get(L, 1); + decimal b = xdecimallib_get(L, 2); /* todo: also number or string */ + decNumberCompare(&result, a, b, &context); + lua_pushboolean(L, decNumberIsNegative(&result)); + return 1; +} + +static int xdecimallib_add(lua_State *L) { + decimal a = xdecimallib_get(L, 1); + decimal b = xdecimallib_get(L, 2); + decimal p = xdecimallib_push(L); + decNumberAdd(p, a, b, &context); + return 1; +} + +static int xdecimallib_sub(lua_State *L) { + decimal a = xdecimallib_get(L, 1); + decimal b = xdecimallib_get(L, 2); + decimal p = xdecimallib_push(L); + decNumberSubtract(p, a, b, &context); + return 1; +} + +static int xdecimallib_mul(lua_State *L) { + decimal a = xdecimallib_get(L, 1); + decimal b = xdecimallib_get(L, 2); + decimal p = xdecimallib_push(L); + decNumberMultiply(p, a, b, &context); + return 1; +} + +static int xdecimallib_div(lua_State *L) { + decimal a = xdecimallib_get(L, 1); + decimal b = xdecimallib_get(L, 2); + decimal p = xdecimallib_push(L); + decNumberDivide(p, a, b, &context); + return 1; +} + +static int xdecimallib_idiv(lua_State *L) { + decimal a = xdecimallib_get(L, 1); + decimal b = xdecimallib_get(L, 2); + decimal p = xdecimallib_push(L); + decNumberDivideInteger(p, a, b, &context); + return 1; +} + +static int xdecimallib_mod(lua_State *L) { + decimal a = xdecimallib_get(L, 1); + decimal b = xdecimallib_get(L, 2); + decimal p = xdecimallib_push(L); + decNumberRemainder(p, a, b, &context); + return 1; +} + +static int xdecimallib_neg(lua_State* L) { + decimal a = xdecimallib_get(L, 1); + decimal p = xdecimallib_push(L); + decNumberCopyNegate(p, a); + return 1; +} + +static int xdecimallib_min(lua_State *L) { + decimal a = xdecimallib_get(L, 1); + decimal b = xdecimallib_get(L, 2); + decimal p = xdecimallib_push(L); + decNumberMin(p, a, b, &context); + return 1; +} + +static int xdecimallib_max(lua_State *L) { + decimal a = xdecimallib_get(L, 1); + decimal b = xdecimallib_get(L, 2); + decimal p = xdecimallib_push(L); + decNumberMax(p, a, b, &context); + return 1; +} + +static int xdecimallib_minus(lua_State* L) { + decimal a = xdecimallib_get(L, 1); + decimal p = xdecimallib_push(L); + decNumberNextMinus(p, a, &context); + return 1; +} + +static int xdecimallib_plus(lua_State* L) { + decimal a = xdecimallib_get(L, 1); + decimal p = xdecimallib_push(L); + decNumberNextPlus(p, a, &context); + return 1; +} + +static int xdecimallib_trim(lua_State* L) { + decimal a = xdecimallib_get(L, 1); + decNumberTrim(a); + return 0; +} + +static int xdecimallib_pow(lua_State *L) { + decimal a = xdecimallib_get(L, 1); + decimal b = xdecimallib_get(L, 2); + decimal p = xdecimallib_push(L); + decNumberPower(p, a, b, &context); + return 1; +} + +static int xdecimallib_abs(lua_State *L) { + decimal a = xdecimallib_get(L, 1); + decimal p = xdecimallib_push(L); + decNumberCopyAbs(p, a); + return 1; +} + +static int xdecimallib_sqrt(lua_State *L) { + decimal a = xdecimallib_get(L, 1); + decimal p = xdecimallib_push(L); + decNumberSquareRoot(p, a, &context); + return 1; +} + +static int xdecimallib_ln(lua_State *L) { + decimal a = xdecimallib_get(L, 1); + decimal p = xdecimallib_push(L); + decNumberLn(p, a, &context); + return 1; +} + +static int xdecimallib_log10(lua_State *L) { + decimal a = xdecimallib_get(L, 1); + decimal p = xdecimallib_push(L); + decNumberLog10(p, a, &context); + return 1; +} + +static int xdecimallib_exp(lua_State *L) { + decimal a = xdecimallib_get(L, 1); + decimal p = xdecimallib_push(L); + decNumberExp(p, a, &context); + return 1; +} + +static int xdecimallib_rotate(lua_State *L) { + decimal a = xdecimallib_get(L, 1); + decimal b = xdecimallib_get(L, 2); + decimal p = xdecimallib_push(L); + decNumberRotate(p, a, b, &context); + return 1; +} + +static int xdecimallib_shift(lua_State *L) { + decimal a = xdecimallib_get(L, 1); + decimal b = xdecimallib_get(L, 2); + decimal p = xdecimallib_push(L); + decNumberShift(p, a, b, &context); + return 1; +} + +static int xdecimallib_left(lua_State *L) { + decimal a = xdecimallib_get(L, 1); + lua_Integer shift = luaL_optinteger(L, 2, 1); + decimal p = xdecimallib_push(L); + decNumber s; + decNumberFromInt32(&s, (int32_t) shift); + decNumberShift(p, a, &s, &context); + return 1; +} + +static int xdecimallib_right(lua_State *L) { + decimal a = xdecimallib_get(L, 1); + lua_Integer shift = - luaL_optinteger(L, 2, 1); + decimal p = xdecimallib_push(L); + decNumber s; + decNumberFromInt32(&s, (int32_t) shift); + decNumberShift(p, a, &s, &context); + return 1; +} + +static int xdecimallib_and(lua_State *L) { + decimal a = xdecimallib_get(L, 1); + decimal b = xdecimallib_get(L, 2); + decimal p = xdecimallib_push(L); + decNumberAnd(p, a, b, &context); + return 1; +} + +static int xdecimallib_or(lua_State *L) +{ + decimal a = xdecimallib_get(L, 1); + decimal b = xdecimallib_get(L, 2); + decimal p = xdecimallib_push(L); + decNumberOr(p, a, b, &context); + return 1; +} + +static int xdecimallib_xor(lua_State *L) +{ + decimal a = xdecimallib_get(L, 1); + decimal b = xdecimallib_get(L, 2); + decimal p = xdecimallib_push(L); + decNumberXor(p, a, b, &context); + return 1; +} + +static int xdecimallib_setp(lua_State *L) +{ + int i = (int) luaL_optinteger(L, 1, default_precision); + if (i < min_precision) { + context.digits = min_precision; + } else if (i > max_precision) { + context.digits = max_precision; + } else { + context.digits = i; + } + lua_pushinteger(L, context.digits); + return 1; +} + +static int xdecimallib_getp(lua_State *L) +{ + lua_pushinteger(L, context.digits); + return 1; +} + +static const luaL_Reg xdecimallib_function_list[] = +{ + /* management */ + { "new", xdecimallib_new }, + { "copy", xdecimallib_copy }, + { "trim", xdecimallib_trim }, + { "tostring", xdecimallib_tostring }, + { "toengstring", xdecimallib_toengstring }, + { "tonumber", xdecimallib_tonumber }, + { "setprecision", xdecimallib_setp }, + { "getprecision", xdecimallib_getp }, + /* operators */ + { "__add", xdecimallib_add }, + { "__idiv", xdecimallib_idiv }, + { "__div", xdecimallib_div }, + { "__mod", xdecimallib_mod }, + { "__eq", xdecimallib_eq }, + { "__le", xdecimallib_le }, + { "__lt", xdecimallib_lt }, + { "__mul", xdecimallib_mul }, + { "__sub", xdecimallib_sub }, + { "__unm", xdecimallib_neg }, + { "__pow", xdecimallib_pow }, + { "__bor", xdecimallib_or }, + { "__bxor", xdecimallib_xor }, + { "__band", xdecimallib_and }, + { "__shl", xdecimallib_left }, + { "__shr", xdecimallib_right }, + /* functions */ + { "conj", xdecimallib_neg }, + { "abs", xdecimallib_abs }, + { "pow", xdecimallib_pow }, + { "sqrt", xdecimallib_sqrt }, + { "ln", xdecimallib_ln }, + { "log", xdecimallib_log10 }, + { "exp", xdecimallib_exp }, + { "bor", xdecimallib_or }, + { "bxor", xdecimallib_xor }, + { "band", xdecimallib_and }, + { "shift", xdecimallib_shift }, + { "rotate", xdecimallib_rotate }, + { "minus", xdecimallib_minus }, + { "plus", xdecimallib_plus }, + { "min", xdecimallib_min }, + { "max", xdecimallib_max }, + /* */ + { NULL, NULL }, +}; + +int luaopen_xdecimal(lua_State *L) +{ + xdecimallib_initialize(); + + luaL_newmetatable(L, DECIMAL_METATABLE); + luaL_setfuncs(L, xdecimallib_function_list, 0); + lua_pushliteral(L, "__index"); + lua_pushvalue(L, -2); + lua_settable(L, -3); + lua_pushliteral(L, "__tostring"); + lua_pushliteral(L, "tostring"); + lua_gettable(L, -3); + lua_settable(L, -3); + lua_pushliteral(L, "__name"); + lua_pushliteral(L, "decimal"); + lua_settable(L, -3); + return 1; +} |