ljx

FORK: LuaJIT with native 5.2 and 5.3 support
git clone https://git.neptards.moe/neptards/ljx.git
Log | Files | Refs | README

lib_math.c (6178B)


      1 /*
      2 ** Math library.
      3 ** Copyright (C) 2005-2016 Mike Pall. See Copyright Notice in luajit.h
      4 */
      5 
      6 #include <math.h>
      7 
      8 #define lib_math_c
      9 #define LUA_LIB
     10 
     11 #include "lua.h"
     12 #include "lauxlib.h"
     13 #include "lualib.h"
     14 
     15 #include "lj_obj.h"
     16 #include "lj_lib.h"
     17 #include "lj_vm.h"
     18 
     19 /* ------------------------------------------------------------------------ */
     20 
     21 #define LJLIB_MODULE_math
     22 
     23 LJLIB_ASM(math_abs)		LJLIB_REC(.)
     24 {
     25   lj_lib_checknumber(L, 1);
     26   return FFH_RETRY;
     27 }
     28 LJLIB_ASM_(math_floor)		LJLIB_REC(math_round IRFPM_FLOOR)
     29 LJLIB_ASM_(math_ceil)		LJLIB_REC(math_round IRFPM_CEIL)
     30 
     31 LJLIB_ASM(math_sqrt)		LJLIB_REC(math_unary IRFPM_SQRT)
     32 {
     33   lj_lib_checknum(L, 1);
     34   return FFH_RETRY;
     35 }
     36 LJLIB_ASM_(math_log10)		LJLIB_REC(math_unary IRFPM_LOG10)
     37 LJLIB_ASM_(math_exp)		LJLIB_REC(math_unary IRFPM_EXP)
     38 LJLIB_ASM_(math_sin)		LJLIB_REC(math_unary IRFPM_SIN)
     39 LJLIB_ASM_(math_cos)		LJLIB_REC(math_unary IRFPM_COS)
     40 LJLIB_ASM_(math_tan)		LJLIB_REC(math_unary IRFPM_TAN)
     41 LJLIB_ASM_(math_asin)		LJLIB_REC(math_atrig FF_math_asin)
     42 LJLIB_ASM_(math_acos)		LJLIB_REC(math_atrig FF_math_acos)
     43 LJLIB_ASM_(math_atan)		LJLIB_REC(math_atrig FF_math_atan)
     44 LJLIB_ASM_(math_sinh)		LJLIB_REC(math_htrig IRCALL_sinh)
     45 LJLIB_ASM_(math_cosh)		LJLIB_REC(math_htrig IRCALL_cosh)
     46 LJLIB_ASM_(math_tanh)		LJLIB_REC(math_htrig IRCALL_tanh)
     47 LJLIB_ASM_(math_frexp)
     48 LJLIB_ASM_(math_modf)		LJLIB_REC(.)
     49 
     50 LJLIB_ASM(math_log)		LJLIB_REC(math_log)
     51 {
     52   double x = lj_lib_checknum(L, 1);
     53   if (L->base+1 < L->top) {
     54     double y = lj_lib_checknum(L, 2);
     55 #ifdef LUAJIT_NO_LOG2
     56     x = log(x); y = 1.0 / log(y);
     57 #else
     58     x = lj_vm_log2(x); y = 1.0 / lj_vm_log2(y);
     59 #endif
     60     setnumV(L->base-1-LJ_FR2, x*y);  /* Do NOT join the expression to x / y. */
     61     return FFH_RES(1);
     62   }
     63   return FFH_RETRY;
     64 }
     65 
     66 LJLIB_LUA(math_deg) /* function(x) return x * 57.29577951308232 end */
     67 LJLIB_LUA(math_rad) /* function(x) return x * 0.017453292519943295 end */
     68 
     69 LJLIB_ASM(math_atan2)		LJLIB_REC(.)
     70 {
     71   lj_lib_checknum(L, 1);
     72   lj_lib_checknum(L, 2);
     73   return FFH_RETRY;
     74 }
     75 LJLIB_ASM_(math_pow)		LJLIB_REC(.)
     76 LJLIB_ASM_(math_fmod)
     77 
     78 LJLIB_ASM(math_ldexp)		LJLIB_REC(.)
     79 {
     80   lj_lib_checknum(L, 1);
     81 #if LJ_DUALNUM && !LJ_TARGET_X86ORX64
     82   lj_lib_checkint(L, 2);
     83 #else
     84   lj_lib_checknum(L, 2);
     85 #endif
     86   return FFH_RETRY;
     87 }
     88 
     89 LJLIB_ASM(math_min)		LJLIB_REC(math_minmax IR_MIN)
     90 {
     91   int i = 0;
     92   do { lj_lib_checknumber(L, ++i); } while (L->base+i < L->top);
     93   return FFH_RETRY;
     94 }
     95 LJLIB_ASM_(math_max)		LJLIB_REC(math_minmax IR_MAX)
     96 
     97 LJLIB_PUSH(3.14159265358979323846) LJLIB_SET(pi)
     98 LJLIB_PUSH(1e310) LJLIB_SET(huge)
     99 
    100 /* ------------------------------------------------------------------------ */
    101 
    102 /* This implements a Tausworthe PRNG with period 2^223. Based on:
    103 **   Tables of maximally-equidistributed combined LFSR generators,
    104 **   Pierre L'Ecuyer, 1991, table 3, 1st entry.
    105 ** Full-period ME-CF generator with L=64, J=4, k=223, N1=49.
    106 */
    107 
    108 /* PRNG state. */
    109 struct RandomState {
    110   uint64_t gen[4];	/* State of the 4 LFSR generators. */
    111   int valid;		/* State is valid. */
    112 };
    113 
    114 /* Union needed for bit-pattern conversion between uint64_t and double. */
    115 typedef union { uint64_t u64; double d; } U64double;
    116 
    117 /* Update generator i and compute a running xor of all states. */
    118 #define TW223_GEN(i, k, q, s) \
    119   z = rs->gen[i]; \
    120   z = (((z<<q)^z) >> (k-s)) ^ ((z&((uint64_t)(int64_t)-1 << (64-k)))<<s); \
    121   r ^= z; rs->gen[i] = z;
    122 
    123 /* PRNG step function. Returns a double in the range 1.0 <= d < 2.0. */
    124 LJ_NOINLINE uint64_t LJ_FASTCALL lj_math_random_step(RandomState *rs)
    125 {
    126   uint64_t z, r = 0;
    127   TW223_GEN(0, 63, 31, 18)
    128   TW223_GEN(1, 58, 19, 28)
    129   TW223_GEN(2, 55, 24,  7)
    130   TW223_GEN(3, 47, 21,  8)
    131   return (r & U64x(000fffff,ffffffff)) | U64x(3ff00000,00000000);
    132 }
    133 
    134 /* PRNG initialization function. */
    135 static void random_init(RandomState *rs, double d)
    136 {
    137   uint32_t r = 0x11090601;  /* 64-k[i] as four 8 bit constants. */
    138   int i;
    139   for (i = 0; i < 4; i++) {
    140     U64double u;
    141     uint32_t m = 1u << (r&255);
    142     r >>= 8;
    143     u.d = d = d * 3.14159265358979323846 + 2.7182818284590452354;
    144     if (u.u64 < m) u.u64 += m;  /* Ensure k[i] MSB of gen[i] are non-zero. */
    145     rs->gen[i] = u.u64;
    146   }
    147   rs->valid = 1;
    148   for (i = 0; i < 10; i++)
    149     lj_math_random_step(rs);
    150 }
    151 
    152 /* PRNG extract function. */
    153 LJLIB_PUSH(top-2)  /* Upvalue holds userdata with RandomState. */
    154 LJLIB_CF(math_random)		LJLIB_REC(.)
    155 {
    156   int n = (int)(L->top - L->base);
    157   RandomState *rs = (RandomState *)(uddata(udataV(lj_lib_upvalue(L, 1))));
    158   U64double u;
    159   double d;
    160   if (LJ_UNLIKELY(!rs->valid)) random_init(rs, 0.0);
    161   u.u64 = lj_math_random_step(rs);
    162   d = u.d - 1.0;
    163   if (n > 0) {
    164 #if LJ_DUALNUM
    165     int isint = 1;
    166     double r1;
    167     lj_lib_checknumber(L, 1);
    168     if (tvisint(L->base)) {
    169       r1 = (lua_Number)intV(L->base);
    170     } else {
    171       isint = 0;
    172       r1 = numV(L->base);
    173     }
    174 #else
    175     double r1 = lj_lib_checknum(L, 1);
    176 #endif
    177     if (n == 1) {
    178       d = lj_vm_floor(d*r1) + 1.0;  /* d is an int in range [1, r1] */
    179     } else {
    180 #if LJ_DUALNUM
    181       double r2;
    182       lj_lib_checknumber(L, 2);
    183       if (tvisint(L->base+1)) {
    184 	r2 = (lua_Number)intV(L->base+1);
    185       } else {
    186 	isint = 0;
    187 	r2 = numV(L->base+1);
    188       }
    189 #else
    190       double r2 = lj_lib_checknum(L, 2);
    191 #endif
    192       d = lj_vm_floor(d*(r2-r1+1.0)) + r1;  /* d is an int in range [r1, r2] */
    193     }
    194 #if LJ_DUALNUM
    195     if (isint) {
    196       setintV(L->top-1, lj_num2int(d));
    197       return 1;
    198     }
    199 #endif
    200   }  /* else: d is a double in range [0, 1] */
    201   setnumV(L->top++, d);
    202   return 1;
    203 }
    204 
    205 /* PRNG seed function. */
    206 LJLIB_PUSH(top-2)  /* Upvalue holds userdata with RandomState. */
    207 LJLIB_CF(math_randomseed)
    208 {
    209   RandomState *rs = (RandomState *)(uddata(udataV(lj_lib_upvalue(L, 1))));
    210   random_init(rs, lj_lib_checknum(L, 1));
    211   return 0;
    212 }
    213 
    214 /* ------------------------------------------------------------------------ */
    215 
    216 #include "lj_libdef.h"
    217 
    218 LUALIB_API int luaopen_math(lua_State *L)
    219 {
    220   RandomState *rs;
    221   rs = (RandomState *)lua_newuserdata(L, sizeof(RandomState));
    222   rs->valid = 0;  /* Use lazy initialization to save some time on startup. */
    223   LJ_LIB_REG(L, LUA_MATHLIBNAME, math);
    224 #if defined(LUA_COMPAT_MOD)
    225   lua_getfield(L, -1, "fmod");
    226   lua_setfield(L, -2, "mod");
    227 #endif
    228   return 1;
    229 }
    230