lmtxcomplexlib.c /size: 10 Kb    last modification: 2024-01-16 10:22
1/*
2
3    See license.txt in the root of this project.
4
5    This is a reformatted and slightly adapted version of lcomplex.c:
6
7    title  : C99 complex numbers for Lua 5.3+
8    author : Luiz Henrique de Figueiredo <lhf@tecgraf.puc-rio.br>
9    date   : 26 Jul 2018 17:57:06
10    licence: This code is hereby placed in the public domain and also under the MIT license
11
12    That implementation doesn't work for MSVC so I rewrote the code to support the microsoft
13    compiler. I no longer use the macro approach to save bytes because with expanded code it is
14    easier to get rid of some compiler warnings (if possible at all).
15
16    In an optional module we hook the error functions into the complex library.
17
18    Note: Alan has to test if all works okay.
19
20*/
21
22# include "luametatex.h"
23
24# include <complex.h>
25
26# define COMPLEX_METATABLE "complex number"
27
28# if (_MSC_VER)
29
30    /*tex
31        Instead of the somewhat strange two-doubles-in-a-row hack in C the microsoft vatiant
32        uses structs. Here we use the double variant.
33    */
34
35    # define Complex _Dcomplex
36
37    inline static Complex xcomplexlib_get(lua_State *L, int i)
38    {
39        switch (lua_type(L, i)) {
40            case LUA_TUSERDATA:
41                return *((Complex*) luaL_checkudata(L, i, COMPLEX_METATABLE));
42            case LUA_TNUMBER:
43            case LUA_TSTRING:
44                return _Cbuild(luaL_checknumber(L, i), 0);
45            default:
46                return _Cbuild(0, 0);
47        }
48    }
49
50# else
51
52    /*tex
53        Here we use the two-doubles-in-a-row variant.
54    */
55
56    # define Complex double complex
57
58    inline static Complex xcomplexlib_get(lua_State *L, int i)
59    {
60        switch (lua_type(L, i)) {
61            case LUA_TUSERDATA:
62                return *((Complex*)luaL_checkudata(L, i, COMPLEX_METATABLE));
63            case LUA_TNUMBER:
64            case LUA_TSTRING:
65                return luaL_checknumber(L, i);
66            default:
67                return 0;
68        }
69    }
70
71# endif
72
73inline static int xcomplexlib_push(lua_State *L, Complex z)
74{
75    Complex *p = lua_newuserdatauv(L, sizeof(Complex), 0);
76    luaL_setmetatable(L, COMPLEX_METATABLE);
77    *p = z;
78    return 1;
79}
80
81# if (_MSC_VER)
82
83    static int xcomplexlib_new(lua_State *L)
84    {
85        xcomplexlib_push(L, _Cbuild(0, 0));
86        return 1;
87    }
88
89    static int xcomplexlib_inew(lua_State *L)
90    {
91        xcomplexlib_push(L, _Cbuild(0, 1));
92        return 1;
93    }
94
95    static int xcomplexlib_eq(lua_State *L)
96    {
97        Complex a = xcomplexlib_get(L, 1);
98        Complex b = xcomplexlib_get(L, 2);
99        lua_pushboolean(L, creal(a) == creal(b) && cimag(a) == cimag(b));
100        return 1;
101    }
102
103    static int xcomplexlib_add(lua_State *L) {
104        Complex a = xcomplexlib_get(L, 1);
105        Complex b = xcomplexlib_get(L, 2);
106        return xcomplexlib_push(L, _Cbuild(creal(a) + creal(b), cimag(a) + cimag(b)));
107    }
108
109    static int xcomplexlib_sub(lua_State *L) {
110        Complex a = xcomplexlib_get(L, 1);
111        Complex b = xcomplexlib_get(L, 2);
112        return xcomplexlib_push(L, _Cbuild(creal(a) - creal(b), cimag(a) - cimag(b)));
113    }
114
115    static int xcomplexlib_neg(lua_State *L) {
116        Complex a = xcomplexlib_get(L, 1);
117        return xcomplexlib_push(L, _Cbuild(-creal(a), -cimag(a)));
118    }
119
120    static int xcomplexlib_div(lua_State *L) {
121        Complex b = xcomplexlib_get(L, 2);
122        if (creal(b) == 0.0 || cimag(b) == 0.0) {
123            return 0;
124        } else {
125            Complex a = xcomplexlib_get(L, 1);
126            Complex t = { 1 / creal(b), 1 / cimag(b) };
127            return xcomplexlib_push(L, _Cmulcc(a, t));
128        }
129    }
130
131    static int xcomplexlib_mul(lua_State *L) {
132        Complex a = xcomplexlib_get(L, 1);
133        Complex b = xcomplexlib_get(L, 2);
134        return xcomplexlib_push(L, _Cmulcc(a, b));
135    }
136
137# else
138
139    static int xcomplexlib_new(lua_State *L)
140    {
141        return xcomplexlib_push(L, luaL_optnumber(L, 1, 0) + luaL_optnumber(L, 2, 0) * I);
142    }
143
144    static int xcomplexlib_inew(lua_State *L)
145    {
146        return xcomplexlib_push(L, I);
147    }
148
149    static int xcomplexlib_eq(lua_State *L)
150    {
151        lua_pushboolean(L, xcomplexlib_get(L, 1) == xcomplexlib_get(L, 2));
152        return 1;
153    }
154
155    static int xcomplexlib_add(lua_State *L)
156    {
157        return xcomplexlib_push(L, xcomplexlib_get(L, 1) + xcomplexlib_get(L, 2));
158    }
159
160    static int xcomplexlib_sub(lua_State *L)
161    {
162        return xcomplexlib_push(L, xcomplexlib_get(L, 1) - xcomplexlib_get(L, 2));
163    }
164
165    static int xcomplexlib_neg(lua_State *L)
166    {
167        return xcomplexlib_push(L, - xcomplexlib_get(L, 1));
168    }
169
170    static int xcomplexlib_div(lua_State *L)
171    {
172        return xcomplexlib_push(L, xcomplexlib_get(L, 1) / xcomplexlib_get(L, 2));
173    }
174
175    static int xcomplexlib_mul(lua_State *L)
176    {
177        return xcomplexlib_push(L, xcomplexlib_get(L, 1) * xcomplexlib_get(L, 2));
178    }
179
180# endif
181
182static int xcomplexlib_abs(lua_State *L)
183{
184    lua_pushnumber(L, (lua_Number) cabs(xcomplexlib_get(L, 1)));
185    return 1;
186}
187
188static int xcomplexlib_acos(lua_State *L)
189{
190    return xcomplexlib_push(L, cacos(xcomplexlib_get(L, 1)));
191}
192
193static int xcomplexlib_acosh(lua_State *L)
194{
195    return xcomplexlib_push(L, cacosh(xcomplexlib_get(L, 1)));
196}
197
198static int xcomplexlib_arg(lua_State *L)
199{
200    lua_pushnumber(L, (lua_Number) carg(xcomplexlib_get(L, 1)));
201    return 1;
202}
203
204static int xcomplexlib_asin(lua_State *L)
205{
206    return xcomplexlib_push(L, casin(xcomplexlib_get(L, 1)));
207}
208
209static int xcomplexlib_asinh(lua_State *L)
210{
211    return xcomplexlib_push(L, casinh(xcomplexlib_get(L, 1)));
212}
213
214static int xcomplexlib_atan(lua_State *L)
215{
216    return xcomplexlib_push(L, catan(xcomplexlib_get(L, 1)));
217}
218
219static int xcomplexlib_atanh(lua_State *L)
220{
221    return xcomplexlib_push(L, catanh(xcomplexlib_get(L, 1)));
222}
223
224static int xcomplexlib_cos(lua_State *L)
225{
226    return xcomplexlib_push(L, ccos(xcomplexlib_get(L, 1)));
227}
228
229static int xcomplexlib_cosh(lua_State *L)
230{
231    return xcomplexlib_push(L, ccosh(xcomplexlib_get(L, 1)));
232}
233
234static int xcomplexlib_exp(lua_State *L)
235{
236    xcomplexlib_push(L, cexp(xcomplexlib_get(L, 1)));
237    return 1;
238}
239
240static int xcomplexlib_imag(lua_State *L) {
241    lua_pushnumber(L, (lua_Number) (cimag)(xcomplexlib_get(L, 1)));
242    return 1;
243}
244
245static int xcomplexlib_log(lua_State *L)
246{
247    return xcomplexlib_push(L, clog(xcomplexlib_get(L, 1)));
248}
249
250static int xcomplexlib_pow(lua_State *L)
251{
252    return xcomplexlib_push(L, cpow(xcomplexlib_get(L, 1), xcomplexlib_get(L, 2)));
253}
254
255static int xcomplexlib_proj(lua_State *L)
256{
257    return xcomplexlib_push(L, cproj(xcomplexlib_get(L, 1)));
258}
259
260static int xcomplexlib_real(lua_State *L)
261{
262    lua_pushnumber(L, (lua_Number) creal(xcomplexlib_get(L, 1)));
263    return 1;
264}
265
266static int xcomplexlib_sin(lua_State *L)
267{
268    return xcomplexlib_push(L, csin(xcomplexlib_get(L, 1)));
269}
270
271static int xcomplexlib_sinh(lua_State *L)
272{
273    return xcomplexlib_push(L, csinh(xcomplexlib_get(L, 1)));
274}
275
276static int xcomplexlib_sqrt(lua_State *L)
277{
278    return xcomplexlib_push(L, csqrt(xcomplexlib_get(L, 1)));
279}
280
281static int xcomplexlib_tan(lua_State *L)
282{
283    return xcomplexlib_push(L, ctan(xcomplexlib_get(L, 1)));
284}
285
286static int xcomplexlib_tanh(lua_State *L)
287{
288    return xcomplexlib_push(L, ctanh(xcomplexlib_get(L, 1)));
289}
290
291/*tex A few convenience functions: */
292
293static int xcomplexlib_tostring(lua_State *L)
294{
295    Complex z = xcomplexlib_get(L, 1);
296    lua_Number x = creal(z);
297    lua_Number y = cimag(z);
298    lua_settop(L, 0);
299    if (x != 0.0 || y == 0.0) {
300        lua_pushnumber(L, x);
301    }
302    if (y != 0.0) {
303        if (y == 1.0) {
304            if (x != 0.0) {
305                lua_pushliteral(L, "+");
306            }
307        } else if (y == -1.0) {
308            lua_pushliteral(L, "-");
309        } else {
310            if (y > 0.0 && x != 0.0) {
311                lua_pushliteral(L, "+");
312            }
313            lua_pushnumber(L, y);
314        }
315        lua_pushliteral(L, "i");
316    }
317    lua_concat(L, lua_gettop(L));
318    return 1;
319}
320
321static int xcomplexlib_topair(lua_State *L)
322{
323    Complex z = xcomplexlib_get(L, 1);
324    lua_pushnumber(L, (lua_Number) creal(z));
325    lua_pushnumber(L, (lua_Number) cimag(z));
326    return 2;
327}
328
329static int xcomplexlib_totable(lua_State *L)
330{
331    Complex z = xcomplexlib_get(L, 1);
332    lua_createtable(L, 2, 0);
333    lua_pushnumber(L, (lua_Number) creal(z));
334    lua_pushnumber(L, (lua_Number) cimag(z));
335    lua_rawseti(L, -3, 1);
336    lua_rawseti(L, -3, 2);
337    return 1;
338}
339
340/*tex Now we assemble the library: */
341
342static const struct luaL_Reg xcomplexlib_function_list[] = {
343    /* management */
344    { "new",        xcomplexlib_new        },
345    { "tostring",   xcomplexlib_tostring   },
346    { "topair",     xcomplexlib_topair     },
347    { "totable",    xcomplexlib_totable    },
348    { "i",          xcomplexlib_inew       },
349    /* operators */
350    { "__add",      xcomplexlib_add        },
351    { "__div",      xcomplexlib_div        },
352    { "__eq",       xcomplexlib_eq         },
353    { "__mul",      xcomplexlib_mul        },
354    { "__sub",      xcomplexlib_sub        },
355    { "__unm",      xcomplexlib_neg        },
356    { "__pow",      xcomplexlib_pow        },
357    /* functions */
358    { "abs",        xcomplexlib_abs        },
359    { "acos",       xcomplexlib_acos       },
360    { "acosh",      xcomplexlib_acosh      },
361    { "arg",        xcomplexlib_arg        },
362    { "asin",       xcomplexlib_asin       },
363    { "asinh",      xcomplexlib_asinh      },
364    { "atan",       xcomplexlib_atan       },
365    { "atanh",      xcomplexlib_atanh      },
366    { "conj",       xcomplexlib_neg        },
367    { "cos",        xcomplexlib_cos        },
368    { "cosh",       xcomplexlib_cosh       },
369    { "exp",        xcomplexlib_exp        },
370    { "imag",       xcomplexlib_imag       },
371    { "log",        xcomplexlib_log        },
372    { "pow",        xcomplexlib_pow        },
373    { "proj",       xcomplexlib_proj       },
374    { "real",       xcomplexlib_real       },
375    { "sin",        xcomplexlib_sin        },
376    { "sinh",       xcomplexlib_sinh       },
377    { "sqrt",       xcomplexlib_sqrt       },
378    { "tan",        xcomplexlib_tan        },
379    { "tanh",       xcomplexlib_tanh       },
380    /* */
381    { NULL,         NULL                   },
382};
383
384int luaopen_xcomplex(lua_State *L)
385{
386    luaL_newmetatable(L, COMPLEX_METATABLE);
387    luaL_setfuncs(L, xcomplexlib_function_list, 0);
388    lua_pushliteral(L, "__index");
389    lua_pushvalue(L, -2);
390    lua_settable(L, -3);
391    lua_pushliteral(L, "__tostring");
392    lua_pushliteral(L, "tostring");
393    lua_gettable(L, -3);
394    lua_settable(L, -3);
395    lua_pushliteral(L, "I");
396    lua_pushliteral(L, "i");
397    lua_gettable(L, -3);
398    lua_settable(L, -3);
399    lua_pushliteral(L, "__name"); /* kind of redundant */
400    lua_pushliteral(L, "complex");
401    lua_settable(L, -3);
402    return 1;
403}
404