1*ecbe1e9dSchristos /* $NetBSD: libm.c,v 1.2 2022/11/23 18:15:43 christos Exp $ */
2ae082addSchristos
3ae082addSchristos /*-
4ae082addSchristos * Copyright (c) 2022 The NetBSD Foundation, Inc.
5ae082addSchristos * All rights reserved.
6ae082addSchristos *
7ae082addSchristos * This code is derived from software contributed to The NetBSD Foundation
8ae082addSchristos * by Phillip Rulon
9ae082addSchristos *
10ae082addSchristos * Redistribution and use in source and binary forms, with or without
11ae082addSchristos * modification, are permitted provided that the following conditions
12ae082addSchristos * are met:
13ae082addSchristos * 1. Redistributions of source code must retain the above copyright
14ae082addSchristos * notice, this list of conditions and the following disclaimer.
15ae082addSchristos * 2. Redistributions in binary form must reproduce the above copyright
16ae082addSchristos * notice, this list of conditions and the following disclaimer in the
17ae082addSchristos * documentation and/or other materials provided with the distribution.
18ae082addSchristos *
19ae082addSchristos * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20ae082addSchristos * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21ae082addSchristos * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22ae082addSchristos * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23ae082addSchristos * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24ae082addSchristos * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25ae082addSchristos * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26ae082addSchristos * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27ae082addSchristos * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28ae082addSchristos * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29ae082addSchristos * POSSIBILITY OF SUCH DAMAGE.
30ae082addSchristos */
31ae082addSchristos #include <sys/cdefs.h>
32*ecbe1e9dSchristos __RCSID("$NetBSD: libm.c,v 1.2 2022/11/23 18:15:43 christos Exp $");
33ae082addSchristos
34ae082addSchristos #include <lua.h>
35ae082addSchristos #include <lauxlib.h>
36ae082addSchristos #include <math.h>
37ae082addSchristos
38ae082addSchristos const char badarg[] = "argument to libm function not a number";
39ae082addSchristos
40ae082addSchristos /*-
41ae082addSchristos * The majority of libm functions fall into a few forms:
42ae082addSchristos *
43ae082addSchristos * int func(double);
44ae082addSchristos * double func(double);
45ae082addSchristos * double func(double, double);
46ae082addSchristos * and,
47ae082addSchristos * double func(int, double);
48ae082addSchristos *
49ae082addSchristos * Accordingly, this lends itself to systematic declaration of the lua
50ae082addSchristos * interface functions. These macros set this up.
51ae082addSchristos */
52ae082addSchristos #define BFUNC_DBL(fname) \
53ae082addSchristos static int \
54ae082addSchristos libm_##fname(lua_State *L) \
55ae082addSchristos { \
56ae082addSchristos if (!lua_isnumber(L, 1)) \
57ae082addSchristos return luaL_error(L, badarg); \
58ae082addSchristos \
59ae082addSchristos double x = lua_tonumber(L, 1); \
60ae082addSchristos lua_pushboolean(L, fname(x)); \
61ae082addSchristos return 1; \
62ae082addSchristos }
63ae082addSchristos
64ae082addSchristos #define DFUNC_DBL(fname) \
65ae082addSchristos static int \
66ae082addSchristos libm_##fname(lua_State *L) \
67ae082addSchristos { \
68ae082addSchristos if (!lua_isnumber(L, 1)) \
69ae082addSchristos return luaL_error(L, badarg); \
70ae082addSchristos \
71ae082addSchristos double x = lua_tonumber(L, 1); \
72ae082addSchristos lua_pushnumber(L, fname(x)); \
73ae082addSchristos return 1; \
74ae082addSchristos }
75ae082addSchristos
76ae082addSchristos #define DFUNC_INT_DBL(fname) \
77ae082addSchristos static int \
78ae082addSchristos libm_##fname(lua_State *L) \
79ae082addSchristos { \
80ae082addSchristos if (!lua_isinteger(L, 1) || \
81ae082addSchristos !lua_isnumber(L, 2)) \
82ae082addSchristos return luaL_error(L, badarg); \
83ae082addSchristos \
84ae082addSchristos int i = (int)lua_tointeger(L, 1); \
85ae082addSchristos double x = lua_tonumber(L, 2); \
86ae082addSchristos lua_pushnumber(L, fname(i, x)); \
87ae082addSchristos return 1; \
88ae082addSchristos }
89ae082addSchristos
90ae082addSchristos #define DFUNC_DBL_DBL(fname) \
91ae082addSchristos static int \
92ae082addSchristos libm_##fname(lua_State *L) \
93ae082addSchristos { \
94ae082addSchristos if (!lua_isnumber(L, 1) || \
95ae082addSchristos !lua_isnumber(L, 2)) \
96ae082addSchristos return luaL_error(L, badarg); \
97ae082addSchristos double x[] = { \
98ae082addSchristos lua_tonumber(L, 1), \
99ae082addSchristos lua_tonumber(L,2) \
100ae082addSchristos }; \
101ae082addSchristos lua_pushnumber(L, fname(x[0], x[1])); \
102ae082addSchristos return 1; \
103ae082addSchristos }
104ae082addSchristos
105ae082addSchristos int luaopen_libm(lua_State *);
106ae082addSchristos
107ae082addSchristos DFUNC_DBL(acos)
DFUNC_DBL(acosh)108ae082addSchristos DFUNC_DBL(acosh)
109ae082addSchristos DFUNC_DBL(asin)
110ae082addSchristos DFUNC_DBL(asinh)
111ae082addSchristos DFUNC_DBL(atan)
112ae082addSchristos DFUNC_DBL(atanh)
113ae082addSchristos DFUNC_DBL_DBL(atan2)
114ae082addSchristos DFUNC_DBL(cbrt)
115ae082addSchristos DFUNC_DBL(ceil)
116ae082addSchristos DFUNC_DBL_DBL(copysign)
117ae082addSchristos DFUNC_DBL(cos)
118ae082addSchristos DFUNC_DBL(cosh)
119ae082addSchristos DFUNC_DBL(erf)
120ae082addSchristos DFUNC_DBL(erfc)
121ae082addSchristos DFUNC_DBL(exp)
122ae082addSchristos DFUNC_DBL(exp2)
123ae082addSchristos DFUNC_DBL(expm1)
124ae082addSchristos DFUNC_DBL(fabs)
125ae082addSchristos DFUNC_DBL_DBL(fdim)
126ae082addSchristos BFUNC_DBL(finite)
127ae082addSchristos DFUNC_DBL(floor)
128ae082addSchristos DFUNC_DBL_DBL(fmax)
129ae082addSchristos DFUNC_DBL_DBL(fmin)
130ae082addSchristos DFUNC_DBL_DBL(fmod)
131ae082addSchristos DFUNC_DBL(gamma)
132ae082addSchristos DFUNC_DBL_DBL(hypot)
133ae082addSchristos BFUNC_DBL(isfinite)
134ae082addSchristos BFUNC_DBL(isnan)
135ae082addSchristos BFUNC_DBL(isinf)
136ae082addSchristos DFUNC_DBL(j0)
137ae082addSchristos DFUNC_DBL(j1)
138ae082addSchristos DFUNC_INT_DBL(jn)
139ae082addSchristos DFUNC_DBL(lgamma)
140ae082addSchristos DFUNC_DBL(log)
141ae082addSchristos DFUNC_DBL(log10)
142ae082addSchristos DFUNC_DBL(log1p)
143*ecbe1e9dSchristos #ifndef __vax__
144ae082addSchristos DFUNC_DBL_DBL(nextafter)
145*ecbe1e9dSchristos #endif
146ae082addSchristos DFUNC_DBL_DBL(pow)
147ae082addSchristos DFUNC_DBL_DBL(remainder)
148ae082addSchristos DFUNC_DBL(rint)
149ae082addSchristos DFUNC_DBL(round)
150ae082addSchristos DFUNC_DBL(sin)
151ae082addSchristos DFUNC_DBL(sinh)
152ae082addSchristos DFUNC_DBL(sqrt)
153ae082addSchristos DFUNC_DBL(tan)
154ae082addSchristos DFUNC_DBL(tanh)
155ae082addSchristos DFUNC_DBL(trunc)
156ae082addSchristos DFUNC_DBL(y0)
157ae082addSchristos DFUNC_DBL(y1)
158ae082addSchristos DFUNC_INT_DBL(yn)
159ae082addSchristos
160ae082addSchristos /*
161ae082addSchristos * The following interface functions are special cases which do not lend
162ae082addSchristos * themseleves to the systematic declaration scheme above.
163ae082addSchristos */
164ae082addSchristos static int
165ae082addSchristos libm_fma(lua_State *L)
166ae082addSchristos {
167ae082addSchristos if (!lua_isnumber(L, 1) ||
168ae082addSchristos !lua_isnumber(L, 2) ||
169ae082addSchristos !lua_isnumber(L, 3))
170ae082addSchristos return luaL_error(L, badarg);
171ae082addSchristos
172ae082addSchristos double x[] = {
173ae082addSchristos lua_tonumber(L, 1),
174ae082addSchristos lua_tonumber(L, 2),
175ae082addSchristos lua_tonumber(L, 3)
176ae082addSchristos };
177ae082addSchristos lua_pushnumber(L, fma(x[0], x[1], x[2]));
178ae082addSchristos return 1;
179ae082addSchristos }
180ae082addSchristos
181ae082addSchristos static int
libm_nan(lua_State * L)182ae082addSchristos libm_nan(lua_State *L)
183ae082addSchristos {
184ae082addSchristos if (!lua_isstring(L, 1))
185ae082addSchristos return luaL_error(L, badarg);
186ae082addSchristos
187ae082addSchristos const char *str = luaL_checkstring(L, 1);
188ae082addSchristos lua_pushnumber(L, nan(str));
189ae082addSchristos return 1;
190ae082addSchristos }
191ae082addSchristos
192ae082addSchristos static int
libm_scalbn(lua_State * L)193ae082addSchristos libm_scalbn(lua_State *L)
194ae082addSchristos {
195ae082addSchristos if (!lua_isnumber(L, 1) || !lua_isinteger(L, 2))
196ae082addSchristos return luaL_error(L, badarg);
197ae082addSchristos
198ae082addSchristos double x = lua_tonumber(L, 1);
199ae082addSchristos int i = (int)lua_tointeger(L, 2);
200ae082addSchristos lua_pushnumber(L, scalbn(x, i));
201ae082addSchristos return 1;
202ae082addSchristos }
203ae082addSchristos
204ae082addSchristos static int
libm_ilogb(lua_State * L)205ae082addSchristos libm_ilogb(lua_State *L)
206ae082addSchristos {
207ae082addSchristos if (!lua_isnumber(L, 1))
208ae082addSchristos return luaL_error(L, badarg);
209ae082addSchristos
210ae082addSchristos double x = lua_tonumber(L, 1);
211ae082addSchristos lua_pushinteger(L, ilogb(x));
212ae082addSchristos return 1;
213ae082addSchristos }
214ae082addSchristos
215ae082addSchristos /*
216ae082addSchristos * set up a table for the math.h constants
217ae082addSchristos */
218ae082addSchristos #define LIBM_CONST(K) {#K, K}
219ae082addSchristos struct kv {
220ae082addSchristos const char *k;
221ae082addSchristos double v;
222ae082addSchristos };
223ae082addSchristos
224ae082addSchristos static const struct kv libm_const[] = {
225ae082addSchristos LIBM_CONST(M_E),
226ae082addSchristos LIBM_CONST(M_LOG2E),
227ae082addSchristos LIBM_CONST(M_LOG10E),
228ae082addSchristos LIBM_CONST(M_LN2),
229ae082addSchristos LIBM_CONST(M_LN10),
230ae082addSchristos LIBM_CONST(M_PI),
231ae082addSchristos LIBM_CONST(M_PI_2),
232ae082addSchristos LIBM_CONST(M_PI_4),
233ae082addSchristos LIBM_CONST(M_1_PI),
234ae082addSchristos LIBM_CONST(M_2_PI),
235ae082addSchristos LIBM_CONST(M_2_SQRTPI),
236ae082addSchristos LIBM_CONST(M_SQRT2),
237ae082addSchristos LIBM_CONST(M_SQRT1_2),
238ae082addSchristos { NULL, 0 }
239ae082addSchristos };
240ae082addSchristos
241ae082addSchristos
242ae082addSchristos static const struct luaL_Reg lualibm[] = {
243ae082addSchristos { "acos", libm_acos },
244ae082addSchristos { "acosh", libm_acosh },
245ae082addSchristos { "asin", libm_asin },
246ae082addSchristos { "asinh", libm_asinh },
247ae082addSchristos { "atan", libm_atan },
248ae082addSchristos { "atanh", libm_atanh },
249ae082addSchristos { "atan2", libm_atan2 },
250ae082addSchristos { "cbrt", libm_cbrt },
251ae082addSchristos { "ceil", libm_ceil },
252ae082addSchristos { "copysign", libm_copysign },
253ae082addSchristos { "cos", libm_cos },
254ae082addSchristos { "cosh", libm_cosh },
255ae082addSchristos { "erf", libm_erf },
256ae082addSchristos { "erfc", libm_erfc },
257ae082addSchristos { "exp", libm_exp },
258ae082addSchristos { "exp2", libm_exp2 },
259ae082addSchristos { "expm1", libm_expm1 },
260ae082addSchristos { "fabs", libm_fabs },
261ae082addSchristos { "fdim", libm_fdim },
262ae082addSchristos { "finite", libm_finite },
263ae082addSchristos { "floor", libm_floor },
264ae082addSchristos { "fma", libm_fma },
265ae082addSchristos { "fmax", libm_fmax },
266ae082addSchristos { "fmin", libm_fmin },
267ae082addSchristos { "fmod", libm_fmod },
268ae082addSchristos { "gamma", libm_gamma },
269ae082addSchristos { "hypot", libm_hypot },
270ae082addSchristos { "ilogb", libm_ilogb },
271ae082addSchristos { "isfinite", libm_isfinite },
272ae082addSchristos { "isinf", libm_isinf },
273ae082addSchristos { "isnan", libm_isnan },
274ae082addSchristos { "j0", libm_j0 },
275ae082addSchristos { "j1", libm_j1 },
276ae082addSchristos { "jn", libm_jn },
277ae082addSchristos { "lgamma", libm_lgamma },
278ae082addSchristos { "log", libm_log },
279ae082addSchristos { "log10", libm_log10 },
280ae082addSchristos { "log1p", libm_log1p },
281ae082addSchristos { "nan", libm_nan },
282*ecbe1e9dSchristos #ifndef __vax__
283ae082addSchristos { "nextafter", libm_nextafter },
284*ecbe1e9dSchristos #endif
285ae082addSchristos { "pow", libm_pow },
286ae082addSchristos { "remainder", libm_remainder },
287ae082addSchristos { "rint", libm_rint },
288ae082addSchristos { "round", libm_round },
289ae082addSchristos { "scalbn", libm_scalbn },
290ae082addSchristos { "sin", libm_sin },
291ae082addSchristos { "sinh", libm_sinh },
292ae082addSchristos { "sqrt", libm_sqrt },
293ae082addSchristos { "tan", libm_tan },
294ae082addSchristos { "tanh", libm_tanh },
295ae082addSchristos { "trunc", libm_trunc },
296ae082addSchristos { "y0", libm_y0 },
297ae082addSchristos { "y1", libm_y1 },
298ae082addSchristos { "yn", libm_yn },
299ae082addSchristos { NULL, NULL }
300ae082addSchristos };
301ae082addSchristos
302ae082addSchristos int
luaopen_libm(lua_State * L)303ae082addSchristos luaopen_libm(lua_State *L)
304ae082addSchristos {
305ae082addSchristos const struct kv *kvp = libm_const;
306ae082addSchristos
307ae082addSchristos luaL_newlib(L, lualibm);
308ae082addSchristos
309ae082addSchristos /* integrate the math.h constants */
310ae082addSchristos while (kvp->k) {
311ae082addSchristos lua_pushnumber(L, kvp->v);
312ae082addSchristos lua_setfield(L, -2, kvp->k);
313ae082addSchristos kvp++;
314ae082addSchristos }
315ae082addSchristos
316ae082addSchristos return 1;
317ae082addSchristos }
318