1 /*
2 ** $Id$
3 ** Standard mathematical library
4 ** See Copyright Notice in lua.h
5 */
6 
7 
8 // FIXME: rand and srand should be replaced by a RandomSource
9 #define FORBIDDEN_SYMBOL_EXCEPTION_rand
10 #define FORBIDDEN_SYMBOL_EXCEPTION_srand
11 
12 #include <stdlib.h>
13 // MSVC does not define M_PI, M_SQRT2 and other math defines by default.
14 // _USE_MATH_DEFINES must be defined in order to have these defined, thus
15 // we enable it here. For more information, check:
16 // http://msdn.microsoft.com/en-us/library/4hwaceh6(v=VS.100).aspx
17 #define _USE_MATH_DEFINES
18 #include <math.h>
19 
20 #define lmathlib_c
21 #define LUA_LIB
22 
23 #include "lua.h"
24 
25 #include "lauxlib.h"
26 #include "lualib.h"
27 
28 #define RADIANS_PER_DEGREE (M_PI/180.0)
29 
math_abs(lua_State * L)30 static int math_abs (lua_State *L) {
31   lua_pushnumber(L, fabs(luaL_checknumber(L, 1)));
32   return 1;
33 }
34 
math_sin(lua_State * L)35 static int math_sin (lua_State *L) {
36   lua_pushnumber(L, sin(luaL_checknumber(L, 1)));
37   return 1;
38 }
39 
math_sinh(lua_State * L)40 static int math_sinh (lua_State *L) {
41   lua_pushnumber(L, sinh(luaL_checknumber(L, 1)));
42   return 1;
43 }
44 
math_cos(lua_State * L)45 static int math_cos (lua_State *L) {
46   lua_pushnumber(L, cos(luaL_checknumber(L, 1)));
47   return 1;
48 }
49 
math_cosh(lua_State * L)50 static int math_cosh (lua_State *L) {
51   lua_pushnumber(L, cosh(luaL_checknumber(L, 1)));
52   return 1;
53 }
54 
math_tan(lua_State * L)55 static int math_tan (lua_State *L) {
56   lua_pushnumber(L, tan(luaL_checknumber(L, 1)));
57   return 1;
58 }
59 
math_tanh(lua_State * L)60 static int math_tanh (lua_State *L) {
61   lua_pushnumber(L, tanh(luaL_checknumber(L, 1)));
62   return 1;
63 }
64 
math_asin(lua_State * L)65 static int math_asin (lua_State *L) {
66   lua_pushnumber(L, asin(luaL_checknumber(L, 1)));
67   return 1;
68 }
69 
math_acos(lua_State * L)70 static int math_acos (lua_State *L) {
71   lua_pushnumber(L, acos(luaL_checknumber(L, 1)));
72   return 1;
73 }
74 
math_atan(lua_State * L)75 static int math_atan (lua_State *L) {
76   lua_pushnumber(L, atan(luaL_checknumber(L, 1)));
77   return 1;
78 }
79 
math_atan2(lua_State * L)80 static int math_atan2 (lua_State *L) {
81   lua_pushnumber(L, atan2(luaL_checknumber(L, 1), luaL_checknumber(L, 2)));
82   return 1;
83 }
84 
math_ceil(lua_State * L)85 static int math_ceil (lua_State *L) {
86   lua_pushnumber(L, ceil(luaL_checknumber(L, 1)));
87   return 1;
88 }
89 
math_floor(lua_State * L)90 static int math_floor (lua_State *L) {
91   lua_pushnumber(L, floor(luaL_checknumber(L, 1)));
92   return 1;
93 }
94 
math_fmod(lua_State * L)95 static int math_fmod (lua_State *L) {
96   lua_pushnumber(L, fmod(luaL_checknumber(L, 1), luaL_checknumber(L, 2)));
97   return 1;
98 }
99 
math_modf(lua_State * L)100 static int math_modf (lua_State *L) {
101   double ip;
102   double fp = modf(luaL_checknumber(L, 1), &ip);
103   lua_pushnumber(L, ip);
104   lua_pushnumber(L, fp);
105   return 2;
106 }
107 
math_sqrt(lua_State * L)108 static int math_sqrt (lua_State *L) {
109   lua_pushnumber(L, sqrt(luaL_checknumber(L, 1)));
110   return 1;
111 }
112 
math_pow(lua_State * L)113 static int math_pow (lua_State *L) {
114   lua_pushnumber(L, pow(luaL_checknumber(L, 1), luaL_checknumber(L, 2)));
115   return 1;
116 }
117 
math_log(lua_State * L)118 static int math_log (lua_State *L) {
119   lua_pushnumber(L, log(luaL_checknumber(L, 1)));
120   return 1;
121 }
122 
math_log10(lua_State * L)123 static int math_log10 (lua_State *L) {
124   lua_pushnumber(L, log10(luaL_checknumber(L, 1)));
125   return 1;
126 }
127 
math_exp(lua_State * L)128 static int math_exp (lua_State *L) {
129   lua_pushnumber(L, exp(luaL_checknumber(L, 1)));
130   return 1;
131 }
132 
math_deg(lua_State * L)133 static int math_deg (lua_State *L) {
134   lua_pushnumber(L, luaL_checknumber(L, 1)/RADIANS_PER_DEGREE);
135   return 1;
136 }
137 
math_rad(lua_State * L)138 static int math_rad (lua_State *L) {
139   lua_pushnumber(L, luaL_checknumber(L, 1)*RADIANS_PER_DEGREE);
140   return 1;
141 }
142 
math_frexp(lua_State * L)143 static int math_frexp (lua_State *L) {
144   int e;
145   lua_pushnumber(L, frexp(luaL_checknumber(L, 1), &e));
146   lua_pushinteger(L, e);
147   return 2;
148 }
149 
math_ldexp(lua_State * L)150 static int math_ldexp (lua_State *L) {
151   lua_pushnumber(L, ldexp(luaL_checknumber(L, 1), luaL_checkint(L, 2)));
152   return 1;
153 }
154 
155 
156 
math_min(lua_State * L)157 static int math_min (lua_State *L) {
158   int n = lua_gettop(L);  /* number of arguments */
159   lua_Number dmin = luaL_checknumber(L, 1);
160   int i;
161   for (i=2; i<=n; i++) {
162     lua_Number d = luaL_checknumber(L, i);
163     if (d < dmin)
164       dmin = d;
165   }
166   lua_pushnumber(L, dmin);
167   return 1;
168 }
169 
170 
math_max(lua_State * L)171 static int math_max (lua_State *L) {
172   int n = lua_gettop(L);  /* number of arguments */
173   lua_Number dmax = luaL_checknumber(L, 1);
174   int i;
175   for (i=2; i<=n; i++) {
176     lua_Number d = luaL_checknumber(L, i);
177     if (d > dmax)
178       dmax = d;
179   }
180   lua_pushnumber(L, dmax);
181   return 1;
182 }
183 
184 
math_random(lua_State * L)185 static int math_random (lua_State *L) {
186   /* the `%' avoids the (rare) case of r==1, and is needed also because on
187      some systems (SunOS!) `rand()' may return a value larger than RAND_MAX */
188   lua_Number r = (lua_Number)(rand()%RAND_MAX) / (lua_Number)RAND_MAX;
189   switch (lua_gettop(L)) {  /* check number of arguments */
190     case 0: {  /* no arguments */
191       lua_pushnumber(L, r);  /* Number between 0 and 1 */
192       break;
193     }
194     case 1: {  /* only upper limit */
195       int u = luaL_checkint(L, 1);
196       luaL_argcheck(L, 1<=u, 1, "interval is empty");
197       lua_pushnumber(L, floor(r*u)+1);  /* int between 1 and `u' */
198       break;
199     }
200     case 2: {  /* lower and upper limits */
201       int l = luaL_checkint(L, 1);
202       int u = luaL_checkint(L, 2);
203       luaL_argcheck(L, l<=u, 2, "interval is empty");
204       lua_pushnumber(L, floor(r*(u-l+1))+l);  /* int between `l' and `u' */
205       break;
206     }
207     default: return luaL_error(L, "wrong number of arguments");
208   }
209   return 1;
210 }
211 
212 
math_randomseed(lua_State * L)213 static int math_randomseed (lua_State *L) {
214   srand(luaL_checkint(L, 1));
215   return 0;
216 }
217 
218 
219 static const luaL_Reg mathlib[] = {
220   {"abs",   math_abs},
221   {"acos",  math_acos},
222   {"asin",  math_asin},
223   {"atan2", math_atan2},
224   {"atan",  math_atan},
225   {"ceil",  math_ceil},
226   {"cosh",   math_cosh},
227   {"cos",   math_cos},
228   {"deg",   math_deg},
229   {"exp",   math_exp},
230   {"floor", math_floor},
231   {"fmod",   math_fmod},
232   {"frexp", math_frexp},
233   {"ldexp", math_ldexp},
234   {"log10", math_log10},
235   {"log",   math_log},
236   {"max",   math_max},
237   {"min",   math_min},
238   {"modf",   math_modf},
239   {"pow",   math_pow},
240   {"rad",   math_rad},
241   {"random",     math_random},
242   {"randomseed", math_randomseed},
243   {"sinh",   math_sinh},
244   {"sin",   math_sin},
245   {"sqrt",  math_sqrt},
246   {"tanh",   math_tanh},
247   {"tan",   math_tan},
248   {NULL, NULL}
249 };
250 
251 
252 /*
253 ** Open math library
254 */
luaopen_math(lua_State * L)255 LUALIB_API int luaopen_math (lua_State *L) {
256   luaL_register(L, LUA_MATHLIBNAME, mathlib);
257   lua_pushnumber(L, M_PI);
258   lua_setfield(L, -2, "pi");
259 #if defined(MACOSX) && defined(__GNUC__) && ! defined( __XLC__ )
260   // WORKAROUND for a bug in the Mac OS X 10.2.8 SDK. It defines
261   // HUGE_VAL simply to 1e500, leading to this compiler error:
262   //   error: floating constant exceeds range of 'double'
263   // However, GCC (at least the version we are using for our cross
264   // compiler) has a __builtin_huge_val which returns the correct
265   // value, so we just use that.
266   lua_pushnumber(L, __builtin_huge_val());
267 #else
268   lua_pushnumber(L, HUGE_VAL);
269 #endif
270   lua_setfield(L, -2, "huge");
271 #if defined(LUA_COMPAT_MOD)
272   lua_getfield(L, -1, "fmod");
273   lua_setfield(L, -2, "mod");
274 #endif
275   return 1;
276 }
277