Home | History | Annotate | Line # | Download | only in libm
      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)
    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
    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
    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
    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
    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