commit ed1fe28bb8c98382412eab8cfe24fe3dc5adf8f3
parent 6645bb2df44d4fc6c7aea8347a559357b657f80a
Author: Roberto Ierusalimschy <roberto@inf.puc-rio.br>
Date: Tue, 2 Jun 2015 16:10:59 -0300
When comparing integers with floats, use float as common type when
possible (i.e., when integer fits in a float without losses); seems
to be more efficient in architectures with native support for used
Lua numbers
Diffstat:
M | lvm.c | | | 121 | +++++++++++++++++++++++++++++++++++++++++++++---------------------------------- |
1 file changed, 69 insertions(+), 52 deletions(-)
diff --git a/lvm.c b/lvm.c
@@ -1,5 +1,5 @@
/*
-** $Id: lvm.c,v 2.242 2015/05/20 18:19:11 roberto Exp roberto $
+** $Id: lvm.c,v 2.243 2015/05/22 17:48:19 roberto Exp roberto $
** Lua virtual machine
** See Copyright Notice in lua.h
*/
@@ -9,7 +9,7 @@
#include "lprefix.h"
-
+#include <float.h>
#include <limits.h>
#include <math.h>
#include <stdio.h>
@@ -36,6 +36,34 @@
+/*
+** '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.
+*/
+#if !defined(l_intfitsf)
+
+/* number of bits in the mantissa of a float */
+#define NBM (l_mathlim(MANT_DIG))
+
+/*
+** Check whether some integers may not fit in a float, that is, whether
+** (maxinteger >> NBM) > 0 (that implies (1 << NBM) <= maxinteger).
+** (The shifts are done in parts to avoid shifting by more than the size
+** of an integer. In a worst case, NBM == 113 for long double and
+** sizeof(integer) == 32.)
+*/
+#if ((((LUA_MAXINTEGER >> (NBM / 4)) >> (NBM / 4)) >> (NBM / 4)) \
+ >> (NBM - (3 * (NBM / 4)))) > 0
+
+#define l_intfitsf(i) \
+ (-((lua_Integer)1 << NBM) <= (i) && (i) <= ((lua_Integer)1 << NBM))
+
+#endif
+
+#endif
+
+
/*
** Try to convert a value to a float. The float case is already handled
@@ -228,60 +256,45 @@ static int l_strcmp (const TString *ls, const TString *rs) {
/*
-** Check whether integer 'i' is less than float 'f'. 'neg' true means
-** result will be later negated: NaN still must result in false after
-** inversion. The comparison is based on the equivalence:
-** i < f <--> i < ceil(f)
-** When 'f' is non-positive, 'ceil' is not necessary, because the
-** standard C truncation (when converting a float to an integer) does
-** the job.
-**
+** 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.)
*/
-static int LTintfloat (lua_Integer i, lua_Number f, int neg) {
- if (f > 0) {
- f = l_mathop(ceil)(f);
+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; larger than all integers */
- else { /* 0 < f < (maxint + 1) */
- /* as f now has integral value, f <= maxint; cast is safe */
- return (i < cast(lua_Integer, f));
- }
- }
- else if (f > cast_num(LUA_MININTEGER)) { /* minint < f <= 0? */
- return (i < cast(lua_Integer, f)); /* cast computes 'ceil' */
+ return 1; /* f >= maxint + 1 > i */
+ else if (f <= cast_num(LUA_MININTEGER)) /* f <= minint */
+ return 0; /* f <= minint <= i --> not(i < f) */
+ else /* minint < f <= maxint */
+ return (i < cast(lua_Integer, f)); /* compare them as integers */
}
- else if (luai_numisnan(f))
- return neg; /* i < NaN: final result must be false */
- else /* f <= minint */
- return 0; /* 'f' cannot be larger than any int */
+#endif
+ return luai_numlt(cast_num(i), f); /* compare them as floats */
}
/*
** Check whether integer 'i' is less than or equal to float 'f'.
-** 'neg' is like in previous function. The comparison is based on the
-** equivalence:
-** i <= f <--> i <= floor(f)
-** When f is non-negative, 'floor' is not necessary (C truncation does
-** the job).
+** See comments on previous function.
*/
-static int LEintfloat (lua_Integer i, lua_Number f, int neg) {
- if (f >= 0) {
- if (f >= -cast_num(LUA_MININTEGER)) /* f >= (maxint + 1)? */
- return 1; /* 'f' larger than all integers */
- else { /* 0 <= f < (maxint + 1) */
- /* truncation ensures that resulting value is <= maxint */
- return (i <= cast(lua_Integer, f));
- }
- }
- else if (f >= cast_num(LUA_MININTEGER)) { /* minint <= f < 0? */
- /* f >= minint --> floor(f) >= minint */
- return (i <= cast(lua_Integer, l_floor(f)));
+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)) /* f < minint */
+ return 0; /* f < minint <= i --> not(i <= f) */
+ else /* minint <= f <= maxint */
+ return (i <= cast(lua_Integer, f)); /* compare them as integers */
}
- else if (luai_numisnan(f))
- return neg; /* i <= NaN: final result must be false */
- else /* f < minint */
- return 0; /* 'f' is smaller than any int */
+#endif
+ return luai_numle(cast_num(i), f); /* compare them as floats */
}
@@ -294,14 +307,16 @@ static int LTnum (const TValue *l, const TValue *r) {
if (ttisinteger(r))
return li < ivalue(r); /* both are integers */
else /* 'l' is int and 'r' is float */
- return LTintfloat(li, fltvalue(r), 0); /* l < r ? */
+ return LTintfloat(li, fltvalue(r)); /* l < r ? */
}
else {
lua_Number lf = fltvalue(l); /* 'l' must be float */
if (ttisfloat(r))
return luai_numlt(lf, fltvalue(r)); /* both are float */
- else /* 'r' is int and 'l' is float */
- return !LEintfloat(ivalue(r), lf, 1); /* not (r <= l) ? */
+ 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) ? */
}
}
@@ -315,14 +330,16 @@ static int LEnum (const TValue *l, const TValue *r) {
if (ttisinteger(r))
return li <= ivalue(r); /* both are integers */
else /* 'l' is int and 'r' is float */
- return LEintfloat(li, fltvalue(r), 0); /* l <= r ? */
+ return LEintfloat(li, fltvalue(r)); /* l <= r ? */
}
else {
lua_Number lf = fltvalue(l); /* 'l' must be float */
if (ttisfloat(r))
return luai_numle(lf, fltvalue(r)); /* both are float */
- else /* 'r' is int and 'l' is float */
- return !LTintfloat(ivalue(r), lf, 1); /* not (r < l) ? */
+ 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) ? */
}
}