lmtposit.c /size: 16 Kb    last modification: 2024-01-16 10:22
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 
33inline static 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
40inline static 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
61inline static 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
72inline static 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    if (lua_gettop(L) == 1) {
339        posit a = positlib_get(L, 1);
340        posit p = positlib_push(L);
341        *p = double_to_posit(log(posit_to_double(*a)));
342    } else {
343        posit a = positlib_get(L, 1);
344        posit b = positlib_get(L, 2);
345        posit p = positlib_push(L);
346        double d = posit_to_double(*a);
347        double n = posit_to_double(*b);
348        if (n == 10.0) {
349            n = (lua_Number) log10(d);
350        } else if (n == 2.0) {
351            n = (lua_Number) log2(d);
352        } else {
353            n = (lua_Number) log(d) / (lua_Number) log(n);
354        }
355        *p = double_to_posit(n);
356    }
357    return 1;
358}
359
360static int positlib_exp(lua_State *L) 
361{
362    posit a = positlib_get(L, 1);
363    posit p = positlib_push(L);
364    *p = double_to_posit(exp(posit_to_double(*a)));
365    return 1;
366}
367
368static int positlib_exp2(lua_State *L) 
369{
370    posit a = positlib_get(L, 1);
371    posit p = positlib_push(L);
372    *p = double_to_posit(exp2(posit_to_double(*a)));
373    return 1;
374}
375
376static int positlib_ceil(lua_State *L) 
377{
378    posit a = positlib_get(L, 1);
379    posit p = positlib_push(L);
380    *p = double_to_posit(ceil(posit_to_double(*a)));
381    return 1;
382}
383
384static int positlib_floor(lua_State *L) 
385{
386    posit a = positlib_get(L, 1);
387    posit p = positlib_push(L);
388    *p = double_to_posit(floor(posit_to_double(*a)));
389    return 1;
390}
391
392static int positlib_modf(lua_State *L) 
393{
394    posit a = positlib_get(L, 1);
395    posit p = positlib_push(L);
396    posit q = positlib_push(L);
397    double d; 
398    *q = double_to_posit(modf(posit_to_double(*a),&d));
399    *p = double_to_posit(d);
400    return 2;
401}
402
403static int positlib_sin(lua_State *L) 
404{
405    posit a = positlib_get(L, 1);
406    posit p = positlib_push(L);
407    *p = double_to_posit(sin(posit_to_double(*a)));
408    return 1;
409}
410
411static int positlib_cos(lua_State *L) 
412{
413    posit a = positlib_get(L, 1);
414    posit p = positlib_push(L);
415    *p = double_to_posit(cos(posit_to_double(*a)));
416    return 1;
417}
418
419static int positlib_tan(lua_State *L) 
420{
421    posit a = positlib_get(L, 1);
422    posit p = positlib_push(L);
423    *p = double_to_posit(tan(posit_to_double(*a)));
424    return 1;
425}
426
427static int positlib_asin(lua_State *L) 
428{
429    posit a = positlib_get(L, 1);
430    posit p = positlib_push(L);
431    *p = double_to_posit(asin(posit_to_double(*a)));
432    return 1;
433}
434
435static int positlib_acos(lua_State *L) 
436{
437    posit a = positlib_get(L, 1);
438    posit p = positlib_push(L);
439    *p = double_to_posit(acos(posit_to_double(*a)));
440    return 1;
441}
442
443static int positlib_atan(lua_State *L) 
444{
445    posit a = positlib_get(L, 1);
446    posit p = positlib_push(L);
447    *p = double_to_posit(atan(posit_to_double(*a)));
448    return 1;
449}
450
451static int positlib_rotate(lua_State *L) 
452{
453    posit a = positlib_get(L, 1);
454    lua_Integer n = luaL_optinteger(L, 2, 1);
455    posit p = positlib_push(L);
456    if (n > 0) { 
457        p->v = (a->v >> n) | (a->v << (posit_bits - n));
458    } else if (n < 0) {
459        p->v = (a->v << n) | (a->v >> (posit_bits - n));
460    } else {
461        p->v = a->v; 
462    }
463    return 1;
464}
465
466static int positlib_shift(lua_State *L) 
467{
468    posit a = positlib_get(L, 1);
469    lua_Integer shift = luaL_optinteger(L, 2, 1);
470    posit p = positlib_push(L);
471    if (shift > 0) { 
472        p->v = (a->v >> shift) & 0xFFFFFFFF;
473    } else if (shift < 0) { 
474        p->v = (a->v << -shift) & 0xFFFFFFFF;
475    } else { 
476        p->v = a->v; 
477    }
478    return 1;
479}
480 
481static int positlib_left(lua_State *L) 
482{
483    posit a = positlib_get(L, 1);
484    lua_Integer shift = luaL_optinteger(L, 2, 1);
485    posit p = positlib_push(L);
486    p->v = (a->v << shift) & 0xFFFFFFFF;
487    return 1;
488}
489
490static int positlib_right(lua_State *L) 
491{
492    posit_t *a = positlib_get(L, 1);
493    lua_Integer shift = - luaL_optinteger(L, 2, 1);
494    posit_t *p = positlib_push(L);
495    p->v = (a->v >> shift) & 0xFFFFFFFF;
496    return 1;
497}
498 
499static int positlib_and(lua_State *L) 
500{
501    posit a = positlib_get(L, 1);
502    posit b = positlib_get(L, 2);
503    posit p = positlib_push(L);
504    p->v = (a->v) & (b->v); 
505    return 1;
506}
507
508static int positlib_or(lua_State *L)
509{
510    posit a = positlib_get(L, 1);
511    posit b = positlib_get(L, 2);
512    posit p = positlib_push(L);
513    p->v = (a->v) | (b->v); 
514    return 1;
515}
516
517static int positlib_xor(lua_State *L)
518{
519    posit a = positlib_get(L, 1);
520    posit b = positlib_get(L, 2);
521    posit p = positlib_push(L);
522    p->v = (a->v) ^ (b->v); 
523    return 1;
524}
525 
526static const luaL_Reg positlib_function_list[] =
527{
528    /* management */
529    { "new",          positlib_new       },
530    { "copy",         positlib_copy      },
531    { "tostring",     positlib_tostring  },
532    { "tonumber",     positlib_tonumber  },
533    { "integer",      positlib_integer   },
534    { "rounded",      positlib_rounded   },
535    { "toposit",      positlib_toposit   },
536    { "fromposit",    positlib_fromposit },
537    /* operators */                      
538    { "__add",        positlib_add       },
539 // { "__idiv",       positlib_idiv      },
540    { "__div",        positlib_div       },
541 // { "__mod",        positlib_mod       },
542    { "__eq",         positlib_eq        },
543    { "__le",         positlib_le        },
544    { "__lt",         positlib_lt        },
545    { "__mul",        positlib_mul       },
546    { "__sub",        positlib_sub       },
547    { "__unm",        positlib_neg       },
548    { "__pow",        positlib_pow       },
549    { "__bor",        positlib_or        },
550    { "__bxor",       positlib_xor       },
551    { "__band",       positlib_and       },
552    { "__shl",        positlib_left      },
553    { "__shr",        positlib_right     },
554    /* */                                
555    { "NaN",          positlib_NaN       },
556    { "NaR",          positlib_NaR       },
557    /* */                                
558    { "bor",          positlib_or        },
559    { "bxor",         positlib_xor       },
560    { "band",         positlib_and       },
561    { "shift",        positlib_shift     },
562    { "rotate",       positlib_rotate    },
563    /* */                                
564    { "min",          positlib_min       },
565    { "max",          positlib_max       },
566    { "abs",          positlib_abs       },
567    { "conj",         positlib_neg       },
568    { "modf",         positlib_modf      },
569    /* */
570    { "acos",         positlib_acos      },
571 // { "acosh",        positlib_acosh     },
572    { "asin",         positlib_asin      },
573 // { "asinh",        positlib_asinh     },
574    { "atan",         positlib_atan      },
575 // { "atan2",        positlib_atan2     },
576 // { "atanh",        positlib_atanh     },
577 // { "cbrt",         positlib_cbrt      },
578    { "ceil",         positlib_ceil      },
579 // { "copysign",     positlib_copysign  },
580    { "cos",          positlib_cos       },
581 // { "cosh",         positlib_cosh      },
582 // { "deg",          positlib_deg       },
583 // { "erf",          positlib_erf       },
584 // { "erfc",         positlib_erfc      },
585    { "exp",          positlib_exp       },
586    { "exp2",         positlib_exp2      },
587 // { "expm1",        positlib_expm1     },
588 // { "fabs",         positlib_fabs      },
589 // { "fdim",         positlib_fdim      },
590    { "floor",        positlib_floor     },
591 // { "fma",          positlib_fma       },
592 // { "fmax",         positlib_fmax      },
593 // { "fmin",         positlib_fmin      },
594 // { "fmod",         positlib_fmod      },
595 // { "frexp",        positlib_frexp     },
596 // { "gamma",        positlib_gamma     },
597 // { "hypot",        positlib_hypot     },
598 // { "isfinite",     positlib_isfinite  },
599 // { "isinf",        positlib_isinf     },
600 // { "isnan",        positlib_isnan     },
601 // { "isnormal",     positlib_isnormal  },
602 // { "j0",           positlib_j0        },
603 // { "j1",           positlib_j1        },
604 // { "jn",           positlib_jn        },
605 // { "ldexp",        positlib_ldexp     },
606 // { "lgamma",       positlib_lgamma    },
607    { "log",          positlib_log       },
608    { "log10",        positlib_log10     },
609    { "log1p",        positlib_log1p     },
610    { "log2",         positlib_log2      },
611    { "logb",         positlib_logb      },
612 // { "modf",         positlib_modf      },
613 // { "nearbyint",    positlib_nearbyint },
614 // { "nextafter",    positlib_nextafter },
615    { "pow",          positlib_pow       },
616 // { "rad",          positlib_rad       },
617 // { "remainder",    positlib_remainder },
618 // { "remquo",       positlib_fremquo   },
619    { "round",        positlib_round     },
620 // { "scalbn",       positlib_scalbn    },
621    { "sin",          positlib_sin       },
622 // { "sinh",         positlib_sinh      },
623    { "sqrt",         positlib_sqrt      },
624    { "tan",          positlib_tan       },
625 // { "tanh",         positlib_tanh      },
626 // { "tgamma",       positlib_tgamma    },
627 // { "trunc",        positlib_trunc     },
628 // { "y0",           positlib_y0        },
629 // { "y1",           positlib_y1        },
630 // { "yn",           positlib_yn        },
631    /* */
632    { NULL,           NULL               },
633};
634
635int luaopen_posit(lua_State *L)
636{
637    luaL_newmetatable(L, POSIT_METATABLE);
638    luaL_setfuncs(L, positlib_function_list, 0);
639    lua_pushliteral(L, "__index");
640    lua_pushvalue(L, -2);
641    lua_settable(L, -3);
642    lua_pushliteral(L, "__tostring");
643    lua_pushliteral(L, "tostring");
644    lua_gettable(L, -3);
645    lua_settable(L, -3);
646    lua_pushliteral(L, "__name");
647    lua_pushliteral(L, "posit");
648    lua_settable(L, -3);
649    return 1;
650}
651