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