diff options
| author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2015-02-13 11:05:34 -0200 |
|---|---|---|
| committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2015-02-13 11:05:34 -0200 |
| commit | e0306e386fdaa1b1f18f0c293a4b14de8b8a8536 (patch) | |
| tree | f94331011a045342b320757ebfbe5318ef3d1faf | |
| parent | 2e6e53c7ccb8634f21598b151413292c472ab432 (diff) | |
| download | lua-e0306e386fdaa1b1f18f0c293a4b14de8b8a8536.tar.gz lua-e0306e386fdaa1b1f18f0c293a4b14de8b8a8536.tar.bz2 lua-e0306e386fdaa1b1f18f0c293a4b14de8b8a8536.zip | |
some changes in 'hashfloat' to avoid undefined (in ISO C) numerical
conversions
| -rw-r--r-- | ltable.c | 29 |
1 files changed, 21 insertions, 8 deletions
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: ltable.c,v 2.100 2015/01/05 13:52:37 roberto Exp roberto $ | 2 | ** $Id: ltable.c,v 2.101 2015/01/16 16:54:37 roberto Exp roberto $ |
| 3 | ** Lua tables (hash) | 3 | ** Lua tables (hash) |
| 4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
| 5 | */ | 5 | */ |
| @@ -96,16 +96,29 @@ static int numisinteger (lua_Number x, lua_Integer *p) { | |||
| 96 | 96 | ||
| 97 | 97 | ||
| 98 | /* | 98 | /* |
| 99 | ** hash for floating-point numbers | 99 | ** Hash for floating-point numbers. |
| 100 | ** The main computation should be just | ||
| 101 | ** n = frepx(n, &i); hash = (n * INT_MAX) + i | ||
| 102 | ** but there are some numerical subtleties. | ||
| 103 | ** In a two-complement representation, INT_MAX does not has an exact | ||
| 104 | ** representation as a float, but INT_MIN does; because the absolute | ||
| 105 | ** value of 'frexp' is smaller than 1 (unless 'n' is inf/NaN), the | ||
| 106 | ** absolute value of the product 'frexp * -INT_MIN' is smaller or equal | ||
| 107 | ** to INT_MAX. Next, the use of 'unsigned int' avoids overflows when | ||
| 108 | ** adding 'i'; the use of '~u' (instead of '-u') avoids problems with | ||
| 109 | ** INT_MIN. | ||
| 100 | */ | 110 | */ |
| 101 | static Node *hashfloat (const Table *t, lua_Number n) { | 111 | static Node *hashfloat (const Table *t, lua_Number n) { |
| 102 | int i; | 112 | int i; |
| 103 | n = l_mathop(frexp)(n, &i) * cast_num(INT_MAX - DBL_MAX_EXP); | 113 | lua_Integer ni; |
| 104 | i += cast_int(n); | 114 | n = l_mathop(frexp)(n, &i) * -cast_num(INT_MIN); |
| 105 | if (i < 0) { | 115 | if (!lua_numbertointeger(n, &ni)) { /* is 'n' inf/-inf/NaN? */ |
| 106 | if (cast(unsigned int, i) == 0u - i) /* use unsigned to avoid overflows */ | 116 | lua_assert(luai_numisnan(n) || l_mathop(fabs)(n) == HUGE_VAL); |
| 107 | i = 0; /* handle INT_MIN */ | 117 | i = 0; |
| 108 | i = -i; /* must be a positive value */ | 118 | } |
| 119 | else { /* normal case */ | ||
| 120 | unsigned int u = cast(unsigned int, i) + cast(unsigned int, ni); | ||
| 121 | i = (u <= cast(unsigned int, INT_MAX) ? u : ~u); | ||
| 109 | } | 122 | } |
| 110 | return hashmod(t, i); | 123 | return hashmod(t, i); |
| 111 | } | 124 | } |
