diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2014-11-21 10:15:00 -0200 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2014-11-21 10:15:00 -0200 |
commit | 049cf14cf9f82a07387df4d0c9bdba5ba2fef22f (patch) | |
tree | 8f8ab9e865710858c816bef0f45db94a26a48a2b | |
parent | 5d628519d37a70b56be610cc4c256b3accc2f72c (diff) | |
download | lua-049cf14cf9f82a07387df4d0c9bdba5ba2fef22f.tar.gz lua-049cf14cf9f82a07387df4d0c9bdba5ba2fef22f.tar.bz2 lua-049cf14cf9f82a07387df4d0c9bdba5ba2fef22f.zip |
'x//y' extended to floats + more comments about module and floor
division operations
-rw-r--r-- | luaconf.h | 18 | ||||
-rw-r--r-- | lvm.c | 49 |
2 files changed, 43 insertions, 24 deletions
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: luaconf.h,v 1.227 2014/11/02 19:35:39 roberto Exp roberto $ | 2 | ** $Id: luaconf.h,v 1.228 2014/11/19 15:00:42 roberto Exp roberto $ |
3 | ** Configuration file for Lua | 3 | ** Configuration file for Lua |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -468,9 +468,23 @@ | |||
468 | /* the following operations need the math library */ | 468 | /* the following operations need the math library */ |
469 | #if defined(lobject_c) || defined(lvm_c) | 469 | #if defined(lobject_c) || defined(lvm_c) |
470 | #include <math.h> | 470 | #include <math.h> |
471 | |||
472 | /* floor division (defined as 'floor(a/b)') */ | ||
473 | #define luai_numidiv(L,a,b) ((void)L, l_mathop(floor)((a)/(b))) | ||
474 | |||
475 | /* | ||
476 | ** module: defined as 'a - floor(a/b)*b'; the previous definition gives | ||
477 | ** NaN when 'b' is huge, but the result should be 'a'. 'fmod' gives the | ||
478 | ** result of 'a - trunc(a/b)*b', and therefore must be corrected when | ||
479 | ** 'trunc(a/b) ~= floor(a/b)'. That happens when the division has a | ||
480 | ** non-integer negative result, which is equivalent to the test below | ||
481 | */ | ||
471 | #define luai_nummod(L,a,b,m) \ | 482 | #define luai_nummod(L,a,b,m) \ |
472 | { (m) = l_mathop(fmod)(a,b); if ((m) != 0 && (a)*(b) < 0) (m) += (b); } | 483 | { (m) = l_mathop(fmod)(a,b); if ((m)*(b) < 0) (m) += (b); } |
484 | |||
485 | /* exponentiation */ | ||
473 | #define luai_numpow(L,a,b) ((void)L, l_mathop(pow)(a,b)) | 486 | #define luai_numpow(L,a,b) ((void)L, l_mathop(pow)(a,b)) |
487 | |||
474 | #endif | 488 | #endif |
475 | 489 | ||
476 | /* these are quite standard operations */ | 490 | /* these are quite standard operations */ |
@@ -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); |