2
0
Эх сурвалжийг харах

'x//y' extended to floats + more comments about module and floor
division operations

Roberto Ierusalimschy 10 жил өмнө
parent
commit
049cf14cf9
2 өөрчлөгдсөн 43 нэмэгдсэн , 24 устгасан
  1. 16 2
      luaconf.h
  2. 27 22
      lvm.c

+ 16 - 2
luaconf.h

@@ -1,5 +1,5 @@
 /*
 /*
-** $Id: luaconf.h,v 1.227 2014/11/02 19:35:39 roberto Exp roberto $
+** $Id: luaconf.h,v 1.228 2014/11/19 15:00:42 roberto Exp roberto $
 ** Configuration file for Lua
 ** Configuration file for Lua
 ** See Copyright Notice in lua.h
 ** See Copyright Notice in lua.h
 */
 */
@@ -468,9 +468,23 @@
 /* the following operations need the math library */
 /* the following operations need the math library */
 #if defined(lobject_c) || defined(lvm_c)
 #if defined(lobject_c) || defined(lvm_c)
 #include <math.h>
 #include <math.h>
+
+/* floor division (defined as 'floor(a/b)') */
+#define luai_numidiv(L,a,b)	((void)L, l_mathop(floor)((a)/(b)))
+
+/*
+** module: defined as 'a - floor(a/b)*b'; the previous definition gives
+** NaN when 'b' is huge, but the result should be 'a'. 'fmod' gives the
+** result of 'a - trunc(a/b)*b', and therefore must be corrected when
+** 'trunc(a/b) ~= floor(a/b)'. That happens when the division has a
+** non-integer negative result, which is equivalent to the test below
+*/
 #define luai_nummod(L,a,b,m)  \
 #define luai_nummod(L,a,b,m)  \
-  { (m) = l_mathop(fmod)(a,b); if ((m) != 0 && (a)*(b) < 0) (m) += (b); }
+  { (m) = l_mathop(fmod)(a,b); if ((m)*(b) < 0) (m) += (b); }
+
+/* exponentiation */
 #define luai_numpow(L,a,b)	((void)L, l_mathop(pow)(a,b))
 #define luai_numpow(L,a,b)	((void)L, l_mathop(pow)(a,b))
+
 #endif
 #endif
 
 
 /* these are quite standard operations */
 /* these are quite standard operations */

+ 27 - 22
lvm.c

@@ -1,5 +1,5 @@
 /*
 /*
-** $Id: lvm.c,v 2.228 2014/11/03 20:07:47 roberto Exp roberto $
+** $Id: lvm.c,v 2.229 2014/11/19 15:05:15 roberto Exp roberto $
 ** Lua virtual machine
 ** Lua virtual machine
 ** See Copyright Notice in lua.h
 ** See Copyright Notice in lua.h
 */
 */
@@ -428,8 +428,10 @@ void luaV_objlen (lua_State *L, StkId ra, const TValue *rb) {
 
 
 
 
 /*
 /*
-** Integer division; return 'm // n'. (Assume that C division with
-** negative operands follows C99 behavior.)
+** Integer division; return 'm // n', that is, floor(m/n).
+** C division truncates its result (rounds towards zero).
+** 'floor(q) == trunc(q)' when 'q >= 0' or when 'q' is integer,
+** otherwise 'floor(q) == trunc(q) - 1'.
 */
 */
 lua_Integer luaV_div (lua_State *L, lua_Integer m, lua_Integer n) {
 lua_Integer luaV_div (lua_State *L, lua_Integer m, lua_Integer n) {
   if (l_castS2U(n) + 1u <= 1u) {  /* special cases: -1 or 0 */
   if (l_castS2U(n) + 1u <= 1u) {  /* special cases: -1 or 0 */
@@ -438,18 +440,18 @@ lua_Integer luaV_div (lua_State *L, lua_Integer m, lua_Integer n) {
     return intop(-, 0, m);   /* n==-1; avoid overflow with 0x80000...//-1 */
     return intop(-, 0, m);   /* n==-1; avoid overflow with 0x80000...//-1 */
   }
   }
   else {
   else {
-    lua_Integer d = m / n;  /* perform division */
-    if ((m ^ n) >= 0 || m % n == 0)   /* same signal or no rest? */
-      return d;
-    else
-      return d - 1;  /* correct 'div' for negative case */
+    lua_Integer q = m / n;  /* perform C division */
+    if ((m ^ n) < 0 && m % n != 0)  /* 'm/n' would be negative non-integer? */
+      q -= 1;  /* correct result for different rounding */
+    return q;
   }
   }
 }
 }
 
 
 
 
 /*
 /*
 ** Integer modulus; return 'm % n'. (Assume that C '%' with 
 ** Integer modulus; return 'm % n'. (Assume that C '%' with 
-** negative operands follows C99 behavior.)
+** negative operands follows C99 behavior. See previous comment
+** about luaV_div.)
 */
 */
 lua_Integer luaV_mod (lua_State *L, lua_Integer m, lua_Integer n) {
 lua_Integer luaV_mod (lua_State *L, lua_Integer m, lua_Integer n) {
   if (l_castS2U(n) + 1u <= 1u) {  /* special cases: -1 or 0 */
   if (l_castS2U(n) + 1u <= 1u) {  /* special cases: -1 or 0 */
@@ -459,10 +461,9 @@ lua_Integer luaV_mod (lua_State *L, lua_Integer m, lua_Integer n) {
   }
   }
   else {
   else {
     lua_Integer r = m % n;
     lua_Integer r = m % n;
-    if (r == 0 || (m ^ n) >= 0)  /* no rest or same signal? */
-      return r;
-    else
-      return r + n;  /* correct 'mod' for negative case */
+    if (r != 0 && (m ^ n) < 0)  /* 'm/n' would be non-integer negative? */
+      r += n;  /* correct result for different rounding */
+    return r;
   }
   }
 }
 }
 
 
@@ -778,15 +779,6 @@ void luaV_execute (lua_State *L) {
         }
         }
         else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_DIV)); }
         else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_DIV)); }
       )
       )
-      vmcase(OP_IDIV,  /* integer division */
-        TValue *rb = RKB(i);
-        TValue *rc = RKC(i);
-        lua_Integer ib; lua_Integer ic;
-        if (tointeger(rb, &ib) && tointeger(rc, &ic)) {
-          setivalue(ra, luaV_div(L, ib, ic));
-        }
-        else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_IDIV)); }
-      )
       vmcase(OP_BAND,
       vmcase(OP_BAND,
         TValue *rb = RKB(i);
         TValue *rb = RKB(i);
         TValue *rc = RKC(i);
         TValue *rc = RKC(i);
@@ -847,6 +839,19 @@ void luaV_execute (lua_State *L) {
         }
         }
         else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_MOD)); }
         else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_MOD)); }
       )
       )
+      vmcase(OP_IDIV,  /* floor division */
+        TValue *rb = RKB(i);
+        TValue *rc = RKC(i);
+        lua_Number nb; lua_Number nc;
+        if (ttisinteger(rb) && ttisinteger(rc)) {
+          lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc);
+          setivalue(ra, luaV_div(L, ib, ic));
+        }
+        else if (tonumber(rb, &nb) && tonumber(rc, &nc)) {
+          setfltvalue(ra, luai_numidiv(L, nb, nc));
+        }
+        else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_IDIV)); }
+      )
       vmcase(OP_POW,
       vmcase(OP_POW,
         TValue *rb = RKB(i);
         TValue *rb = RKB(i);
         TValue *rc = RKC(i);
         TValue *rc = RKC(i);