mirror of
https://github.com/gbdev/rgbds.git
synced 2025-11-20 10:12:06 +00:00
Fix division and modulo for very large negative numbers (#1790)
This commit is contained in:
@@ -11,15 +11,16 @@
|
|||||||
int32_t op_divide(int32_t dividend, int32_t divisor) {
|
int32_t op_divide(int32_t dividend, int32_t divisor) {
|
||||||
// Adjust division to floor toward negative infinity,
|
// Adjust division to floor toward negative infinity,
|
||||||
// not truncate toward zero
|
// not truncate toward zero
|
||||||
return dividend / divisor - ((dividend % divisor < 0) != (divisor < 0));
|
int32_t remainder = dividend % divisor;
|
||||||
|
return dividend / divisor - (remainder != 0 && (remainder < 0) != (divisor < 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t op_modulo(int32_t dividend, int32_t divisor) {
|
int32_t op_modulo(int32_t dividend, int32_t divisor) {
|
||||||
int32_t remainder = dividend % divisor;
|
|
||||||
|
|
||||||
// Adjust modulo to have the sign of the divisor,
|
// Adjust modulo to have the sign of the divisor,
|
||||||
// not the sign of the dividend
|
// not the sign of the dividend
|
||||||
return remainder + divisor * ((remainder < 0) != (divisor < 0));
|
return static_cast<int32_t>(
|
||||||
|
dividend - static_cast<int64_t>(op_divide(dividend, divisor)) * divisor
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t op_exponent(int32_t base, uint32_t power) {
|
int32_t op_exponent(int32_t base, uint32_t power) {
|
||||||
|
|||||||
47
test/asm/div-negative.asm
Normal file
47
test/asm/div-negative.asm
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
MACRO test
|
||||||
|
def num = \1
|
||||||
|
def den = \2
|
||||||
|
def quo = num / den
|
||||||
|
def rem = num % den
|
||||||
|
def rev = quo * den + rem
|
||||||
|
assert num == rev
|
||||||
|
println "{ 11d:num} (${08x:num}) / { 11d:den} (${08x:den}) = { 11d:quo} (${08x:quo}) R { 11d:rem} (${08x:rem})"
|
||||||
|
ENDM
|
||||||
|
|
||||||
|
test $8000_0000, $8000_0000
|
||||||
|
test $8000_0000, $c000_0000
|
||||||
|
test $8000_0000, $f000_0000
|
||||||
|
test $8000_0000, $f800_0000
|
||||||
|
test $8000_0000, $ff00_0000
|
||||||
|
|
||||||
|
test $c000_0000, $8000_0000
|
||||||
|
test $c000_0000, $c000_0000
|
||||||
|
test $c000_0000, $f000_0000
|
||||||
|
test $c000_0000, $f800_0000
|
||||||
|
test $c000_0000, $ff00_0000
|
||||||
|
|
||||||
|
test $f800_0000, $8000_0000
|
||||||
|
test $f800_0000, $c000_0000
|
||||||
|
test $f800_0000, $f000_0000
|
||||||
|
test $f800_0000, $f800_0000
|
||||||
|
test $f800_0000, $ff00_0000
|
||||||
|
|
||||||
|
test $0000_0000, $8000_0000
|
||||||
|
test $0000_0000, $c000_0000
|
||||||
|
test $0000_0000, $f000_0000
|
||||||
|
test $0000_0000, $f800_0000
|
||||||
|
test $0000_0000, $ff00_0000
|
||||||
|
|
||||||
|
test $0080_0000, $ff80_0000
|
||||||
|
|
||||||
|
test $0300_0000, $fd00_0000
|
||||||
|
test $0300_0000, $ff00_0000
|
||||||
|
test $0300_0000, $ff80_0000
|
||||||
|
|
||||||
|
test $6000_0000, $fd00_0000
|
||||||
|
test $6000_0000, $ff00_0000
|
||||||
|
test $6000_0000, $ff80_0000
|
||||||
|
|
||||||
|
test $7f00_0000, $fd00_0000
|
||||||
|
test $7f00_0000, $ff00_0000
|
||||||
|
test $7f00_0000, $ff80_0000
|
||||||
30
test/asm/div-negative.out
Normal file
30
test/asm/div-negative.out
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
-2147483648 ($80000000) / -2147483648 ($80000000) = 1 ($00000001) R 0 ($00000000)
|
||||||
|
-2147483648 ($80000000) / -1073741824 ($c0000000) = 2 ($00000002) R 0 ($00000000)
|
||||||
|
-2147483648 ($80000000) / -268435456 ($f0000000) = 8 ($00000008) R 0 ($00000000)
|
||||||
|
-2147483648 ($80000000) / -134217728 ($f8000000) = 16 ($00000010) R 0 ($00000000)
|
||||||
|
-2147483648 ($80000000) / -16777216 ($ff000000) = 128 ($00000080) R 0 ($00000000)
|
||||||
|
-1073741824 ($c0000000) / -2147483648 ($80000000) = 0 ($00000000) R -1073741824 ($c0000000)
|
||||||
|
-1073741824 ($c0000000) / -1073741824 ($c0000000) = 1 ($00000001) R 0 ($00000000)
|
||||||
|
-1073741824 ($c0000000) / -268435456 ($f0000000) = 4 ($00000004) R 0 ($00000000)
|
||||||
|
-1073741824 ($c0000000) / -134217728 ($f8000000) = 8 ($00000008) R 0 ($00000000)
|
||||||
|
-1073741824 ($c0000000) / -16777216 ($ff000000) = 64 ($00000040) R 0 ($00000000)
|
||||||
|
-134217728 ($f8000000) / -2147483648 ($80000000) = 0 ($00000000) R -134217728 ($f8000000)
|
||||||
|
-134217728 ($f8000000) / -1073741824 ($c0000000) = 0 ($00000000) R -134217728 ($f8000000)
|
||||||
|
-134217728 ($f8000000) / -268435456 ($f0000000) = 0 ($00000000) R -134217728 ($f8000000)
|
||||||
|
-134217728 ($f8000000) / -134217728 ($f8000000) = 1 ($00000001) R 0 ($00000000)
|
||||||
|
-134217728 ($f8000000) / -16777216 ($ff000000) = 8 ($00000008) R 0 ($00000000)
|
||||||
|
0 ($00000000) / -2147483648 ($80000000) = 0 ($00000000) R 0 ($00000000)
|
||||||
|
0 ($00000000) / -1073741824 ($c0000000) = 0 ($00000000) R 0 ($00000000)
|
||||||
|
0 ($00000000) / -268435456 ($f0000000) = 0 ($00000000) R 0 ($00000000)
|
||||||
|
0 ($00000000) / -134217728 ($f8000000) = 0 ($00000000) R 0 ($00000000)
|
||||||
|
0 ($00000000) / -16777216 ($ff000000) = 0 ($00000000) R 0 ($00000000)
|
||||||
|
8388608 ($00800000) / -8388608 ($ff800000) = -1 ($ffffffff) R 0 ($00000000)
|
||||||
|
50331648 ($03000000) / -50331648 ($fd000000) = -1 ($ffffffff) R 0 ($00000000)
|
||||||
|
50331648 ($03000000) / -16777216 ($ff000000) = -3 ($fffffffd) R 0 ($00000000)
|
||||||
|
50331648 ($03000000) / -8388608 ($ff800000) = -6 ($fffffffa) R 0 ($00000000)
|
||||||
|
1610612736 ($60000000) / -50331648 ($fd000000) = -32 ($ffffffe0) R 0 ($00000000)
|
||||||
|
1610612736 ($60000000) / -16777216 ($ff000000) = -96 ($ffffffa0) R 0 ($00000000)
|
||||||
|
1610612736 ($60000000) / -8388608 ($ff800000) = -192 ($ffffff40) R 0 ($00000000)
|
||||||
|
2130706432 ($7f000000) / -50331648 ($fd000000) = -43 ($ffffffd5) R -33554432 ($fe000000)
|
||||||
|
2130706432 ($7f000000) / -16777216 ($ff000000) = -127 ($ffffff81) R 0 ($00000000)
|
||||||
|
2130706432 ($7f000000) / -8388608 ($ff800000) = -254 ($ffffff02) R 0 ($00000000)
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
def fzero equs "startof(\"test\")"
|
def fzero equs "startof(\"test\")"
|
||||||
section "test", rom0
|
section "test", rom0
|
||||||
ld a, $8000_0000 / (fzero - 1)
|
ld a, $8000_0000 / (fzero - 1)
|
||||||
|
ld a, $8000_0000 / (fzero - 2)
|
||||||
ld a, 1 << (fzero - 1)
|
ld a, 1 << (fzero - 1)
|
||||||
ld a, 1 << (fzero + 32)
|
ld a, 1 << (fzero + 32)
|
||||||
ld a, (fzero - 1) >> 1
|
ld a, (fzero - 1) >> 1
|
||||||
|
|||||||
@@ -1,16 +1,18 @@
|
|||||||
warning: Shifting right by large amount 32 [-Wshift-amount]
|
warning: Shifting right by large amount 32 [-Wshift-amount]
|
||||||
|
at patch-diagnostics.asm(11)
|
||||||
|
warning: Shifting right by negative amount -1 [-Wshift-amount]
|
||||||
at patch-diagnostics.asm(10)
|
at patch-diagnostics.asm(10)
|
||||||
warning: Shifting right by negative amount -1 [-Wshift-amount]
|
|
||||||
at patch-diagnostics.asm(9)
|
|
||||||
warning: Shifting right by large amount 32 [-Wshift-amount]
|
warning: Shifting right by large amount 32 [-Wshift-amount]
|
||||||
at patch-diagnostics.asm(8)
|
at patch-diagnostics.asm(9)
|
||||||
warning: Shifting right by negative amount -1 [-Wshift-amount]
|
warning: Shifting right by negative amount -1 [-Wshift-amount]
|
||||||
at patch-diagnostics.asm(7)
|
at patch-diagnostics.asm(8)
|
||||||
warning: Shifting right negative value -1 [-Wshift]
|
warning: Shifting right negative value -1 [-Wshift]
|
||||||
at patch-diagnostics.asm(6)
|
at patch-diagnostics.asm(7)
|
||||||
warning: Shifting left by large amount 32 [-Wshift-amount]
|
warning: Shifting left by large amount 32 [-Wshift-amount]
|
||||||
at patch-diagnostics.asm(5)
|
at patch-diagnostics.asm(6)
|
||||||
warning: Shifting left by negative amount -1 [-Wshift-amount]
|
warning: Shifting left by negative amount -1 [-Wshift-amount]
|
||||||
|
at patch-diagnostics.asm(5)
|
||||||
|
warning: Value $40000000 is not 8-bit [-Wtruncation]
|
||||||
at patch-diagnostics.asm(4)
|
at patch-diagnostics.asm(4)
|
||||||
warning: Division of -2147483648 by -1 yields -2147483648 [-Wdiv]
|
warning: Division of -2147483648 by -1 yields -2147483648 [-Wdiv]
|
||||||
at patch-diagnostics.asm(3)
|
at patch-diagnostics.asm(3)
|
||||||
|
|||||||
Reference in New Issue
Block a user