diff options
Diffstat (limited to 'lvm.c')
-rw-r--r-- | lvm.c | 49 |
1 files changed, 27 insertions, 22 deletions
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lvm.c,v 2.228 2014/11/03 20:07:47 roberto Exp roberto $ | 2 | ** $Id: lvm.c,v 2.229 2014/11/19 15:05:15 roberto Exp roberto $ |
3 | ** Lua virtual machine | 3 | ** Lua virtual machine |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -428,8 +428,10 @@ void luaV_objlen (lua_State *L, StkId ra, const TValue *rb) { | |||
428 | 428 | ||
429 | 429 | ||
430 | /* | 430 | /* |
431 | ** Integer division; return 'm // n'. (Assume that C division with | 431 | ** Integer division; return 'm // n', that is, floor(m/n). |
432 | ** negative operands follows C99 behavior.) | 432 | ** C division truncates its result (rounds towards zero). |
433 | ** 'floor(q) == trunc(q)' when 'q >= 0' or when 'q' is integer, | ||
434 | ** otherwise 'floor(q) == trunc(q) - 1'. | ||
433 | */ | 435 | */ |
434 | lua_Integer luaV_div (lua_State *L, lua_Integer m, lua_Integer n) { | 436 | lua_Integer luaV_div (lua_State *L, lua_Integer m, lua_Integer n) { |
435 | if (l_castS2U(n) + 1u <= 1u) { /* special cases: -1 or 0 */ | 437 | 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) { | |||
438 | return intop(-, 0, m); /* n==-1; avoid overflow with 0x80000...//-1 */ | 440 | return intop(-, 0, m); /* n==-1; avoid overflow with 0x80000...//-1 */ |
439 | } | 441 | } |
440 | else { | 442 | else { |
441 | lua_Integer d = m / n; /* perform division */ | 443 | lua_Integer q = m / n; /* perform C division */ |
442 | if ((m ^ n) >= 0 || m % n == 0) /* same signal or no rest? */ | 444 | if ((m ^ n) < 0 && m % n != 0) /* 'm/n' would be negative non-integer? */ |
443 | return d; | 445 | q -= 1; /* correct result for different rounding */ |
444 | else | 446 | return q; |
445 | return d - 1; /* correct 'div' for negative case */ | ||
446 | } | 447 | } |
447 | } | 448 | } |
448 | 449 | ||
449 | 450 | ||
450 | /* | 451 | /* |
451 | ** Integer modulus; return 'm % n'. (Assume that C '%' with | 452 | ** Integer modulus; return 'm % n'. (Assume that C '%' with |
452 | ** negative operands follows C99 behavior.) | 453 | ** negative operands follows C99 behavior. See previous comment |
454 | ** about luaV_div.) | ||
453 | */ | 455 | */ |
454 | lua_Integer luaV_mod (lua_State *L, lua_Integer m, lua_Integer n) { | 456 | lua_Integer luaV_mod (lua_State *L, lua_Integer m, lua_Integer n) { |
455 | if (l_castS2U(n) + 1u <= 1u) { /* special cases: -1 or 0 */ | 457 | 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) { | |||
459 | } | 461 | } |
460 | else { | 462 | else { |
461 | lua_Integer r = m % n; | 463 | lua_Integer r = m % n; |
462 | if (r == 0 || (m ^ n) >= 0) /* no rest or same signal? */ | 464 | if (r != 0 && (m ^ n) < 0) /* 'm/n' would be non-integer negative? */ |
463 | return r; | 465 | r += n; /* correct result for different rounding */ |
464 | else | 466 | return r; |
465 | return r + n; /* correct 'mod' for negative case */ | ||
466 | } | 467 | } |
467 | } | 468 | } |
468 | 469 | ||
@@ -778,15 +779,6 @@ void luaV_execute (lua_State *L) { | |||
778 | } | 779 | } |
779 | else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_DIV)); } | 780 | else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_DIV)); } |
780 | ) | 781 | ) |
781 | vmcase(OP_IDIV, /* integer division */ | ||
782 | TValue *rb = RKB(i); | ||
783 | TValue *rc = RKC(i); | ||
784 | lua_Integer ib; lua_Integer ic; | ||
785 | if (tointeger(rb, &ib) && tointeger(rc, &ic)) { | ||
786 | setivalue(ra, luaV_div(L, ib, ic)); | ||
787 | } | ||
788 | else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_IDIV)); } | ||
789 | ) | ||
790 | vmcase(OP_BAND, | 782 | vmcase(OP_BAND, |
791 | TValue *rb = RKB(i); | 783 | TValue *rb = RKB(i); |
792 | TValue *rc = RKC(i); | 784 | TValue *rc = RKC(i); |
@@ -847,6 +839,19 @@ void luaV_execute (lua_State *L) { | |||
847 | } | 839 | } |
848 | else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_MOD)); } | 840 | else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_MOD)); } |
849 | ) | 841 | ) |
842 | vmcase(OP_IDIV, /* floor division */ | ||
843 | TValue *rb = RKB(i); | ||
844 | TValue *rc = RKC(i); | ||
845 | lua_Number nb; lua_Number nc; | ||
846 | if (ttisinteger(rb) && ttisinteger(rc)) { | ||
847 | lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc); | ||
848 | setivalue(ra, luaV_div(L, ib, ic)); | ||
849 | } | ||
850 | else if (tonumber(rb, &nb) && tonumber(rc, &nc)) { | ||
851 | setfltvalue(ra, luai_numidiv(L, nb, nc)); | ||
852 | } | ||
853 | else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_IDIV)); } | ||
854 | ) | ||
850 | vmcase(OP_POW, | 855 | vmcase(OP_POW, |
851 | TValue *rb = RKB(i); | 856 | TValue *rb = RKB(i); |
852 | TValue *rc = RKC(i); | 857 | TValue *rc = RKC(i); |