lmtxdecimallib.c /size: 14 Kb    last modification: 2024-01-16 10:22
1/*
2    See license.txt in the root of this project.
3*/
4
5/*
6    decNumberCompare(decNumber *, const decNumber *, const decNumber *, decContext *);
7
8    decNumberRemainder(decNumber *, const decNumber *, const decNumber *, decContext *);
9    decNumberRemainderNear(decNumber *, const decNumber *, const decNumber *, decContext *);
10
11    # define decNumberIsCanonical(dn)
12    # define decNumberIsFinite(dn)
13    # define decNumberIsInfinite(dn)
14    # define decNumberIsNaN(dn)
15    # define decNumberIsNegative(dn)
16    # define decNumberIsQNaN(dn)
17    # define decNumberIsSNaN(dn)
18    # define decNumberIsSpecial(dn)
19    # define decNumberIsZero(dn)
20    # define decNumberRadix(dn)
21
22    The main reason why we have this module is that we already load the library in \METAPOST\
23    so it was a trivial extension to make. Because it is likely that we keep decimal support
24    there, it is also quite likely that we keep this module, even if it's rarely used. The binary
25    number system used in \METAPOST\ is not included. It is even less likely to be used and adds
26    much to the binary. Some more functions might be added here so that we become more compatible
27    with the other math libraries that are present.
28
29*/
30
31# include <luametatex.h>
32
33# include <decContext.h>
34# include <decNumber.h>
35
36# define DECIMAL_METATABLE "decimal number"
37
38typedef decNumber *decimal;
39
40static decContext context;
41
42# define min_precision      25
43# define default_precision  50
44# define max_precision    2500
45
46static void xdecimallib_initialize(void)
47{
48    decContextDefault(&context, DEC_INIT_BASE);
49    context.traps = 0;
50    context.emax = 999999;
51    context.emin = -999999;
52    context.digits = default_precision;
53}
54
55/*tex
56    Todo: Use metatable at the top. But we're not going to crunch numbers anyway so for now there
57    is no need for it. Anyway, the overhade of calculations is much larger than that of locating
58    a metatable.
59*/
60
61inline static decimal xdecimallib_push(lua_State *L)
62{
63    decimal p = lua_newuserdatauv(L, sizeof(decNumber), 0);
64    luaL_setmetatable(L, DECIMAL_METATABLE);
65    return p;
66}
67
68static void decNumberFromDouble(decNumber *A, double B, decContext *C) /* from mplib, extra arg */
69{
70    char buf[1000];
71    char *c;
72    snprintf(buf, 1000, "%-650.325lf", B);
73    c = buf;
74    while (*c++) {
75        if (*c == ' ') {
76            *c = '\0';
77            break;
78        }
79    }
80    decNumberFromString(A, buf, C);
81}
82
83inline static int xdecimallib_new(lua_State *L)
84{
85    decimal p = xdecimallib_push(L);
86    switch (lua_type(L, 1)) {
87        case LUA_TSTRING:
88            decNumberFromString(p, lua_tostring(L, 1), &context);
89            break;
90        case LUA_TNUMBER:
91            if (lua_isinteger(L, 1)) {
92                decNumberFromInt32(p, (int32_t) lua_tointeger(L, 1));
93            } else {
94                decNumberFromDouble(p, lua_tonumber(L, 1), &context);
95            }
96            break;
97        default:
98            decNumberZero(p);
99            break;
100    }
101    return 1;
102}
103
104/*
105    This is nicer for the user. Beware, we create a userdata object on the stack so we need to
106    replace the original non userdata.
107*/
108
109static decimal xdecimallib_get(lua_State *L, int i)
110{
111    switch (lua_type(L, i)) {
112        case LUA_TUSERDATA:
113            return (decimal) luaL_checkudata(L, i, DECIMAL_METATABLE);
114        case LUA_TSTRING:
115            {
116                decimal p = xdecimallib_push(L);
117                decNumberFromString(p, lua_tostring(L, i), &context);
118                lua_replace(L, i);
119                return p;
120            }
121        case LUA_TNUMBER:
122            {
123                decimal p = xdecimallib_push(L);
124                if (lua_isinteger(L, i)) {
125                    decNumberFromInt32(p, (int32_t) lua_tointeger(L, i));
126                } else {
127                    decNumberFromDouble(p, lua_tonumber(L, i), &context);
128                }
129                lua_replace(L, i);
130                return p;
131            }
132        default:
133            {
134                decimal p = xdecimallib_push(L);
135                decNumberZero(p);
136                lua_replace(L, i);
137                return p;
138            }
139    }
140}
141
142static int xdecimallib_tostring(lua_State *L)
143{
144    decimal a = xdecimallib_get(L, 1);
145    luaL_Buffer buffer;
146    char *b = luaL_buffinitsize(L, &buffer, (size_t) a->digits + 14);
147    decNumberToString(a, b);
148    luaL_addsize(&buffer, strlen(b));
149    luaL_pushresult(&buffer);
150    return 1;
151}
152
153static int xdecimallib_toengstring(lua_State *L)
154{
155    decimal a = xdecimallib_get(L, 1);
156    luaL_Buffer buffer;
157    char *b = luaL_buffinitsize(L, &buffer, (size_t) a->digits + 14);
158    decNumberToEngString(a, b);
159    luaL_addsize(&buffer, strlen(b));
160    luaL_pushresult(&buffer);
161    return 1;
162}
163
164static int xdecimallib_tonumber(lua_State *L)
165{
166    decimal a = xdecimallib_get(L, 1);
167    char *buffer = lmt_memory_malloc((size_t) a->digits + 14); /* could be shared */
168    if (buffer) {
169        double result = 0.0;
170        decNumberToString(a, buffer);
171        if (sscanf(buffer, "%lf", &result)) {
172            lua_pushnumber(L, result);
173        } else {
174            lua_pushnil(L);
175        }
176        lmt_memory_free(buffer);
177        return 1;
178    } else {
179        return 0;
180    }
181}
182
183static int xdecimallib_copy(lua_State *L)
184{
185    decimal a = xdecimallib_get(L, 1);
186    decimal p = xdecimallib_push(L);
187    decNumberCopy(p, a);
188    return 1;
189}
190
191static int xdecimallib_eq(lua_State *L)
192{
193    decNumber result;
194    decimal a = xdecimallib_get(L, 1);
195    decimal b = xdecimallib_get(L, 2);
196    decNumberCompare(&result, a, b, &context);
197    lua_pushboolean(L, decNumberIsZero(&result));
198    return 1;
199}
200
201static int xdecimallib_le(lua_State *L)
202{
203    decNumber result;
204    decimal a = xdecimallib_get(L, 1);
205    decimal b = xdecimallib_get(L, 2); /* todo: also number or string */
206    decNumberCompare(&result, a, b, &context);
207    lua_pushboolean(L, decNumberIsNegative(&result) || decNumberIsZero(&result));
208    return 1;
209}
210
211static int xdecimallib_lt(lua_State *L)
212{
213    decNumber result;
214    decimal a = xdecimallib_get(L, 1);
215    decimal b = xdecimallib_get(L, 2); /* todo: also number or string */
216    decNumberCompare(&result, a, b, &context);
217    lua_pushboolean(L, decNumberIsNegative(&result));
218    return 1;
219}
220
221static int xdecimallib_add(lua_State *L) {
222    decimal a = xdecimallib_get(L, 1);
223    decimal b = xdecimallib_get(L, 2);
224    decimal p = xdecimallib_push(L);
225    decNumberAdd(p, a, b, &context);
226    return 1;
227}
228
229static int xdecimallib_sub(lua_State *L) {
230    decimal a = xdecimallib_get(L, 1);
231    decimal b = xdecimallib_get(L, 2);
232    decimal p = xdecimallib_push(L);
233    decNumberSubtract(p, a, b, &context);
234    return 1;
235}
236
237static int xdecimallib_mul(lua_State *L) {
238    decimal a = xdecimallib_get(L, 1);
239    decimal b = xdecimallib_get(L, 2);
240    decimal p = xdecimallib_push(L);
241    decNumberMultiply(p, a, b, &context);
242    return 1;
243}
244
245static int xdecimallib_div(lua_State *L) {
246    decimal a = xdecimallib_get(L, 1);
247    decimal b = xdecimallib_get(L, 2);
248    decimal p = xdecimallib_push(L);
249    decNumberDivide(p, a, b, &context);
250    return 1;
251}
252
253static int xdecimallib_idiv(lua_State *L) {
254    decimal a = xdecimallib_get(L, 1);
255    decimal b = xdecimallib_get(L, 2);
256    decimal p = xdecimallib_push(L);
257    decNumberDivideInteger(p, a, b, &context);
258    return 1;
259}
260
261static int xdecimallib_mod(lua_State *L) {
262    decimal a = xdecimallib_get(L, 1);
263    decimal b = xdecimallib_get(L, 2);
264    decimal p = xdecimallib_push(L);
265    decNumberRemainder(p, a, b, &context);
266    return 1;
267}
268
269static int xdecimallib_neg(lua_State* L) {
270    decimal a = xdecimallib_get(L, 1);
271    decimal p = xdecimallib_push(L);
272    decNumberCopyNegate(p, a);
273    return 1;
274}
275
276static int xdecimallib_min(lua_State *L) {
277    decimal a = xdecimallib_get(L, 1);
278    decimal b = xdecimallib_get(L, 2);
279    decimal p = xdecimallib_push(L);
280    decNumberMin(p, a, b, &context);
281    return 1;
282}
283
284static int xdecimallib_max(lua_State *L) {
285    decimal a = xdecimallib_get(L, 1);
286    decimal b = xdecimallib_get(L, 2);
287    decimal p = xdecimallib_push(L);
288    decNumberMax(p, a, b, &context);
289    return 1;
290}
291
292static int xdecimallib_minus(lua_State* L) {
293    decimal a = xdecimallib_get(L, 1);
294    decimal p = xdecimallib_push(L);
295    decNumberNextMinus(p, a, &context);
296    return 1;
297}
298
299static int xdecimallib_plus(lua_State* L) {
300    decimal a = xdecimallib_get(L, 1);
301    decimal p = xdecimallib_push(L);
302    decNumberNextPlus(p, a, &context);
303    return 1;
304}
305
306static int xdecimallib_trim(lua_State* L) {
307    decimal a = xdecimallib_get(L, 1);
308    decNumberTrim(a);
309    return 0;
310}
311
312static int xdecimallib_pow(lua_State *L) {
313    decimal a = xdecimallib_get(L, 1);
314    decimal b = xdecimallib_get(L, 2);
315    decimal p = xdecimallib_push(L);
316    decNumberPower(p, a, b, &context);
317    return 1;
318}
319
320static int xdecimallib_abs(lua_State *L) {
321    decimal a = xdecimallib_get(L, 1);
322    decimal p = xdecimallib_push(L);
323    decNumberCopyAbs(p, a);
324    return 1;
325}
326
327static int xdecimallib_sqrt(lua_State *L) {
328    decimal a = xdecimallib_get(L, 1);
329    decimal p = xdecimallib_push(L);
330    decNumberSquareRoot(p, a, &context);
331    return 1;
332}
333
334static int xdecimallib_ln(lua_State *L) {
335    decimal a = xdecimallib_get(L, 1);
336    decimal p = xdecimallib_push(L);
337    decNumberLn(p, a, &context);
338    return 1;
339}
340
341static int xdecimallib_log10(lua_State *L) {
342    decimal a = xdecimallib_get(L, 1);
343    decimal p = xdecimallib_push(L);
344    decNumberLog10(p, a, &context);
345    return 1;
346}
347
348static int xdecimallib_exp(lua_State *L) {
349    decimal a = xdecimallib_get(L, 1);
350    decimal p = xdecimallib_push(L);
351    decNumberExp(p, a, &context);
352    return 1;
353}
354
355static int xdecimallib_rotate(lua_State *L) {
356    decimal a = xdecimallib_get(L, 1);
357    decimal b = xdecimallib_get(L, 2);
358    decimal p = xdecimallib_push(L);
359    decNumberRotate(p, a, b, &context);
360    return 1;
361}
362
363static int xdecimallib_shift(lua_State *L) {
364    decimal a = xdecimallib_get(L, 1);
365    decimal b = xdecimallib_get(L, 2);
366    decimal p = xdecimallib_push(L);
367    decNumberShift(p, a, b, &context);
368    return 1;
369}
370
371static int xdecimallib_left(lua_State *L) {
372    decimal a = xdecimallib_get(L, 1);
373    lua_Integer shift = luaL_optinteger(L, 2, 1);
374    decimal p = xdecimallib_push(L);
375    decNumber s;
376    decNumberFromInt32(&s, (int32_t) shift);
377    decNumberShift(p, a, &s, &context);
378    return 1;
379}
380
381static int xdecimallib_right(lua_State *L) {
382    decimal a = xdecimallib_get(L, 1);
383    lua_Integer shift = - luaL_optinteger(L, 2, 1);
384    decimal p = xdecimallib_push(L);
385    decNumber s;
386    decNumberFromInt32(&s, (int32_t) shift);
387    decNumberShift(p, a, &s, &context);
388    return 1;
389}
390
391static int xdecimallib_and(lua_State *L) {
392    decimal a = xdecimallib_get(L, 1);
393    decimal b = xdecimallib_get(L, 2);
394    decimal p = xdecimallib_push(L);
395    decNumberAnd(p, a, b, &context);
396    return 1;
397}
398
399static int xdecimallib_or(lua_State *L)
400{
401    decimal a = xdecimallib_get(L, 1);
402    decimal b = xdecimallib_get(L, 2);
403    decimal p = xdecimallib_push(L);
404    decNumberOr(p, a, b, &context);
405    return 1;
406}
407
408static int xdecimallib_xor(lua_State *L)
409{
410    decimal a = xdecimallib_get(L, 1);
411    decimal b = xdecimallib_get(L, 2);
412    decimal p = xdecimallib_push(L);
413    decNumberXor(p, a, b, &context);
414    return 1;
415}
416
417static int xdecimallib_setp(lua_State *L)
418{
419    int i = (int) luaL_optinteger(L, 1, default_precision);
420    if (i < min_precision) {
421        context.digits = min_precision;
422    } else if (i > max_precision) {
423        context.digits = max_precision;
424    } else {
425        context.digits = i;
426    }
427    lua_pushinteger(L, context.digits);
428    return 1;
429}
430
431static int xdecimallib_getp(lua_State *L)
432{
433    lua_pushinteger(L, context.digits);
434    return 1;
435}
436
437static const luaL_Reg xdecimallib_function_list[] =
438{
439    /* management */
440    { "new",          xdecimallib_new         },
441    { "copy",         xdecimallib_copy        },
442    { "trim",         xdecimallib_trim        },
443    { "tostring",     xdecimallib_tostring    },
444    { "toengstring",  xdecimallib_toengstring },
445    { "tonumber",     xdecimallib_tonumber    },
446    { "setprecision", xdecimallib_setp        },
447    { "getprecision", xdecimallib_getp        },
448    /* operators */
449    { "__add",        xdecimallib_add         },
450    { "__idiv",       xdecimallib_idiv        },
451    { "__div",        xdecimallib_div         },
452    { "__mod",        xdecimallib_mod         },
453    { "__eq",         xdecimallib_eq          },
454    { "__le",         xdecimallib_le          },
455    { "__lt",         xdecimallib_lt          },
456    { "__mul",        xdecimallib_mul         },
457    { "__sub",        xdecimallib_sub         },
458    { "__unm",        xdecimallib_neg         },
459    { "__pow",        xdecimallib_pow         },
460    { "__bor",        xdecimallib_or          },
461    { "__bxor",       xdecimallib_xor         },
462    { "__band",       xdecimallib_and         },
463    { "__shl",        xdecimallib_left        },
464    { "__shr",        xdecimallib_right       },
465    /* functions */
466    { "conj",         xdecimallib_neg         },
467    { "abs",          xdecimallib_abs         },
468    { "pow",          xdecimallib_pow         },
469    { "sqrt",         xdecimallib_sqrt        },
470    { "ln",           xdecimallib_ln          },
471    { "log",          xdecimallib_log10       },
472    { "exp",          xdecimallib_exp         },
473    { "bor",          xdecimallib_or          },
474    { "bxor",         xdecimallib_xor         },
475    { "band",         xdecimallib_and         },
476    { "shift",        xdecimallib_shift       },
477    { "rotate",       xdecimallib_rotate      },
478    { "minus",        xdecimallib_minus       },
479    { "plus",         xdecimallib_plus        },
480    { "min",          xdecimallib_min         },
481    { "max",          xdecimallib_max         },
482    /* */
483    { NULL,           NULL                    },
484};
485
486int luaopen_xdecimal(lua_State *L)
487{
488    xdecimallib_initialize();
489
490    luaL_newmetatable(L, DECIMAL_METATABLE);
491    luaL_setfuncs(L, xdecimallib_function_list, 0);
492    lua_pushliteral(L, "__index");
493    lua_pushvalue(L, -2);
494    lua_settable(L, -3);
495    lua_pushliteral(L, "__tostring");
496    lua_pushliteral(L, "tostring");
497    lua_gettable(L, -3);
498    lua_settable(L, -3);
499    lua_pushliteral(L, "__name");
500    lua_pushliteral(L, "decimal");
501    lua_settable(L, -3);
502    return 1;
503}
504