lmtposit.c /size: 16 Kb    last modification: 2025-02-21 11:03
1/*
2    See license.txt in the root of this project.
3*/
4
5/*tex 
6    This is an experiment using the posit (unum) implementation from https://gitlab.com/cerlane/SoftPosit#known, which is 
7    afaiks the standard. At some point it migh tbe interesting to have this as MetaPost number plugin too, but first I need 
8    to figure out some helpers (sin, cos, pow etc). 
9
10    Watch out: this is just a playground for me and a few others. There are \CONTEXT\ interfaces but these are also quite 
11    experimental. For instance we might move to 64 bit posits. And how about quires.  It all depends on developments in 
12    this area. 
13
14    The standard is at: 
15
16        https://posithub.org/docs/posit_standard-2.pdf
17
18    The reference code can be found here:
19
20        https://gitlab.com/cerlane/SoftPosit
21
22    However, the implementation lags behind the standard: no posit64 and no functions except from a few that add, subtract, 
23    multiply, divide etc. But I will keep an eye in it.  
24
25    Todo: check if we used the right functions (also in auxposit).
26
27*/
28
29# include <luametatex.h>
30
31# define POSIT_METATABLE "posit number"
32 
33static inline posit_t *positlib_push(lua_State *L)
34{
35    posit p = lua_newuserdatauv(L, sizeof(posit_t), 0);
36    luaL_setmetatable(L, POSIT_METATABLE);
37    return p;
38}
39
40static inline int positlib_new(lua_State *L)
41{
42    posit p = positlib_push(L);
43    switch (lua_type(L, 1)) {
44        case LUA_TSTRING:
45            *p = double_to_posit(lua_tonumber(L, 1));
46            break;
47        case LUA_TNUMBER:
48            if (lua_isinteger(L, 1)) {
49                *p = i64_to_posit(lua_tointeger(L, 1));
50            } else {
51                *p = double_to_posit(lua_tonumber(L, 1));
52            }
53            break;
54        default:
55            p->v = 0;
56            break;
57    }
58    return 1;
59}
60
61static inline int positlib_toposit(lua_State *L)
62{
63    if (lua_type(L, 1) == LUA_TNUMBER) {
64        posit_t p = double_to_posit(lua_tonumber(L, 1));
65        lua_pushinteger(L, p.v);
66    } else {
67        lua_pushinteger(L, 0);
68    }
69    return 1;
70}
71
72static inline int positlib_fromposit(lua_State *L)
73{
74    if (lua_type(L, 1) == LUA_TNUMBER) {
75        posit_t p = { .v = lmt_roundnumber(L, 1) };
76        lua_pushnumber(L, posit_to_double(p));
77    } else {
78        lua_pushinteger(L, 0);
79    }
80    return 1;
81}
82
83/*
84    This is nicer for the user. Beware, we create a userdata object on the stack so we need to
85    replace the original non userdata.
86*/
87
88static posit_t *positlib_get(lua_State *L, int i)
89{
90    switch (lua_type(L, i)) {
91        case LUA_TUSERDATA:
92            return (posit) luaL_checkudata(L, i, POSIT_METATABLE);
93        case LUA_TSTRING:
94            {
95                posit p = positlib_push(L);
96                *p = double_to_posit(lua_tonumber(L, i));
97                lua_replace(L, i);
98                return p;
99            }
100        case LUA_TNUMBER:
101            {
102                posit p = positlib_push(L);
103                *p = lua_isinteger(L, i) ? integer_to_posit(lua_tointeger(L, i)) : double_to_posit(lua_tonumber(L, i));
104                lua_replace(L, i);
105                return p;
106            }
107        default:
108            {
109                posit p = positlib_push(L);
110                lua_replace(L, i);
111                return p;
112            }
113    }
114}
115
116static int positlib_tostring(lua_State *L)
117{
118    posit p = positlib_get(L, 1);
119    double d = posit_to_double(*p);
120    lua_pushnumber(L, d);
121    lua_tostring(L, -1);
122    return 1;
123}
124
125
126static int positlib_tonumber(lua_State *L)
127{
128    posit p = positlib_get(L, 1);
129    double d = posit_to_double(*p);
130    lua_pushnumber(L, d);
131    return 1;
132}
133
134static int positlib_copy(lua_State *L)
135{
136    posit a = positlib_get(L, 1);
137    posit p = positlib_push(L);
138    *p  = *a;
139    return 1;
140}
141
142static int positlib_eq(lua_State *L)
143{
144    posit a = positlib_get(L, 1);
145    posit b = positlib_get(L, 2);
146    lua_pushboolean(L, posit_eq(*a, *b));
147    return 1;
148}
149
150static int positlib_le(lua_State *L)
151{
152    posit a = positlib_get(L, 1);
153    posit b = positlib_get(L, 2);
154    lua_pushboolean(L, posit_le(*a, *b));
155    return 1;
156}
157
158static int positlib_lt(lua_State *L)
159{
160    posit a = positlib_get(L, 1);
161    posit b = positlib_get(L, 2);
162    lua_pushboolean(L, posit_lt(*a, *b));
163    return 1;
164}
165
166static int positlib_add(lua_State *L) 
167{
168    posit a = positlib_get(L, 1);
169    posit b = positlib_get(L, 2);
170    posit p = positlib_push(L);
171    *p = posit_add(*a, *b);
172    return 1;
173}
174
175static int positlib_sub(lua_State *L)
176{
177    posit a = positlib_get(L, 1);
178    posit b = positlib_get(L, 2);
179    posit p = positlib_push(L);
180    *p = posit_sub(*a, *b);
181    return 1;
182}
183
184static int positlib_mul(lua_State *L) 
185{
186    posit a = positlib_get(L, 1);
187    posit b = positlib_get(L, 2);
188    posit p = positlib_push(L);
189    *p = posit_mul(*a, *b);
190    return 1;
191}
192
193static int positlib_div(lua_State *L) {
194    posit a = positlib_get(L, 1);
195    posit b = positlib_get(L, 2);
196    posit p = positlib_push(L);
197    *p = posit_div(*a, *b);
198    return 1;
199}
200
201static int positlib_round(lua_State *L) 
202{
203    posit a = positlib_get(L, 1);
204    posit p = positlib_push(L);
205    *p = posit_round_to_integer(*a);
206    return 1;
207}
208
209static int positlib_rounded(lua_State *L) 
210{ 
211    posit a = positlib_get(L, 1);
212    lua_pushinteger(L, posit_to_integer(*a));
213    return 1;
214}
215
216static int positlib_integer(lua_State *L) 
217{
218    posit p = positlib_get(L, 1);
219    lua_pushinteger(L, (lua_Integer) posit_to_i64(*p));
220    return 1;
221}
222
223static int positlib_NaN(lua_State *L) 
224{
225    posit p = positlib_get(L, 1);
226    lua_pushboolean(L, p->v == (uint32_t) 0x80000000);
227    return 1;
228}
229
230static int positlib_NaR(lua_State *L) 
231{
232    posit p = positlib_get(L, 1);
233    lua_pushboolean(L, posit_is_NaR(p->v));
234    return 1;
235}
236
237// static int positlib_idiv(lua_State *L) {
238//     return 0;
239// }
240
241// static int positlib_mod(lua_State *L) {
242//     return 0;
243// }
244
245static int positlib_neg(lua_State* L) 
246{
247    posit a = positlib_get(L, 1);
248    posit p = positlib_push(L);
249    *p = posit_neg(*a); 
250    return 1;
251}
252
253static int positlib_min(lua_State *L) 
254{
255    posit a = positlib_get(L, 1);
256    posit b = positlib_get(L, 2);
257    posit p = positlib_push(L);
258    *p = posit_lt(*a, *b) ? *a : *b; 
259    return 1;
260}
261
262static int positlib_max(lua_State *L) 
263{
264    posit a = positlib_get(L, 1);
265    posit b = positlib_get(L, 2);
266    posit p = positlib_push(L);
267    *p = posit_lt(*a, *b) ? *b : *a; 
268    return 1;
269}
270
271static int positlib_pow(lua_State *L) 
272{
273    posit a = positlib_get(L, 1);
274    posit b = positlib_get(L, 1);
275    posit p = positlib_push(L);
276    *p = double_to_posit(pow(posit_to_double(*a),posit_to_double(*b)));
277    return 1;
278}
279 
280static int positlib_abs(lua_State *L) 
281{
282    posit a = positlib_get(L, 1);
283    posit p = positlib_push(L);
284    *p = posit_abs(*a);
285    return 1;
286}
287
288static int positlib_sqrt(lua_State *L) 
289{
290    posit a = positlib_get(L, 1);
291    posit p = positlib_push(L);
292    *p = posit_sqrt(*a);
293    return 1;
294}
295 
296// static int positlib_ln(lua_State *L) 
297// {
298//     posit a = positlib_get(L, 1);
299//     posit p = positlib_push(L);
300//     *p = double_to_posit(ln(posit_to_double(*a)));
301//     return 1;
302// }
303 
304static int positlib_log10(lua_State *L) 
305{
306    posit a = positlib_get(L, 1);
307    posit p = positlib_push(L);
308    *p = double_to_posit(log10(posit_to_double(*a)));
309    return 1;
310}
311
312static int positlib_log1p(lua_State *L) 
313{
314    posit a = positlib_get(L, 1);
315    posit p = positlib_push(L);
316    *p = double_to_posit(log1p(posit_to_double(*a)));
317    return 1;
318}
319
320static int positlib_log2(lua_State *L) 
321{
322    posit a = positlib_get(L, 1);
323    posit p = positlib_push(L);
324    *p = double_to_posit(log2(posit_to_double(*a)));
325    return 1;
326}
327
328static int positlib_logb(lua_State *L) 
329{
330    posit a = positlib_get(L, 1);
331    posit p = positlib_push(L);
332    *p = double_to_posit(logb(posit_to_double(*a)));
333    return 1;
334}
335
336static int positlib_log(lua_State *L)
337{
338    posit a = positlib_get(L, 1);
339    posit p = positlib_push(L);
340    if (lua_gettop(L) == 1) {
341        *p = double_to_posit(log(posit_to_double(*a)));
342    } else {
343        posit b = positlib_get(L, 2);
344        double d = posit_to_double(*a);
345        double n = posit_to_double(*b);
346        if (n == 10.0) {
347            n = (lua_Number) log10(d);
348        } else if (n == 2.0) {
349            n = (lua_Number) log2(d);
350        } else {
351            n = (lua_Number) log(d) / (lua_Number) log(n);
352        }
353        *p = double_to_posit(n);
354    }
355    return 1;
356}
357
358static int positlib_exp(lua_State *L) 
359{
360    posit a = positlib_get(L, 1);
361    posit p = positlib_push(L);
362    *p = double_to_posit(exp(posit_to_double(*a)));
363    return 1;
364}
365
366static int positlib_exp2(lua_State *L) 
367{
368    posit a = positlib_get(L, 1);
369    posit p = positlib_push(L);
370    *p = double_to_posit(exp2(posit_to_double(*a)));
371    return 1;
372}
373
374static int positlib_ceil(lua_State *L) 
375{
376    posit a = positlib_get(L, 1);
377    posit p = positlib_push(L);
378    *p = double_to_posit(ceil(posit_to_double(*a)));
379    return 1;
380}
381
382static int positlib_floor(lua_State *L) 
383{
384    posit a = positlib_get(L, 1);
385    posit p = positlib_push(L);
386    *p = double_to_posit(floor(posit_to_double(*a)));
387    return 1;
388}
389
390static int positlib_modf(lua_State *L) 
391{
392    posit a = positlib_get(L, 1);
393    posit p = positlib_push(L);
394    posit q = positlib_push(L);
395    double d; 
396    *q = double_to_posit(modf(posit_to_double(*a),&d));
397    *p = double_to_posit(d);
398    return 2;
399}
400
401static int positlib_sin(lua_State *L) 
402{
403    posit a = positlib_get(L, 1);
404    posit p = positlib_push(L);
405    *p = double_to_posit(sin(posit_to_double(*a)));
406    return 1;
407}
408
409static int positlib_cos(lua_State *L) 
410{
411    posit a = positlib_get(L, 1);
412    posit p = positlib_push(L);
413    *p = double_to_posit(cos(posit_to_double(*a)));
414    return 1;
415}
416
417static int positlib_tan(lua_State *L) 
418{
419    posit a = positlib_get(L, 1);
420    posit p = positlib_push(L);
421    *p = double_to_posit(tan(posit_to_double(*a)));
422    return 1;
423}
424
425static int positlib_asin(lua_State *L) 
426{
427    posit a = positlib_get(L, 1);
428    posit p = positlib_push(L);
429    *p = double_to_posit(asin(posit_to_double(*a)));
430    return 1;
431}
432
433static int positlib_acos(lua_State *L) 
434{
435    posit a = positlib_get(L, 1);
436    posit p = positlib_push(L);
437    *p = double_to_posit(acos(posit_to_double(*a)));
438    return 1;
439}
440
441static int positlib_atan(lua_State *L) 
442{
443    posit a = positlib_get(L, 1);
444    posit p = positlib_push(L);
445    *p = double_to_posit(atan(posit_to_double(*a)));
446    return 1;
447}
448
449static int positlib_rotate(lua_State *L) 
450{
451    posit a = positlib_get(L, 1);
452    lua_Integer n = luaL_optinteger(L, 2, 1);
453    posit p = positlib_push(L);
454    if (n > 0) { 
455        p->v = (a->v >> n) | (a->v << (posit_bits - n));
456    } else if (n < 0) {
457        p->v = (a->v << n) | (a->v >> (posit_bits - n));
458    } else {
459        p->v = a->v; 
460    }
461    return 1;
462}
463
464static int positlib_shift(lua_State *L) 
465{
466    posit a = positlib_get(L, 1);
467    lua_Integer shift = luaL_optinteger(L, 2, 1);
468    posit p = positlib_push(L);
469    if (shift > 0) { 
470        p->v = (a->v >> shift) & 0xFFFFFFFF;
471    } else if (shift < 0) { 
472        p->v = (a->v << -shift) & 0xFFFFFFFF;
473    } else { 
474        p->v = a->v; 
475    }
476    return 1;
477}
478 
479static int positlib_left(lua_State *L) 
480{
481    posit a = positlib_get(L, 1);
482    lua_Integer shift = luaL_optinteger(L, 2, 1);
483    posit p = positlib_push(L);
484    p->v = (a->v << shift) & 0xFFFFFFFF;
485    return 1;
486}
487
488static int positlib_right(lua_State *L) 
489{
490    posit_t *a = positlib_get(L, 1);
491    lua_Integer shift = - luaL_optinteger(L, 2, 1);
492    posit_t *p = positlib_push(L);
493    p->v = (a->v >> shift) & 0xFFFFFFFF;
494    return 1;
495}
496 
497static int positlib_and(lua_State *L) 
498{
499    posit a = positlib_get(L, 1);
500    posit b = positlib_get(L, 2);
501    posit p = positlib_push(L);
502    p->v = (a->v) & (b->v); 
503    return 1;
504}
505
506static int positlib_or(lua_State *L)
507{
508    posit a = positlib_get(L, 1);
509    posit b = positlib_get(L, 2);
510    posit p = positlib_push(L);
511    p->v = (a->v) | (b->v); 
512    return 1;
513}
514
515static int positlib_xor(lua_State *L)
516{
517    posit a = positlib_get(L, 1);
518    posit b = positlib_get(L, 2);
519    posit p = positlib_push(L);
520    p->v = (a->v) ^ (b->v); 
521    return 1;
522}
523 
524static const luaL_Reg positlib_function_list[] =
525{
526    /* management */
527    { "new",          positlib_new       },
528    { "copy",         positlib_copy      },
529    { "tostring",     positlib_tostring  },
530    { "tonumber",     positlib_tonumber  },
531    { "integer",      positlib_integer   },
532    { "rounded",      positlib_rounded   },
533    { "toposit",      positlib_toposit   },
534    { "fromposit",    positlib_fromposit },
535    /* operators */                      
536    { "__add",        positlib_add       },
537 // { "__idiv",       positlib_idiv      },
538    { "__div",        positlib_div       },
539 // { "__mod",        positlib_mod       },
540    { "__eq",         positlib_eq        },
541    { "__le",         positlib_le        },
542    { "__lt",         positlib_lt        },
543    { "__mul",        positlib_mul       },
544    { "__sub",        positlib_sub       },
545    { "__unm",        positlib_neg       },
546    { "__pow",        positlib_pow       },
547    { "__bor",        positlib_or        },
548    { "__bxor",       positlib_xor       },
549    { "__band",       positlib_and       },
550    { "__shl",        positlib_left      },
551    { "__shr",        positlib_right     },
552    /* */                                
553    { "NaN",          positlib_NaN       },
554    { "NaR",          positlib_NaR       },
555    /* */                                
556    { "bor",          positlib_or        },
557    { "bxor",         positlib_xor       },
558    { "band",         positlib_and       },
559    { "shift",        positlib_shift     },
560    { "rotate",       positlib_rotate    },
561    /* */                                
562    { "min",          positlib_min       },
563    { "max",          positlib_max       },
564    { "abs",          positlib_abs       },
565    { "conj",         positlib_neg       },
566    { "modf",         positlib_modf      },
567    /* */
568    { "acos",         positlib_acos      },
569 // { "acosh",        positlib_acosh     },
570    { "asin",         positlib_asin      },
571 // { "asinh",        positlib_asinh     },
572    { "atan",         positlib_atan      },
573 // { "atan2",        positlib_atan2     },
574 // { "atanh",        positlib_atanh     },
575 // { "cbrt",         positlib_cbrt      },
576    { "ceil",         positlib_ceil      },
577 // { "copysign",     positlib_copysign  },
578    { "cos",          positlib_cos       },
579 // { "cosh",         positlib_cosh      },
580 // { "deg",          positlib_deg       },
581 // { "erf",          positlib_erf       },
582 // { "erfc",         positlib_erfc      },
583    { "exp",          positlib_exp       },
584    { "exp2",         positlib_exp2      },
585 // { "expm1",        positlib_expm1     },
586 // { "fabs",         positlib_fabs      },
587 // { "fdim",         positlib_fdim      },
588    { "floor",        positlib_floor     },
589 // { "fma",          positlib_fma       },
590 // { "fmax",         positlib_fmax      },
591 // { "fmin",         positlib_fmin      },
592 // { "fmod",         positlib_fmod      },
593 // { "frexp",        positlib_frexp     },
594 // { "gamma",        positlib_gamma     },
595 // { "hypot",        positlib_hypot     },
596 // { "isfinite",     positlib_isfinite  },
597 // { "isinf",        positlib_isinf     },
598 // { "isnan",        positlib_isnan     },
599 // { "isnormal",     positlib_isnormal  },
600 // { "j0",           positlib_j0        },
601 // { "j1",           positlib_j1        },
602 // { "jn",           positlib_jn        },
603 // { "ldexp",        positlib_ldexp     },
604 // { "lgamma",       positlib_lgamma    },
605    { "log",          positlib_log       },
606    { "log10",        positlib_log10     },
607    { "log1p",        positlib_log1p     },
608    { "log2",         positlib_log2      },
609    { "logb",         positlib_logb      },
610 // { "modf",         positlib_modf      },
611 // { "nearbyint",    positlib_nearbyint },
612 // { "nextafter",    positlib_nextafter },
613    { "pow",          positlib_pow       },
614 // { "rad",          positlib_rad       },
615 // { "remainder",    positlib_remainder },
616 // { "remquo",       positlib_fremquo   },
617    { "round",        positlib_round     },
618 // { "scalbn",       positlib_scalbn    },
619    { "sin",          positlib_sin       },
620 // { "sinh",         positlib_sinh      },
621    { "sqrt",         positlib_sqrt      },
622    { "tan",          positlib_tan       },
623 // { "tanh",         positlib_tanh      },
624 // { "tgamma",       positlib_tgamma    },
625 // { "trunc",        positlib_trunc     },
626 // { "y0",           positlib_y0        },
627 // { "y1",           positlib_y1        },
628 // { "yn",           positlib_yn        },
629    /* */
630    { NULL,           NULL               },
631};
632
633int luaopen_posit(lua_State *L)
634{
635    luaL_newmetatable(L, POSIT_METATABLE);
636    luaL_setfuncs(L, positlib_function_list, 0);
637    lua_pushliteral(L, "__index");
638    lua_pushvalue(L, -2);
639    lua_settable(L, -3);
640    lua_pushliteral(L, "__tostring");
641    lua_pushliteral(L, "tostring");
642    lua_gettable(L, -3);
643    lua_settable(L, -3);
644    lua_pushliteral(L, "__name");
645    lua_pushliteral(L, "posit");
646    lua_settable(L, -3);
647    return 1;
648}
649