18e3e3a7aSWarner Losh /* 20495ed39SKyle Evans ** $Id: lmathlib.c $ 38e3e3a7aSWarner Losh ** Standard mathematical library 48e3e3a7aSWarner Losh ** See Copyright Notice in lua.h 58e3e3a7aSWarner Losh */ 68e3e3a7aSWarner Losh 78e3e3a7aSWarner Losh #define lmathlib_c 88e3e3a7aSWarner Losh #define LUA_LIB 98e3e3a7aSWarner Losh 108e3e3a7aSWarner Losh #include "lprefix.h" 118e3e3a7aSWarner Losh 128e3e3a7aSWarner Losh 130495ed39SKyle Evans #include <float.h> 140495ed39SKyle Evans #include <limits.h> 158e3e3a7aSWarner Losh #include <math.h> 160495ed39SKyle Evans #include <stdlib.h> 170495ed39SKyle Evans #include <time.h> 188e3e3a7aSWarner Losh 198e3e3a7aSWarner Losh #include "lua.h" 208e3e3a7aSWarner Losh 218e3e3a7aSWarner Losh #include "lauxlib.h" 228e3e3a7aSWarner Losh #include "lualib.h" 238e3e3a7aSWarner Losh 248e3e3a7aSWarner Losh 258e3e3a7aSWarner Losh #undef PI 268e3e3a7aSWarner Losh #define PI (l_mathop(3.141592653589793238462643383279502884)) 278e3e3a7aSWarner Losh 288e3e3a7aSWarner Losh 298e3e3a7aSWarner Losh static int math_abs (lua_State *L) { 308e3e3a7aSWarner Losh if (lua_isinteger(L, 1)) { 318e3e3a7aSWarner Losh lua_Integer n = lua_tointeger(L, 1); 328e3e3a7aSWarner Losh if (n < 0) n = (lua_Integer)(0u - (lua_Unsigned)n); 338e3e3a7aSWarner Losh lua_pushinteger(L, n); 348e3e3a7aSWarner Losh } 358e3e3a7aSWarner Losh else 368e3e3a7aSWarner Losh lua_pushnumber(L, l_mathop(fabs)(luaL_checknumber(L, 1))); 378e3e3a7aSWarner Losh return 1; 388e3e3a7aSWarner Losh } 398e3e3a7aSWarner Losh 408e3e3a7aSWarner Losh static int math_sin (lua_State *L) { 418e3e3a7aSWarner Losh lua_pushnumber(L, l_mathop(sin)(luaL_checknumber(L, 1))); 428e3e3a7aSWarner Losh return 1; 438e3e3a7aSWarner Losh } 448e3e3a7aSWarner Losh 458e3e3a7aSWarner Losh static int math_cos (lua_State *L) { 468e3e3a7aSWarner Losh lua_pushnumber(L, l_mathop(cos)(luaL_checknumber(L, 1))); 478e3e3a7aSWarner Losh return 1; 488e3e3a7aSWarner Losh } 498e3e3a7aSWarner Losh 508e3e3a7aSWarner Losh static int math_tan (lua_State *L) { 518e3e3a7aSWarner Losh lua_pushnumber(L, l_mathop(tan)(luaL_checknumber(L, 1))); 528e3e3a7aSWarner Losh return 1; 538e3e3a7aSWarner Losh } 548e3e3a7aSWarner Losh 558e3e3a7aSWarner Losh static int math_asin (lua_State *L) { 568e3e3a7aSWarner Losh lua_pushnumber(L, l_mathop(asin)(luaL_checknumber(L, 1))); 578e3e3a7aSWarner Losh return 1; 588e3e3a7aSWarner Losh } 598e3e3a7aSWarner Losh 608e3e3a7aSWarner Losh static int math_acos (lua_State *L) { 618e3e3a7aSWarner Losh lua_pushnumber(L, l_mathop(acos)(luaL_checknumber(L, 1))); 628e3e3a7aSWarner Losh return 1; 638e3e3a7aSWarner Losh } 648e3e3a7aSWarner Losh 658e3e3a7aSWarner Losh static int math_atan (lua_State *L) { 668e3e3a7aSWarner Losh lua_Number y = luaL_checknumber(L, 1); 678e3e3a7aSWarner Losh lua_Number x = luaL_optnumber(L, 2, 1); 688e3e3a7aSWarner Losh lua_pushnumber(L, l_mathop(atan2)(y, x)); 698e3e3a7aSWarner Losh return 1; 708e3e3a7aSWarner Losh } 718e3e3a7aSWarner Losh 728e3e3a7aSWarner Losh 738e3e3a7aSWarner Losh static int math_toint (lua_State *L) { 748e3e3a7aSWarner Losh int valid; 758e3e3a7aSWarner Losh lua_Integer n = lua_tointegerx(L, 1, &valid); 76*8c784bb8SWarner Losh if (l_likely(valid)) 778e3e3a7aSWarner Losh lua_pushinteger(L, n); 788e3e3a7aSWarner Losh else { 798e3e3a7aSWarner Losh luaL_checkany(L, 1); 800495ed39SKyle Evans luaL_pushfail(L); /* value is not convertible to integer */ 818e3e3a7aSWarner Losh } 828e3e3a7aSWarner Losh return 1; 838e3e3a7aSWarner Losh } 848e3e3a7aSWarner Losh 858e3e3a7aSWarner Losh 868e3e3a7aSWarner Losh static void pushnumint (lua_State *L, lua_Number d) { 878e3e3a7aSWarner Losh lua_Integer n; 888e3e3a7aSWarner Losh if (lua_numbertointeger(d, &n)) /* does 'd' fit in an integer? */ 898e3e3a7aSWarner Losh lua_pushinteger(L, n); /* result is integer */ 908e3e3a7aSWarner Losh else 918e3e3a7aSWarner Losh lua_pushnumber(L, d); /* result is float */ 928e3e3a7aSWarner Losh } 938e3e3a7aSWarner Losh 948e3e3a7aSWarner Losh 958e3e3a7aSWarner Losh static int math_floor (lua_State *L) { 968e3e3a7aSWarner Losh if (lua_isinteger(L, 1)) 978e3e3a7aSWarner Losh lua_settop(L, 1); /* integer is its own floor */ 988e3e3a7aSWarner Losh else { 998e3e3a7aSWarner Losh lua_Number d = l_mathop(floor)(luaL_checknumber(L, 1)); 1008e3e3a7aSWarner Losh pushnumint(L, d); 1018e3e3a7aSWarner Losh } 1028e3e3a7aSWarner Losh return 1; 1038e3e3a7aSWarner Losh } 1048e3e3a7aSWarner Losh 1058e3e3a7aSWarner Losh 1068e3e3a7aSWarner Losh static int math_ceil (lua_State *L) { 1078e3e3a7aSWarner Losh if (lua_isinteger(L, 1)) 1088e3e3a7aSWarner Losh lua_settop(L, 1); /* integer is its own ceil */ 1098e3e3a7aSWarner Losh else { 1108e3e3a7aSWarner Losh lua_Number d = l_mathop(ceil)(luaL_checknumber(L, 1)); 1118e3e3a7aSWarner Losh pushnumint(L, d); 1128e3e3a7aSWarner Losh } 1138e3e3a7aSWarner Losh return 1; 1148e3e3a7aSWarner Losh } 1158e3e3a7aSWarner Losh 1168e3e3a7aSWarner Losh 1178e3e3a7aSWarner Losh static int math_fmod (lua_State *L) { 1188e3e3a7aSWarner Losh if (lua_isinteger(L, 1) && lua_isinteger(L, 2)) { 1198e3e3a7aSWarner Losh lua_Integer d = lua_tointeger(L, 2); 1208e3e3a7aSWarner Losh if ((lua_Unsigned)d + 1u <= 1u) { /* special cases: -1 or 0 */ 1218e3e3a7aSWarner Losh luaL_argcheck(L, d != 0, 2, "zero"); 1228e3e3a7aSWarner Losh lua_pushinteger(L, 0); /* avoid overflow with 0x80000... / -1 */ 1238e3e3a7aSWarner Losh } 1248e3e3a7aSWarner Losh else 1258e3e3a7aSWarner Losh lua_pushinteger(L, lua_tointeger(L, 1) % d); 1268e3e3a7aSWarner Losh } 1278e3e3a7aSWarner Losh else 1288e3e3a7aSWarner Losh lua_pushnumber(L, l_mathop(fmod)(luaL_checknumber(L, 1), 1298e3e3a7aSWarner Losh luaL_checknumber(L, 2))); 1308e3e3a7aSWarner Losh return 1; 1318e3e3a7aSWarner Losh } 1328e3e3a7aSWarner Losh 1338e3e3a7aSWarner Losh 1348e3e3a7aSWarner Losh /* 1358e3e3a7aSWarner Losh ** next function does not use 'modf', avoiding problems with 'double*' 1368e3e3a7aSWarner Losh ** (which is not compatible with 'float*') when lua_Number is not 1378e3e3a7aSWarner Losh ** 'double'. 1388e3e3a7aSWarner Losh */ 1398e3e3a7aSWarner Losh static int math_modf (lua_State *L) { 1408e3e3a7aSWarner Losh if (lua_isinteger(L ,1)) { 1418e3e3a7aSWarner Losh lua_settop(L, 1); /* number is its own integer part */ 1428e3e3a7aSWarner Losh lua_pushnumber(L, 0); /* no fractional part */ 1438e3e3a7aSWarner Losh } 1448e3e3a7aSWarner Losh else { 1458e3e3a7aSWarner Losh lua_Number n = luaL_checknumber(L, 1); 1468e3e3a7aSWarner Losh /* integer part (rounds toward zero) */ 1478e3e3a7aSWarner Losh lua_Number ip = (n < 0) ? l_mathop(ceil)(n) : l_mathop(floor)(n); 1488e3e3a7aSWarner Losh pushnumint(L, ip); 1498e3e3a7aSWarner Losh /* fractional part (test needed for inf/-inf) */ 1508e3e3a7aSWarner Losh lua_pushnumber(L, (n == ip) ? l_mathop(0.0) : (n - ip)); 1518e3e3a7aSWarner Losh } 1528e3e3a7aSWarner Losh return 2; 1538e3e3a7aSWarner Losh } 1548e3e3a7aSWarner Losh 1558e3e3a7aSWarner Losh 1568e3e3a7aSWarner Losh static int math_sqrt (lua_State *L) { 1578e3e3a7aSWarner Losh lua_pushnumber(L, l_mathop(sqrt)(luaL_checknumber(L, 1))); 1588e3e3a7aSWarner Losh return 1; 1598e3e3a7aSWarner Losh } 1608e3e3a7aSWarner Losh 1618e3e3a7aSWarner Losh 1628e3e3a7aSWarner Losh static int math_ult (lua_State *L) { 1638e3e3a7aSWarner Losh lua_Integer a = luaL_checkinteger(L, 1); 1648e3e3a7aSWarner Losh lua_Integer b = luaL_checkinteger(L, 2); 1658e3e3a7aSWarner Losh lua_pushboolean(L, (lua_Unsigned)a < (lua_Unsigned)b); 1668e3e3a7aSWarner Losh return 1; 1678e3e3a7aSWarner Losh } 1688e3e3a7aSWarner Losh 1698e3e3a7aSWarner Losh static int math_log (lua_State *L) { 1708e3e3a7aSWarner Losh lua_Number x = luaL_checknumber(L, 1); 1718e3e3a7aSWarner Losh lua_Number res; 1728e3e3a7aSWarner Losh if (lua_isnoneornil(L, 2)) 1738e3e3a7aSWarner Losh res = l_mathop(log)(x); 1748e3e3a7aSWarner Losh else { 1758e3e3a7aSWarner Losh lua_Number base = luaL_checknumber(L, 2); 1768e3e3a7aSWarner Losh #if !defined(LUA_USE_C89) 1778e3e3a7aSWarner Losh if (base == l_mathop(2.0)) 178*8c784bb8SWarner Losh res = l_mathop(log2)(x); 179*8c784bb8SWarner Losh else 1808e3e3a7aSWarner Losh #endif 1818e3e3a7aSWarner Losh if (base == l_mathop(10.0)) 1828e3e3a7aSWarner Losh res = l_mathop(log10)(x); 1838e3e3a7aSWarner Losh else 1848e3e3a7aSWarner Losh res = l_mathop(log)(x)/l_mathop(log)(base); 1858e3e3a7aSWarner Losh } 1868e3e3a7aSWarner Losh lua_pushnumber(L, res); 1878e3e3a7aSWarner Losh return 1; 1888e3e3a7aSWarner Losh } 1898e3e3a7aSWarner Losh 1908e3e3a7aSWarner Losh static int math_exp (lua_State *L) { 1918e3e3a7aSWarner Losh lua_pushnumber(L, l_mathop(exp)(luaL_checknumber(L, 1))); 1928e3e3a7aSWarner Losh return 1; 1938e3e3a7aSWarner Losh } 1948e3e3a7aSWarner Losh 1958e3e3a7aSWarner Losh static int math_deg (lua_State *L) { 1968e3e3a7aSWarner Losh lua_pushnumber(L, luaL_checknumber(L, 1) * (l_mathop(180.0) / PI)); 1978e3e3a7aSWarner Losh return 1; 1988e3e3a7aSWarner Losh } 1998e3e3a7aSWarner Losh 2008e3e3a7aSWarner Losh static int math_rad (lua_State *L) { 2018e3e3a7aSWarner Losh lua_pushnumber(L, luaL_checknumber(L, 1) * (PI / l_mathop(180.0))); 2028e3e3a7aSWarner Losh return 1; 2038e3e3a7aSWarner Losh } 2048e3e3a7aSWarner Losh 2058e3e3a7aSWarner Losh 2068e3e3a7aSWarner Losh static int math_min (lua_State *L) { 2078e3e3a7aSWarner Losh int n = lua_gettop(L); /* number of arguments */ 2088e3e3a7aSWarner Losh int imin = 1; /* index of current minimum value */ 2098e3e3a7aSWarner Losh int i; 2108e3e3a7aSWarner Losh luaL_argcheck(L, n >= 1, 1, "value expected"); 2118e3e3a7aSWarner Losh for (i = 2; i <= n; i++) { 2128e3e3a7aSWarner Losh if (lua_compare(L, i, imin, LUA_OPLT)) 2138e3e3a7aSWarner Losh imin = i; 2148e3e3a7aSWarner Losh } 2158e3e3a7aSWarner Losh lua_pushvalue(L, imin); 2168e3e3a7aSWarner Losh return 1; 2178e3e3a7aSWarner Losh } 2188e3e3a7aSWarner Losh 2198e3e3a7aSWarner Losh 2208e3e3a7aSWarner Losh static int math_max (lua_State *L) { 2218e3e3a7aSWarner Losh int n = lua_gettop(L); /* number of arguments */ 2228e3e3a7aSWarner Losh int imax = 1; /* index of current maximum value */ 2238e3e3a7aSWarner Losh int i; 2248e3e3a7aSWarner Losh luaL_argcheck(L, n >= 1, 1, "value expected"); 2258e3e3a7aSWarner Losh for (i = 2; i <= n; i++) { 2268e3e3a7aSWarner Losh if (lua_compare(L, imax, i, LUA_OPLT)) 2278e3e3a7aSWarner Losh imax = i; 2288e3e3a7aSWarner Losh } 2298e3e3a7aSWarner Losh lua_pushvalue(L, imax); 2308e3e3a7aSWarner Losh return 1; 2318e3e3a7aSWarner Losh } 2328e3e3a7aSWarner Losh 2330495ed39SKyle Evans 2340495ed39SKyle Evans static int math_type (lua_State *L) { 2350495ed39SKyle Evans if (lua_type(L, 1) == LUA_TNUMBER) 2360495ed39SKyle Evans lua_pushstring(L, (lua_isinteger(L, 1)) ? "integer" : "float"); 2370495ed39SKyle Evans else { 2380495ed39SKyle Evans luaL_checkany(L, 1); 2390495ed39SKyle Evans luaL_pushfail(L); 2400495ed39SKyle Evans } 2410495ed39SKyle Evans return 1; 2420495ed39SKyle Evans } 2430495ed39SKyle Evans 2440495ed39SKyle Evans 2450495ed39SKyle Evans 2468e3e3a7aSWarner Losh /* 2470495ed39SKyle Evans ** {================================================================== 2480495ed39SKyle Evans ** Pseudo-Random Number Generator based on 'xoshiro256**'. 2490495ed39SKyle Evans ** =================================================================== 2508e3e3a7aSWarner Losh */ 2510495ed39SKyle Evans 2520495ed39SKyle Evans /* number of binary digits in the mantissa of a float */ 2530495ed39SKyle Evans #define FIGS l_floatatt(MANT_DIG) 2540495ed39SKyle Evans 2550495ed39SKyle Evans #if FIGS > 64 2560495ed39SKyle Evans /* there are only 64 random bits; use them all */ 2570495ed39SKyle Evans #undef FIGS 2580495ed39SKyle Evans #define FIGS 64 2590495ed39SKyle Evans #endif 2600495ed39SKyle Evans 2610495ed39SKyle Evans 2620495ed39SKyle Evans /* 2630495ed39SKyle Evans ** LUA_RAND32 forces the use of 32-bit integers in the implementation 2640495ed39SKyle Evans ** of the PRN generator (mainly for testing). 2650495ed39SKyle Evans */ 2660495ed39SKyle Evans #if !defined(LUA_RAND32) && !defined(Rand64) 2670495ed39SKyle Evans 2680495ed39SKyle Evans /* try to find an integer type with at least 64 bits */ 2690495ed39SKyle Evans 2700495ed39SKyle Evans #if (ULONG_MAX >> 31 >> 31) >= 3 2710495ed39SKyle Evans 2720495ed39SKyle Evans /* 'long' has at least 64 bits */ 2730495ed39SKyle Evans #define Rand64 unsigned long 2740495ed39SKyle Evans 2750495ed39SKyle Evans #elif !defined(LUA_USE_C89) && defined(LLONG_MAX) 2760495ed39SKyle Evans 2770495ed39SKyle Evans /* there is a 'long long' type (which must have at least 64 bits) */ 2780495ed39SKyle Evans #define Rand64 unsigned long long 2790495ed39SKyle Evans 2800495ed39SKyle Evans #elif (LUA_MAXUNSIGNED >> 31 >> 31) >= 3 2810495ed39SKyle Evans 2820495ed39SKyle Evans /* 'lua_Integer' has at least 64 bits */ 2830495ed39SKyle Evans #define Rand64 lua_Unsigned 2840495ed39SKyle Evans 2850495ed39SKyle Evans #endif 2860495ed39SKyle Evans 2870495ed39SKyle Evans #endif 2880495ed39SKyle Evans 2890495ed39SKyle Evans 2900495ed39SKyle Evans #if defined(Rand64) /* { */ 2910495ed39SKyle Evans 2920495ed39SKyle Evans /* 2930495ed39SKyle Evans ** Standard implementation, using 64-bit integers. 2940495ed39SKyle Evans ** If 'Rand64' has more than 64 bits, the extra bits do not interfere 2950495ed39SKyle Evans ** with the 64 initial bits, except in a right shift. Moreover, the 2960495ed39SKyle Evans ** final result has to discard the extra bits. 2970495ed39SKyle Evans */ 2980495ed39SKyle Evans 2990495ed39SKyle Evans /* avoid using extra bits when needed */ 3000495ed39SKyle Evans #define trim64(x) ((x) & 0xffffffffffffffffu) 3010495ed39SKyle Evans 3020495ed39SKyle Evans 3030495ed39SKyle Evans /* rotate left 'x' by 'n' bits */ 3040495ed39SKyle Evans static Rand64 rotl (Rand64 x, int n) { 3050495ed39SKyle Evans return (x << n) | (trim64(x) >> (64 - n)); 3060495ed39SKyle Evans } 3070495ed39SKyle Evans 3080495ed39SKyle Evans static Rand64 nextrand (Rand64 *state) { 3090495ed39SKyle Evans Rand64 state0 = state[0]; 3100495ed39SKyle Evans Rand64 state1 = state[1]; 3110495ed39SKyle Evans Rand64 state2 = state[2] ^ state0; 3120495ed39SKyle Evans Rand64 state3 = state[3] ^ state1; 3130495ed39SKyle Evans Rand64 res = rotl(state1 * 5, 7) * 9; 3140495ed39SKyle Evans state[0] = state0 ^ state3; 3150495ed39SKyle Evans state[1] = state1 ^ state2; 3160495ed39SKyle Evans state[2] = state2 ^ (state1 << 17); 3170495ed39SKyle Evans state[3] = rotl(state3, 45); 3180495ed39SKyle Evans return res; 3190495ed39SKyle Evans } 3200495ed39SKyle Evans 3210495ed39SKyle Evans 3220495ed39SKyle Evans /* must take care to not shift stuff by more than 63 slots */ 3230495ed39SKyle Evans 3240495ed39SKyle Evans 3250495ed39SKyle Evans /* 3260495ed39SKyle Evans ** Convert bits from a random integer into a float in the 3270495ed39SKyle Evans ** interval [0,1), getting the higher FIG bits from the 3280495ed39SKyle Evans ** random unsigned integer and converting that to a float. 3290495ed39SKyle Evans */ 3300495ed39SKyle Evans 3310495ed39SKyle Evans /* must throw out the extra (64 - FIGS) bits */ 3320495ed39SKyle Evans #define shift64_FIG (64 - FIGS) 3330495ed39SKyle Evans 3340495ed39SKyle Evans /* to scale to [0, 1), multiply by scaleFIG = 2^(-FIGS) */ 3350495ed39SKyle Evans #define scaleFIG (l_mathop(0.5) / ((Rand64)1 << (FIGS - 1))) 3360495ed39SKyle Evans 3370495ed39SKyle Evans static lua_Number I2d (Rand64 x) { 3380495ed39SKyle Evans return (lua_Number)(trim64(x) >> shift64_FIG) * scaleFIG; 3390495ed39SKyle Evans } 3400495ed39SKyle Evans 3410495ed39SKyle Evans /* convert a 'Rand64' to a 'lua_Unsigned' */ 3420495ed39SKyle Evans #define I2UInt(x) ((lua_Unsigned)trim64(x)) 3430495ed39SKyle Evans 3440495ed39SKyle Evans /* convert a 'lua_Unsigned' to a 'Rand64' */ 3450495ed39SKyle Evans #define Int2I(x) ((Rand64)(x)) 3460495ed39SKyle Evans 3470495ed39SKyle Evans 3480495ed39SKyle Evans #else /* no 'Rand64' }{ */ 3490495ed39SKyle Evans 3500495ed39SKyle Evans /* get an integer with at least 32 bits */ 3510495ed39SKyle Evans #if LUAI_IS32INT 3520495ed39SKyle Evans typedef unsigned int lu_int32; 3530495ed39SKyle Evans #else 3540495ed39SKyle Evans typedef unsigned long lu_int32; 3550495ed39SKyle Evans #endif 3560495ed39SKyle Evans 3570495ed39SKyle Evans 3580495ed39SKyle Evans /* 3590495ed39SKyle Evans ** Use two 32-bit integers to represent a 64-bit quantity. 3600495ed39SKyle Evans */ 3610495ed39SKyle Evans typedef struct Rand64 { 3620495ed39SKyle Evans lu_int32 h; /* higher half */ 3630495ed39SKyle Evans lu_int32 l; /* lower half */ 3640495ed39SKyle Evans } Rand64; 3650495ed39SKyle Evans 3660495ed39SKyle Evans 3670495ed39SKyle Evans /* 3680495ed39SKyle Evans ** If 'lu_int32' has more than 32 bits, the extra bits do not interfere 3690495ed39SKyle Evans ** with the 32 initial bits, except in a right shift and comparisons. 3700495ed39SKyle Evans ** Moreover, the final result has to discard the extra bits. 3710495ed39SKyle Evans */ 3720495ed39SKyle Evans 3730495ed39SKyle Evans /* avoid using extra bits when needed */ 3740495ed39SKyle Evans #define trim32(x) ((x) & 0xffffffffu) 3750495ed39SKyle Evans 3760495ed39SKyle Evans 3770495ed39SKyle Evans /* 3780495ed39SKyle Evans ** basic operations on 'Rand64' values 3790495ed39SKyle Evans */ 3800495ed39SKyle Evans 3810495ed39SKyle Evans /* build a new Rand64 value */ 3820495ed39SKyle Evans static Rand64 packI (lu_int32 h, lu_int32 l) { 3830495ed39SKyle Evans Rand64 result; 3840495ed39SKyle Evans result.h = h; 3850495ed39SKyle Evans result.l = l; 3860495ed39SKyle Evans return result; 3870495ed39SKyle Evans } 3880495ed39SKyle Evans 3890495ed39SKyle Evans /* return i << n */ 3900495ed39SKyle Evans static Rand64 Ishl (Rand64 i, int n) { 3910495ed39SKyle Evans lua_assert(n > 0 && n < 32); 3920495ed39SKyle Evans return packI((i.h << n) | (trim32(i.l) >> (32 - n)), i.l << n); 3930495ed39SKyle Evans } 3940495ed39SKyle Evans 3950495ed39SKyle Evans /* i1 ^= i2 */ 3960495ed39SKyle Evans static void Ixor (Rand64 *i1, Rand64 i2) { 3970495ed39SKyle Evans i1->h ^= i2.h; 3980495ed39SKyle Evans i1->l ^= i2.l; 3990495ed39SKyle Evans } 4000495ed39SKyle Evans 4010495ed39SKyle Evans /* return i1 + i2 */ 4020495ed39SKyle Evans static Rand64 Iadd (Rand64 i1, Rand64 i2) { 4030495ed39SKyle Evans Rand64 result = packI(i1.h + i2.h, i1.l + i2.l); 4040495ed39SKyle Evans if (trim32(result.l) < trim32(i1.l)) /* carry? */ 4050495ed39SKyle Evans result.h++; 4060495ed39SKyle Evans return result; 4070495ed39SKyle Evans } 4080495ed39SKyle Evans 4090495ed39SKyle Evans /* return i * 5 */ 4100495ed39SKyle Evans static Rand64 times5 (Rand64 i) { 4110495ed39SKyle Evans return Iadd(Ishl(i, 2), i); /* i * 5 == (i << 2) + i */ 4120495ed39SKyle Evans } 4130495ed39SKyle Evans 4140495ed39SKyle Evans /* return i * 9 */ 4150495ed39SKyle Evans static Rand64 times9 (Rand64 i) { 4160495ed39SKyle Evans return Iadd(Ishl(i, 3), i); /* i * 9 == (i << 3) + i */ 4170495ed39SKyle Evans } 4180495ed39SKyle Evans 4190495ed39SKyle Evans /* return 'i' rotated left 'n' bits */ 4200495ed39SKyle Evans static Rand64 rotl (Rand64 i, int n) { 4210495ed39SKyle Evans lua_assert(n > 0 && n < 32); 4220495ed39SKyle Evans return packI((i.h << n) | (trim32(i.l) >> (32 - n)), 4230495ed39SKyle Evans (trim32(i.h) >> (32 - n)) | (i.l << n)); 4240495ed39SKyle Evans } 4250495ed39SKyle Evans 4260495ed39SKyle Evans /* for offsets larger than 32, rotate right by 64 - offset */ 4270495ed39SKyle Evans static Rand64 rotl1 (Rand64 i, int n) { 4280495ed39SKyle Evans lua_assert(n > 32 && n < 64); 4290495ed39SKyle Evans n = 64 - n; 4300495ed39SKyle Evans return packI((trim32(i.h) >> n) | (i.l << (32 - n)), 4310495ed39SKyle Evans (i.h << (32 - n)) | (trim32(i.l) >> n)); 4320495ed39SKyle Evans } 4330495ed39SKyle Evans 4340495ed39SKyle Evans /* 4350495ed39SKyle Evans ** implementation of 'xoshiro256**' algorithm on 'Rand64' values 4360495ed39SKyle Evans */ 4370495ed39SKyle Evans static Rand64 nextrand (Rand64 *state) { 4380495ed39SKyle Evans Rand64 res = times9(rotl(times5(state[1]), 7)); 4390495ed39SKyle Evans Rand64 t = Ishl(state[1], 17); 4400495ed39SKyle Evans Ixor(&state[2], state[0]); 4410495ed39SKyle Evans Ixor(&state[3], state[1]); 4420495ed39SKyle Evans Ixor(&state[1], state[2]); 4430495ed39SKyle Evans Ixor(&state[0], state[3]); 4440495ed39SKyle Evans Ixor(&state[2], t); 4450495ed39SKyle Evans state[3] = rotl1(state[3], 45); 4460495ed39SKyle Evans return res; 4470495ed39SKyle Evans } 4480495ed39SKyle Evans 4490495ed39SKyle Evans 4500495ed39SKyle Evans /* 4510495ed39SKyle Evans ** Converts a 'Rand64' into a float. 4520495ed39SKyle Evans */ 4530495ed39SKyle Evans 4540495ed39SKyle Evans /* an unsigned 1 with proper type */ 4550495ed39SKyle Evans #define UONE ((lu_int32)1) 4560495ed39SKyle Evans 4570495ed39SKyle Evans 4580495ed39SKyle Evans #if FIGS <= 32 4590495ed39SKyle Evans 4600495ed39SKyle Evans /* 2^(-FIGS) */ 4610495ed39SKyle Evans #define scaleFIG (l_mathop(0.5) / (UONE << (FIGS - 1))) 4620495ed39SKyle Evans 4630495ed39SKyle Evans /* 4640495ed39SKyle Evans ** get up to 32 bits from higher half, shifting right to 4650495ed39SKyle Evans ** throw out the extra bits. 4660495ed39SKyle Evans */ 4670495ed39SKyle Evans static lua_Number I2d (Rand64 x) { 4680495ed39SKyle Evans lua_Number h = (lua_Number)(trim32(x.h) >> (32 - FIGS)); 4690495ed39SKyle Evans return h * scaleFIG; 4700495ed39SKyle Evans } 4710495ed39SKyle Evans 4720495ed39SKyle Evans #else /* 32 < FIGS <= 64 */ 4730495ed39SKyle Evans 4740495ed39SKyle Evans /* must take care to not shift stuff by more than 31 slots */ 4750495ed39SKyle Evans 4760495ed39SKyle Evans /* 2^(-FIGS) = 1.0 / 2^30 / 2^3 / 2^(FIGS-33) */ 4770495ed39SKyle Evans #define scaleFIG \ 478*8c784bb8SWarner Losh (l_mathop(1.0) / (UONE << 30) / l_mathop(8.0) / (UONE << (FIGS - 33))) 4790495ed39SKyle Evans 4800495ed39SKyle Evans /* 4810495ed39SKyle Evans ** use FIGS - 32 bits from lower half, throwing out the other 4820495ed39SKyle Evans ** (32 - (FIGS - 32)) = (64 - FIGS) bits 4830495ed39SKyle Evans */ 4840495ed39SKyle Evans #define shiftLOW (64 - FIGS) 4850495ed39SKyle Evans 4860495ed39SKyle Evans /* 4870495ed39SKyle Evans ** higher 32 bits go after those (FIGS - 32) bits: shiftHI = 2^(FIGS - 32) 4880495ed39SKyle Evans */ 489*8c784bb8SWarner Losh #define shiftHI ((lua_Number)(UONE << (FIGS - 33)) * l_mathop(2.0)) 4900495ed39SKyle Evans 4910495ed39SKyle Evans 4920495ed39SKyle Evans static lua_Number I2d (Rand64 x) { 4930495ed39SKyle Evans lua_Number h = (lua_Number)trim32(x.h) * shiftHI; 4940495ed39SKyle Evans lua_Number l = (lua_Number)(trim32(x.l) >> shiftLOW); 4950495ed39SKyle Evans return (h + l) * scaleFIG; 4960495ed39SKyle Evans } 4970495ed39SKyle Evans 4980495ed39SKyle Evans #endif 4990495ed39SKyle Evans 5000495ed39SKyle Evans 5010495ed39SKyle Evans /* convert a 'Rand64' to a 'lua_Unsigned' */ 5020495ed39SKyle Evans static lua_Unsigned I2UInt (Rand64 x) { 5030495ed39SKyle Evans return ((lua_Unsigned)trim32(x.h) << 31 << 1) | (lua_Unsigned)trim32(x.l); 5040495ed39SKyle Evans } 5050495ed39SKyle Evans 5060495ed39SKyle Evans /* convert a 'lua_Unsigned' to a 'Rand64' */ 5070495ed39SKyle Evans static Rand64 Int2I (lua_Unsigned n) { 5080495ed39SKyle Evans return packI((lu_int32)(n >> 31 >> 1), (lu_int32)n); 5090495ed39SKyle Evans } 5100495ed39SKyle Evans 5110495ed39SKyle Evans #endif /* } */ 5120495ed39SKyle Evans 5130495ed39SKyle Evans 5140495ed39SKyle Evans /* 5150495ed39SKyle Evans ** A state uses four 'Rand64' values. 5160495ed39SKyle Evans */ 5170495ed39SKyle Evans typedef struct { 5180495ed39SKyle Evans Rand64 s[4]; 5190495ed39SKyle Evans } RanState; 5200495ed39SKyle Evans 5210495ed39SKyle Evans 5220495ed39SKyle Evans /* 5230495ed39SKyle Evans ** Project the random integer 'ran' into the interval [0, n]. 5240495ed39SKyle Evans ** Because 'ran' has 2^B possible values, the projection can only be 5250495ed39SKyle Evans ** uniform when the size of the interval is a power of 2 (exact 5260495ed39SKyle Evans ** division). Otherwise, to get a uniform projection into [0, n], we 5270495ed39SKyle Evans ** first compute 'lim', the smallest Mersenne number not smaller than 5280495ed39SKyle Evans ** 'n'. We then project 'ran' into the interval [0, lim]. If the result 5290495ed39SKyle Evans ** is inside [0, n], we are done. Otherwise, we try with another 'ran', 5300495ed39SKyle Evans ** until we have a result inside the interval. 5310495ed39SKyle Evans */ 5320495ed39SKyle Evans static lua_Unsigned project (lua_Unsigned ran, lua_Unsigned n, 5330495ed39SKyle Evans RanState *state) { 5340495ed39SKyle Evans if ((n & (n + 1)) == 0) /* is 'n + 1' a power of 2? */ 5350495ed39SKyle Evans return ran & n; /* no bias */ 5360495ed39SKyle Evans else { 5370495ed39SKyle Evans lua_Unsigned lim = n; 5380495ed39SKyle Evans /* compute the smallest (2^b - 1) not smaller than 'n' */ 5390495ed39SKyle Evans lim |= (lim >> 1); 5400495ed39SKyle Evans lim |= (lim >> 2); 5410495ed39SKyle Evans lim |= (lim >> 4); 5420495ed39SKyle Evans lim |= (lim >> 8); 5430495ed39SKyle Evans lim |= (lim >> 16); 5440495ed39SKyle Evans #if (LUA_MAXUNSIGNED >> 31) >= 3 5450495ed39SKyle Evans lim |= (lim >> 32); /* integer type has more than 32 bits */ 5460495ed39SKyle Evans #endif 5470495ed39SKyle Evans lua_assert((lim & (lim + 1)) == 0 /* 'lim + 1' is a power of 2, */ 5480495ed39SKyle Evans && lim >= n /* not smaller than 'n', */ 5490495ed39SKyle Evans && (lim >> 1) < n); /* and it is the smallest one */ 5500495ed39SKyle Evans while ((ran &= lim) > n) /* project 'ran' into [0..lim] */ 5510495ed39SKyle Evans ran = I2UInt(nextrand(state->s)); /* not inside [0..n]? try again */ 5520495ed39SKyle Evans return ran; 5530495ed39SKyle Evans } 5540495ed39SKyle Evans } 5550495ed39SKyle Evans 5560495ed39SKyle Evans 5578e3e3a7aSWarner Losh static int math_random (lua_State *L) { 5588e3e3a7aSWarner Losh lua_Integer low, up; 5590495ed39SKyle Evans lua_Unsigned p; 5600495ed39SKyle Evans RanState *state = (RanState *)lua_touserdata(L, lua_upvalueindex(1)); 5610495ed39SKyle Evans Rand64 rv = nextrand(state->s); /* next pseudo-random value */ 5628e3e3a7aSWarner Losh switch (lua_gettop(L)) { /* check number of arguments */ 5638e3e3a7aSWarner Losh case 0: { /* no arguments */ 5640495ed39SKyle Evans lua_pushnumber(L, I2d(rv)); /* float between 0 and 1 */ 5658e3e3a7aSWarner Losh return 1; 5668e3e3a7aSWarner Losh } 5678e3e3a7aSWarner Losh case 1: { /* only upper limit */ 5688e3e3a7aSWarner Losh low = 1; 5698e3e3a7aSWarner Losh up = luaL_checkinteger(L, 1); 5700495ed39SKyle Evans if (up == 0) { /* single 0 as argument? */ 5710495ed39SKyle Evans lua_pushinteger(L, I2UInt(rv)); /* full random integer */ 5720495ed39SKyle Evans return 1; 5730495ed39SKyle Evans } 5748e3e3a7aSWarner Losh break; 5758e3e3a7aSWarner Losh } 5768e3e3a7aSWarner Losh case 2: { /* lower and upper limits */ 5778e3e3a7aSWarner Losh low = luaL_checkinteger(L, 1); 5788e3e3a7aSWarner Losh up = luaL_checkinteger(L, 2); 5798e3e3a7aSWarner Losh break; 5808e3e3a7aSWarner Losh } 5818e3e3a7aSWarner Losh default: return luaL_error(L, "wrong number of arguments"); 5828e3e3a7aSWarner Losh } 5838e3e3a7aSWarner Losh /* random integer in the interval [low, up] */ 5848e3e3a7aSWarner Losh luaL_argcheck(L, low <= up, 1, "interval is empty"); 5850495ed39SKyle Evans /* project random integer into the interval [0, up - low] */ 5860495ed39SKyle Evans p = project(I2UInt(rv), (lua_Unsigned)up - (lua_Unsigned)low, state); 5870495ed39SKyle Evans lua_pushinteger(L, p + (lua_Unsigned)low); 5888e3e3a7aSWarner Losh return 1; 5898e3e3a7aSWarner Losh } 5908e3e3a7aSWarner Losh 5918e3e3a7aSWarner Losh 5920495ed39SKyle Evans static void setseed (lua_State *L, Rand64 *state, 5930495ed39SKyle Evans lua_Unsigned n1, lua_Unsigned n2) { 5940495ed39SKyle Evans int i; 5950495ed39SKyle Evans state[0] = Int2I(n1); 5960495ed39SKyle Evans state[1] = Int2I(0xff); /* avoid a zero state */ 5970495ed39SKyle Evans state[2] = Int2I(n2); 5980495ed39SKyle Evans state[3] = Int2I(0); 5990495ed39SKyle Evans for (i = 0; i < 16; i++) 6000495ed39SKyle Evans nextrand(state); /* discard initial values to "spread" seed */ 6010495ed39SKyle Evans lua_pushinteger(L, n1); 6020495ed39SKyle Evans lua_pushinteger(L, n2); 6030495ed39SKyle Evans } 6040495ed39SKyle Evans 6050495ed39SKyle Evans 6060495ed39SKyle Evans /* 6070495ed39SKyle Evans ** Set a "random" seed. To get some randomness, use the current time 6080495ed39SKyle Evans ** and the address of 'L' (in case the machine does address space layout 6090495ed39SKyle Evans ** randomization). 6100495ed39SKyle Evans */ 6110495ed39SKyle Evans static void randseed (lua_State *L, RanState *state) { 6120495ed39SKyle Evans lua_Unsigned seed1 = (lua_Unsigned)time(NULL); 6130495ed39SKyle Evans lua_Unsigned seed2 = (lua_Unsigned)(size_t)L; 6140495ed39SKyle Evans setseed(L, state->s, seed1, seed2); 6150495ed39SKyle Evans } 6160495ed39SKyle Evans 6170495ed39SKyle Evans 6188e3e3a7aSWarner Losh static int math_randomseed (lua_State *L) { 6190495ed39SKyle Evans RanState *state = (RanState *)lua_touserdata(L, lua_upvalueindex(1)); 6200495ed39SKyle Evans if (lua_isnone(L, 1)) { 6210495ed39SKyle Evans randseed(L, state); 6228e3e3a7aSWarner Losh } 6238e3e3a7aSWarner Losh else { 6240495ed39SKyle Evans lua_Integer n1 = luaL_checkinteger(L, 1); 6250495ed39SKyle Evans lua_Integer n2 = luaL_optinteger(L, 2, 0); 6260495ed39SKyle Evans setseed(L, state->s, n1, n2); 6278e3e3a7aSWarner Losh } 6280495ed39SKyle Evans return 2; /* return seeds */ 6298e3e3a7aSWarner Losh } 6308e3e3a7aSWarner Losh 6318e3e3a7aSWarner Losh 6320495ed39SKyle Evans static const luaL_Reg randfuncs[] = { 6330495ed39SKyle Evans {"random", math_random}, 6340495ed39SKyle Evans {"randomseed", math_randomseed}, 6350495ed39SKyle Evans {NULL, NULL} 6360495ed39SKyle Evans }; 6370495ed39SKyle Evans 6380495ed39SKyle Evans 6390495ed39SKyle Evans /* 6400495ed39SKyle Evans ** Register the random functions and initialize their state. 6410495ed39SKyle Evans */ 6420495ed39SKyle Evans static void setrandfunc (lua_State *L) { 6430495ed39SKyle Evans RanState *state = (RanState *)lua_newuserdatauv(L, sizeof(RanState), 0); 6440495ed39SKyle Evans randseed(L, state); /* initialize with a "random" seed */ 6450495ed39SKyle Evans lua_pop(L, 2); /* remove pushed seeds */ 6460495ed39SKyle Evans luaL_setfuncs(L, randfuncs, 1); 6470495ed39SKyle Evans } 6480495ed39SKyle Evans 6490495ed39SKyle Evans /* }================================================================== */ 6500495ed39SKyle Evans 6510495ed39SKyle Evans 6528e3e3a7aSWarner Losh /* 6538e3e3a7aSWarner Losh ** {================================================================== 6548e3e3a7aSWarner Losh ** Deprecated functions (for compatibility only) 6558e3e3a7aSWarner Losh ** =================================================================== 6568e3e3a7aSWarner Losh */ 6578e3e3a7aSWarner Losh #if defined(LUA_COMPAT_MATHLIB) 6588e3e3a7aSWarner Losh 6598e3e3a7aSWarner Losh static int math_cosh (lua_State *L) { 6608e3e3a7aSWarner Losh lua_pushnumber(L, l_mathop(cosh)(luaL_checknumber(L, 1))); 6618e3e3a7aSWarner Losh return 1; 6628e3e3a7aSWarner Losh } 6638e3e3a7aSWarner Losh 6648e3e3a7aSWarner Losh static int math_sinh (lua_State *L) { 6658e3e3a7aSWarner Losh lua_pushnumber(L, l_mathop(sinh)(luaL_checknumber(L, 1))); 6668e3e3a7aSWarner Losh return 1; 6678e3e3a7aSWarner Losh } 6688e3e3a7aSWarner Losh 6698e3e3a7aSWarner Losh static int math_tanh (lua_State *L) { 6708e3e3a7aSWarner Losh lua_pushnumber(L, l_mathop(tanh)(luaL_checknumber(L, 1))); 6718e3e3a7aSWarner Losh return 1; 6728e3e3a7aSWarner Losh } 6738e3e3a7aSWarner Losh 6748e3e3a7aSWarner Losh static int math_pow (lua_State *L) { 6758e3e3a7aSWarner Losh lua_Number x = luaL_checknumber(L, 1); 6768e3e3a7aSWarner Losh lua_Number y = luaL_checknumber(L, 2); 6778e3e3a7aSWarner Losh lua_pushnumber(L, l_mathop(pow)(x, y)); 6788e3e3a7aSWarner Losh return 1; 6798e3e3a7aSWarner Losh } 6808e3e3a7aSWarner Losh 6818e3e3a7aSWarner Losh static int math_frexp (lua_State *L) { 6828e3e3a7aSWarner Losh int e; 6838e3e3a7aSWarner Losh lua_pushnumber(L, l_mathop(frexp)(luaL_checknumber(L, 1), &e)); 6848e3e3a7aSWarner Losh lua_pushinteger(L, e); 6858e3e3a7aSWarner Losh return 2; 6868e3e3a7aSWarner Losh } 6878e3e3a7aSWarner Losh 6888e3e3a7aSWarner Losh static int math_ldexp (lua_State *L) { 6898e3e3a7aSWarner Losh lua_Number x = luaL_checknumber(L, 1); 6908e3e3a7aSWarner Losh int ep = (int)luaL_checkinteger(L, 2); 6918e3e3a7aSWarner Losh lua_pushnumber(L, l_mathop(ldexp)(x, ep)); 6928e3e3a7aSWarner Losh return 1; 6938e3e3a7aSWarner Losh } 6948e3e3a7aSWarner Losh 6958e3e3a7aSWarner Losh static int math_log10 (lua_State *L) { 6968e3e3a7aSWarner Losh lua_pushnumber(L, l_mathop(log10)(luaL_checknumber(L, 1))); 6978e3e3a7aSWarner Losh return 1; 6988e3e3a7aSWarner Losh } 6998e3e3a7aSWarner Losh 7008e3e3a7aSWarner Losh #endif 7018e3e3a7aSWarner Losh /* }================================================================== */ 7028e3e3a7aSWarner Losh 7038e3e3a7aSWarner Losh 7048e3e3a7aSWarner Losh 7058e3e3a7aSWarner Losh static const luaL_Reg mathlib[] = { 7068e3e3a7aSWarner Losh {"abs", math_abs}, 7078e3e3a7aSWarner Losh {"acos", math_acos}, 7088e3e3a7aSWarner Losh {"asin", math_asin}, 7098e3e3a7aSWarner Losh {"atan", math_atan}, 7108e3e3a7aSWarner Losh {"ceil", math_ceil}, 7118e3e3a7aSWarner Losh {"cos", math_cos}, 7128e3e3a7aSWarner Losh {"deg", math_deg}, 7138e3e3a7aSWarner Losh {"exp", math_exp}, 7148e3e3a7aSWarner Losh {"tointeger", math_toint}, 7158e3e3a7aSWarner Losh {"floor", math_floor}, 7168e3e3a7aSWarner Losh {"fmod", math_fmod}, 7178e3e3a7aSWarner Losh {"ult", math_ult}, 7188e3e3a7aSWarner Losh {"log", math_log}, 7198e3e3a7aSWarner Losh {"max", math_max}, 7208e3e3a7aSWarner Losh {"min", math_min}, 7218e3e3a7aSWarner Losh {"modf", math_modf}, 7228e3e3a7aSWarner Losh {"rad", math_rad}, 7238e3e3a7aSWarner Losh {"sin", math_sin}, 7248e3e3a7aSWarner Losh {"sqrt", math_sqrt}, 7258e3e3a7aSWarner Losh {"tan", math_tan}, 7268e3e3a7aSWarner Losh {"type", math_type}, 7278e3e3a7aSWarner Losh #if defined(LUA_COMPAT_MATHLIB) 7288e3e3a7aSWarner Losh {"atan2", math_atan}, 7298e3e3a7aSWarner Losh {"cosh", math_cosh}, 7308e3e3a7aSWarner Losh {"sinh", math_sinh}, 7318e3e3a7aSWarner Losh {"tanh", math_tanh}, 7328e3e3a7aSWarner Losh {"pow", math_pow}, 7338e3e3a7aSWarner Losh {"frexp", math_frexp}, 7348e3e3a7aSWarner Losh {"ldexp", math_ldexp}, 7358e3e3a7aSWarner Losh {"log10", math_log10}, 7368e3e3a7aSWarner Losh #endif 7378e3e3a7aSWarner Losh /* placeholders */ 7380495ed39SKyle Evans {"random", NULL}, 7390495ed39SKyle Evans {"randomseed", NULL}, 7408e3e3a7aSWarner Losh {"pi", NULL}, 7418e3e3a7aSWarner Losh {"huge", NULL}, 7428e3e3a7aSWarner Losh {"maxinteger", NULL}, 7438e3e3a7aSWarner Losh {"mininteger", NULL}, 7448e3e3a7aSWarner Losh {NULL, NULL} 7458e3e3a7aSWarner Losh }; 7468e3e3a7aSWarner Losh 7478e3e3a7aSWarner Losh 7488e3e3a7aSWarner Losh /* 7498e3e3a7aSWarner Losh ** Open math library 7508e3e3a7aSWarner Losh */ 7518e3e3a7aSWarner Losh LUAMOD_API int luaopen_math (lua_State *L) { 7528e3e3a7aSWarner Losh luaL_newlib(L, mathlib); 7538e3e3a7aSWarner Losh lua_pushnumber(L, PI); 7548e3e3a7aSWarner Losh lua_setfield(L, -2, "pi"); 7558e3e3a7aSWarner Losh lua_pushnumber(L, (lua_Number)HUGE_VAL); 7568e3e3a7aSWarner Losh lua_setfield(L, -2, "huge"); 7578e3e3a7aSWarner Losh lua_pushinteger(L, LUA_MAXINTEGER); 7588e3e3a7aSWarner Losh lua_setfield(L, -2, "maxinteger"); 7598e3e3a7aSWarner Losh lua_pushinteger(L, LUA_MININTEGER); 7608e3e3a7aSWarner Losh lua_setfield(L, -2, "mininteger"); 7610495ed39SKyle Evans setrandfunc(L); 7628e3e3a7aSWarner Losh return 1; 7638e3e3a7aSWarner Losh } 7648e3e3a7aSWarner Losh 765