Browse Source

simpler implementation for 'LTintfloat'/'LEintfloat'
+ 'LTfloatint'/'LEfloatint'

Roberto Ierusalimschy 7 years ago
parent
commit
06865aa01d
1 changed files with 71 additions and 45 deletions
  1. 71 45
      lvm.c

+ 71 - 45
lvm.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lvm.c,v 2.342 2018/02/19 20:06:56 roberto Exp roberto $
+** $Id: lvm.c,v 2.343 2018/02/21 12:54:26 roberto Exp roberto $
 ** Lua virtual machine
 ** See Copyright Notice in lua.h
 */
@@ -31,17 +31,14 @@
 #include "lvm.h"
 
 
-/* limit for table tag-method chains (to avoid loops) */
+/* limit for table tag-method chains (to avoid infinite loops) */
 #define MAXTAGLOOP	2000
 
 
 /*
 ** 'l_intfitsf' checks whether a given integer can be converted to a
-** float without rounding. Used in comparisons. Left undefined if
-** all integers fit in a float precisely.
+** float without rounding. Used in comparisons.
 */
-#if !defined(l_intfitsf)
-
 /* number of bits in the mantissa of a float */
 #define NBM		(l_mathlim(MANT_DIG))
 
@@ -58,7 +55,9 @@
 #define l_intfitsf(i)  \
   (-((lua_Integer)1 << NBM) <= (i) && (i) <= ((lua_Integer)1 << NBM))
 
-#endif
+#else  /* all integers fit in a float precisely */
+
+#define l_intfitsf(i)	1
 
 #endif
 
@@ -157,7 +156,7 @@ static int forlimit (const TValue *obj, lua_Integer *p, lua_Integer step,
       *p = LUA_MAXINTEGER;
       if (step < 0) *stopnow = 1;
     }
