xref: /netbsd-src/lib/lua/libm/libm.c (revision ecbe1e9db9fad3850893dc7888a128ce02d9b745)
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