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