aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lcode.c34
-rw-r--r--testes/code.lua14
2 files changed, 40 insertions, 8 deletions
diff --git a/lcode.c b/lcode.c
index 80d975cb..9cba24f9 100644
--- a/lcode.c
+++ b/lcode.c
@@ -10,6 +10,7 @@
10#include "lprefix.h" 10#include "lprefix.h"
11 11
12 12
13#include <float.h>
13#include <limits.h> 14#include <limits.h>
14#include <math.h> 15#include <math.h>
15#include <stdlib.h> 16#include <stdlib.h>
@@ -580,24 +581,41 @@ static int stringK (FuncState *fs, TString *s) {
580 581
581/* 582/*
582** Add an integer to list of constants and return its index. 583** Add an integer to list of constants and return its index.
583** Integers use userdata as keys to avoid collision with floats with
584** same value; conversion to 'void*' is used only for hashing, so there
585** are no "precision" problems.
586*/ 584*/
587static int luaK_intK (FuncState *fs, lua_Integer n) { 585static int luaK_intK (FuncState *fs, lua_Integer n) {
588 TValue k, o; 586 TValue o;
589 setpvalue(&k, cast_voidp(cast_sizet(n)));
590 setivalue(&o, n); 587 setivalue(&o, n);
591 return addk(fs, &k, &o); 588 return addk(fs, &o, &o); /* use integer itself as key */
592} 589}
593 590
594/* 591/*
595** Add a float to list of constants and return its index. 592** Add a float to list of constants and return its index. Floats
593** with integral values need a different key, to avoid collision
594** with actual integers. To that, we add to the number its smaller
595** power-of-two fraction that is still significant in its scale.
596** For doubles, that would be 1/2^52.
597** (This method is not bulletproof: there may be another float
598** with that value, and for floats larger than 2^53 the result is
599** still an integer. At worst, this only wastes an entry with
600** a duplicate.)
596*/ 601*/
597static int luaK_numberK (FuncState *fs, lua_Number r) { 602static int luaK_numberK (FuncState *fs, lua_Number r) {
598 TValue o; 603 TValue o;
604 lua_Integer ik;
599 setfltvalue(&o, r); 605 setfltvalue(&o, r);
600 return addk(fs, &o, &o); /* use number itself as key */ 606 if (!luaV_flttointeger(r, &ik, F2Ieq)) /* not an integral value? */
607 return addk(fs, &o, &o); /* use number itself as key */
608 else { /* must build an alternative key */
609 const int nbm = l_floatatt(MANT_DIG);
610 const lua_Number q = l_mathop(ldexp)(1.0, -nbm + 1);
611 const lua_Number k = (ik == 0) ? q : r + r*q; /* new key */
612 TValue kv;
613 setfltvalue(&kv, k);
614 /* result is not an integral value, unless value is too large */
615 lua_assert(!luaV_flttointeger(k, &ik, F2Ieq) ||
616 l_mathop(fabs)(r) >= l_mathop(1e6));
617 return addk(fs, &kv, &o);
618 }
601} 619}
602 620
603 621
diff --git a/testes/code.lua b/testes/code.lua
index 4e00309f..543743fc 100644
--- a/testes/code.lua
+++ b/testes/code.lua
@@ -69,6 +69,20 @@ foo = function (f, a)
69checkKlist(foo, {100000, 100000.0, -100000, -100000.0}) 69checkKlist(foo, {100000, 100000.0, -100000, -100000.0})
70 70
71 71
72-- floats x integers
73foo = function (t, a)
74 t[a] = 1; t[a] = 1.0
75 t[a] = 1; t[a] = 1.0
76 t[a] = 2; t[a] = 2.0
77 t[a] = 0; t[a] = 0.0
78 t[a] = 1; t[a] = 1.0
79 t[a] = 2; t[a] = 2.0
80 t[a] = 0; t[a] = 0.0
81end
82
83checkKlist(foo, {1, 1.0, 2, 2.0, 0, 0.0})
84
85
72-- testing opcodes 86-- testing opcodes
73 87
74-- check that 'f' opcodes match '...' 88-- check that 'f' opcodes match '...'