xref: /netbsd-src/lib/lua/libm/libm.c (revision ecbe1e9db9fad3850893dc7888a128ce02d9b745)
1 /* $NetBSD: libm.c,v 1.2 2022/11/23 18:15:43 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.2 2022/11/23 18:15:43 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)
DFUNC_DBL(acosh)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 #ifndef __vax__
144 DFUNC_DBL_DBL(nextafter)
145 #endif
146 DFUNC_DBL_DBL(pow)
147 DFUNC_DBL_DBL(remainder)
148 DFUNC_DBL(rint)
149 DFUNC_DBL(round)
150 DFUNC_DBL(sin)
151 DFUNC_DBL(sinh)
152 DFUNC_DBL(sqrt)
153 DFUNC_DBL(tan)
154 DFUNC_DBL(tanh)
155 DFUNC_DBL(trunc)
156 DFUNC_DBL(y0)
157 DFUNC_DBL(y1)
158 DFUNC_INT_DBL(yn)
159 
160 /*
161  * The following interface functions are special cases which do not lend
162  * themseleves to the systematic declaration scheme above.
163  */
164 static int
165 libm_fma(lua_State *L)
166 {
167 	if (!lua_isnumber(L, 1) ||
168 	    !lua_isnumber(L, 2) ||
169 	    !lua_isnumber(L, 3))
170 		return luaL_error(L, badarg);
171 
172 	double	x[] = {
173 	    lua_tonumber(L, 1),
174 	    lua_tonumber(L, 2),
175 	    lua_tonumber(L, 3)
176 	};
177 	lua_pushnumber(L, fma(x[0], x[1], x[2]));
178 	return 1;
179 }
180 
181 static int
libm_nan(lua_State * L)182 libm_nan(lua_State *L)
183 {
184 	if (!lua_isstring(L, 1))
185 		return luaL_error(L, badarg);
186 
187 	const char     *str = luaL_checkstring(L, 1);
188 	lua_pushnumber(L, nan(str));
189 	return 1;
190 }
191 
192 static int
libm_scalbn(lua_State * L)193 libm_scalbn(lua_State *L)
194 {
195 	if (!lua_isnumber(L, 1) || !lua_isinteger(L, 2))
196 		return luaL_error(L, badarg);
197 
198 	double		x = lua_tonumber(L, 1);
199 	int		i = (int)lua_tointeger(L, 2);
200 	lua_pushnumber(L, scalbn(x, i));
201 	return 1;
202 }
203 
204 static int
libm_ilogb(lua_State * L)205 libm_ilogb(lua_State *L)
206 {
207 	if (!lua_isnumber(L, 1))
208 		return luaL_error(L, badarg);
209 
210 	double		x = lua_tonumber(L, 1);
211 	lua_pushinteger(L, ilogb(x));
212 	return 1;
213 }
214 
215 /*
216  * set up a table for the math.h constants
217  */
218 #define LIBM_CONST(K) {#K, K}
219 struct kv {
220 	const char     *k;
221 	double		v;
222 };
223 
224 static const struct kv libm_const[] = {
225 	LIBM_CONST(M_E),
226 	LIBM_CONST(M_LOG2E),
227 	LIBM_CONST(M_LOG10E),
228 	LIBM_CONST(M_LN2),
229 	LIBM_CONST(M_LN10),
230 	LIBM_CONST(M_PI),
231 	LIBM_CONST(M_PI_2),
232 	LIBM_CONST(M_PI_4),
233 	LIBM_CONST(M_1_PI),
234 	LIBM_CONST(M_2_PI),
235 	LIBM_CONST(M_2_SQRTPI),
236 	LIBM_CONST(M_SQRT2),
237 	LIBM_CONST(M_SQRT1_2),
238 	{ NULL, 0 }
239 };
240 
241 
242 static const struct luaL_Reg lualibm[] = {
243 	{ "acos", libm_acos },
244 	{ "acosh", libm_acosh },
245 	{ "asin", libm_asin },
246 	{ "asinh", libm_asinh },
247 	{ "atan", libm_atan },
248 	{ "atanh", libm_atanh },
249 	{ "atan2", libm_atan2 },
250 	{ "cbrt", libm_cbrt },
251 	{ "ceil", libm_ceil },
252 	{ "copysign", libm_copysign },
253 	{ "cos", libm_cos },
254 	{ "cosh", libm_cosh },
255 	{ "erf", libm_erf },
256 	{ "erfc", libm_erfc },
257 	{ "exp", libm_exp },
258 	{ "exp2", libm_exp2 },
259 	{ "expm1", libm_expm1 },
260 	{ "fabs", libm_fabs },
261 	{ "fdim", libm_fdim },
262 	{ "finite", libm_finite },
263 	{ "floor", libm_floor },
264 	{ "fma", libm_fma },
265 	{ "fmax", libm_fmax },
266 	{ "fmin", libm_fmin },
267 	{ "fmod", libm_fmod },
268 	{ "gamma", libm_gamma },
269 	{ "hypot", libm_hypot },
270 	{ "ilogb", libm_ilogb },
271 	{ "isfinite", libm_isfinite },
272 	{ "isinf", libm_isinf },
273 	{ "isnan", libm_isnan },
274 	{ "j0", libm_j0 },
275 	{ "j1", libm_j1 },
276 	{ "jn", libm_jn },
277 	{ "lgamma", libm_lgamma },
278 	{ "log", libm_log },
279 	{ "log10", libm_log10 },
280 	{ "log1p", libm_log1p },
281 	{ "nan", libm_nan },
282 #ifndef __vax__
283 	{ "nextafter", libm_nextafter },
284 #endif
285 	{ "pow", libm_pow },
286 	{ "remainder", libm_remainder },
287 	{ "rint", libm_rint },
288 	{ "round", libm_round },
289 	{ "scalbn", libm_scalbn },
290 	{ "sin", libm_sin },
291 	{ "sinh", libm_sinh },
292 	{ "sqrt", libm_sqrt },
293 	{ "tan", libm_tan },
294 	{ "tanh", libm_tanh },
295 	{ "trunc", libm_trunc },
296 	{ "y0", libm_y0 },
297 	{ "y1", libm_y1 },
298 	{ "yn", libm_yn },
299 	{ NULL, NULL }
300 };
301 
302 int
luaopen_libm(lua_State * L)303 luaopen_libm(lua_State *L)
304 {
305 	const struct kv *kvp = libm_const;
306 
307 	luaL_newlib(L, lualibm);
308 
309 	/* integrate the math.h constants */
310 	while (kvp->k) {
311 		lua_pushnumber(L, kvp->v);
312 		lua_setfield(L, -2, kvp->k);
313 		kvp++;
314 	}
315 
316 	return 1;
317 }
318