-    else {  /* float is smaller than min integer */
+    else {  /* float is less than min integer */
       *p = LUA_MININTEGER;
       if (step >= 0) *stopnow = 1;
     }
@@ -255,8 +254,8 @@ void luaV_finishset (lua_State *L, const TValue *t, TValue *key,
 
 
 /*
-** Compare two strings 'ls' x 'rs', returning an integer smaller-equal-
-** -larger than zero if 'ls' is smaller-equal-larger than 'rs'.
+** Compare two strings 'ls' x 'rs', returning an integer less-equal-
+** -greater than zero if 'ls' is less-equal-greater than 'rs'.
 ** The code is a little tricky because it allows '\0' in the strings
 ** and it uses 'strcoll' (to respect locales) for each segments
 ** of the strings.
@@ -275,7 +274,7 @@ static int l_strcmp (const TString *ls, const TString *rs) {
       if (len == lr)  /* 'rs' is finished? */
         return (len == ll) ? 0 : 1;  /* check 'ls' */
       else if (len == ll)  /* 'ls' is finished? */
-        return -1;  /* 'ls' is smaller than 'rs' ('rs' is not finished) */
+        return -1;  /* 'ls' is less than 'rs' ('rs' is not finished) */
       /* both strings longer than 'len'; go on comparing after the '\0' */
       len++;
       l += len; ll -= len; r += len; lr -= len;
@@ -287,25 +286,24 @@ static int l_strcmp (const TString *ls, const TString *rs) {
 /*
 ** Check whether integer 'i' is less than float 'f'. If 'i' has an
 ** exact representation as a float ('l_intfitsf'), compare numbers as
-** floats. Otherwise, if 'f' is outside the range for integers, result
-** is trivial. Otherwise, compare them as integers. (When 'i' has no
-** float representation, either 'f' is "far away" from 'i' or 'f' has
-** no precision left for a fractional part; either way, how 'f' is
-** truncated is irrelevant.) When 'f' is NaN, comparisons must result
-** in false.
+** floats. Otherwise, use the equivalence 'i < f <=> i < ceil(f)'.
+** If 'ceil(f)' is out of integer range, either 'f' is greater than
+** all integers or less than all integers.
+** (The test with 'l_intfitsf' is only for performance; the else
+** case is correct for all values, but it is slow due to the conversion
+** from float to int.)
+** When 'f' is NaN, comparisons must result in false.
 */
 static int LTintfloat (lua_Integer i, lua_Number f) {
-#if defined(l_intfitsf)
-  if (!l_intfitsf(i)) {
-    if (f >= -cast_num(LUA_MININTEGER))  /* -minint == maxint + 1 */
-      return 1;  /* f >= maxint + 1 > i */
-    else if (f > cast_num(LUA_MININTEGER))  /* minint < f <= maxint ? */
-      return (i < cast(lua_Integer, f));  /* compare them as integers */
-    else  /* f <= minint <= i (or 'f' is NaN)  -->  not(i < f) */
-      return 0;
+  if (l_intfitsf(i))
+    return luai_numlt(cast_num(i), f);  /* compare them as floats */
+  else {  /* i < f <=> i < ceil(f) */
+    lua_Integer fi;
+    if (luaV_flttointeger(f, &fi, 2))  /* fi = ceil(f) */
+      return i < fi;   /* compare them as integers */
+    else  /* 'f' is either greater or less than all integers */
+      return f > 0;  /* greater? */
   }
-#endif
-  return luai_numlt(cast_num(i), f);  /* compare them as floats */
 }
 
 
@@ -314,17 +312,49 @@ static int LTintfloat (lua_Integer i, lua_Number f) {
 ** See comments on previous function.
 */
 static int LEintfloat (lua_Integer i, lua_Number f) {
-#if defined(l_intfitsf)
-  if (!l_intfitsf(i)) {
-    if (f >= -cast_num(LUA_MININTEGER))  /* -minint == maxint + 1 */
-      return 1;  /* f >= maxint + 1 > i */
-    else if (f >= cast_num(LUA_MININTEGER))  /* minint <= f <= maxint ? */
-      return (i <= cast(lua_Integer, f));  /* compare them as integers */
-    else  /* f < minint <= i (or 'f' is NaN)  -->  not(i <= f) */
-      return 0;
+  if (l_intfitsf(i))
+    return luai_numle(cast_num(i), f);  /* compare them as floats */
+  else {  /* i <= f <=> i <= floor(f) */
+    lua_Integer fi;
+    if (luaV_flttointeger(f, &fi, 1))  /* fi = floor(f) */
+      return i <= fi;   /* compare them as integers */
+    else  /* 'f' is either greater or less than all integers */
+      return f > 0;  /* greater? */
+  }
+}
+
+
+/*
+** Check whether float 'f' is less than integer 'i'.
+** See comments on previous function.
+*/
+static int LTfloatint (lua_Number f, lua_Integer i) {
+  if (l_intfitsf(i))
+    return luai_numlt(f, cast_num(i));  /* compare them as floats */
+  else {  /* f < i <=> floor(f) < i */
+    lua_Integer fi;
+    if (luaV_flttointeger(f, &fi, 1))  /* fi = floor(f) */
+      return fi < i;   /* compare them as integers */
+    else  /* 'f' is either greater or less than all integers */
+      return f < 0;  /* less? */
+  }
+}
+
+
+/*
+** Check whether float 'f' is less than or equal to integer 'i'.
+** See comments on previous function.
+*/
+static int LEfloatint (lua_Number f, lua_Integer i) {
+  if (l_intfitsf(i))
+    return luai_numle(f, cast_num(i));  /* compare them as floats */
+  else {  /* f <= i <=> ceil(f) <= i */
+    lua_Integer fi;
+    if (luaV_flttointeger(f, &fi, 2))  /* fi = ceil(f) */
+      return fi <= i;   /* compare them as integers */
+    else  /* 'f' is either greater or less than all integers */
+      return f < 0;  /* less? */
   }
-#endif
-  return luai_numle(cast_num(i), f);  /* compare them as floats */
 }
 
 
@@ -344,10 +374,8 @@ static int LTnum (const TValue *l, const TValue *r) {
     lua_Number lf = fltvalue(l);  /* 'l' must be float */
     if (ttisfloat(r))
       return luai_numlt(lf, fltvalue(r));  /* both are float */
-    else if (luai_numisnan(lf))  /* 'r' is int and 'l' is float */
-      return 0;  /* NaN < i is always false */
-    else  /* without NaN, (l < r)  <-->  not(r <= l) */
-      return !LEintfloat(ivalue(r), lf);  /* not (r <= l) ? */
+    else  /* 'l' is float and 'r' is int */
+      return LTfloatint(lf, ivalue(r));
   }
 }
 
@@ -368,10 +396,8 @@ static int LEnum (const TValue *l, const TValue *r) {
     lua_Number lf = fltvalue(l);  /* 'l' must be float */
     if (ttisfloat(r))
       return luai_numle(lf, fltvalue(r));  /* both are float */
-    else if (luai_numisnan(lf))  /* 'r' is int and 'l' is float */
-      return 0;  /*  NaN <= i is always false */
-    else  /* without NaN, (l <= r)  <-->  not(r < l) */
-      return !LTintfloat(ivalue(r), lf);  /* not (r < l) ? */
+    else  /* 'l' is float and 'r' is int */
+      return LEfloatint(lf, ivalue(r));
   }
 }