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 38const 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) \ 53static int \ 54libm_##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) \ 65static int \ 66libm_##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) \ 77static int \ 78libm_##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) \ 91static int \ 92libm_##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 105int luaopen_libm(lua_State *); 106 107DFUNC_DBL(acos) 108DFUNC_DBL(acosh) 109DFUNC_DBL(asin) 110DFUNC_DBL(asinh) 111DFUNC_DBL(atan) 112DFUNC_DBL(atanh) 113DFUNC_DBL_DBL(atan2) 114DFUNC_DBL(cbrt) 115DFUNC_DBL(ceil) 116DFUNC_DBL_DBL(copysign) 117DFUNC_DBL(cos) 118DFUNC_DBL(cosh) 119DFUNC_DBL(erf) 120DFUNC_DBL(erfc) 121DFUNC_DBL(exp) 122DFUNC_DBL(exp2) 123DFUNC_DBL(expm1) 124DFUNC_DBL(fabs) 125DFUNC_DBL_DBL(fdim) 126BFUNC_DBL(finite) 127DFUNC_DBL(floor) 128DFUNC_DBL_DBL(fmax) 129DFUNC_DBL_DBL(fmin) 130DFUNC_DBL_DBL(fmod) 131DFUNC_DBL(gamma) 132DFUNC_DBL_DBL(hypot) 133BFUNC_DBL(isfinite) 134BFUNC_DBL(isnan) 135BFUNC_DBL(isinf) 136DFUNC_DBL(j0) 137DFUNC_DBL(j1) 138DFUNC_INT_DBL(jn) 139DFUNC_DBL(lgamma) 140DFUNC_DBL(log) 141DFUNC_DBL(log10) 142DFUNC_DBL(log1p) 143#ifndef __vax__ 144DFUNC_DBL_DBL(nextafter) 145#endif 146DFUNC_DBL_DBL(pow) 147DFUNC_DBL_DBL(remainder) 148DFUNC_DBL(rint) 149DFUNC_DBL(round) 150DFUNC_DBL(sin) 151DFUNC_DBL(sinh) 152DFUNC_DBL(sqrt) 153DFUNC_DBL(tan) 154DFUNC_DBL(tanh) 155DFUNC_DBL(trunc) 156DFUNC_DBL(y0) 157DFUNC_DBL(y1) 158DFUNC_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 */ 164static int 165libm_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 181static int 182libm_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 192static int 193libm_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 204static int 205libm_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} 219struct kv { 220 const char *k; 221 double v; 222}; 223 224static 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 242static 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 302int 303luaopen_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