问题
In one of the books that I am reading, following function is used to determine 2's complement integer multiplication overflow.
int tmult_ok(int x, int y) {
int p = x*y;
return !x || p/x == y;
}
While this works, how do I prove its correctness in all the cases? How do I ensure that p != x*y when there is an overflow?
Here is what I understand:
- When you multiply 2 integers of size "w- bits", the result can be 2w bits.
- The computation truncates higher order w bits. So we are left with lower order w bits. 3.Let us say that P = lowest w-bits
- Then, we need to prove that (P/x != y) and (P/y !=x) when there is overflow.
- My confusion lies here. How can you say that (P/x !=y) when there is no overflow? Isn't it possible that the bit pattern of P when divided by x could yield y even when there is an overflow?
回答1:
tmult_ok(x, y)
fails anytime x*y
in int p = x*y;
overflows as that is undefined behavior (UB).
It also fails a corner case like tmult_ok(INT_MIN, -1)
for the same reason.
It does not portably "work".
An alternative (and others for /,-,+) which does not depend on 2's complement. Notice this returns the opposite of tmult_ok()
.
int is_undefined_mult1(int a, int b) {
if (a > 0) {
if (b > 0) {
return a > INT_MAX / b; // a positive, b positive
}
return b < INT_MIN / a; // a positive, b not positive
}
if (b > 0) {
return a < INT_MIN / b; // a not positive, b positive
}
return a != 0 && b < INT_MAX / a; // a not positive, b not positive
}
How do I ensure that p != x*y when there is an overflow?
Portable code cannot. With signed integer math in C, overflow is UB. Code should detect a potential overflow without first performing the multiplication. @Quentin @Eugene Sh.
how do I prove its correctness in all the cases?
Form a reference test with uses 2x wide math. If int
is 32-bit, compare tmult_ok()
to a multiplication using 64-bit math and see if the product in in range. @rici
int tmult_ok_ll(int x, int y) {
long long prod = x;
prod *= y;
return (prod >= INT_MIN && prod <= INT_MAX);
}
Trying all combinations is a brute force approach - likely too long for 32-bit int
.
Try a subset of all combinations, for each x,y
,try INT_MIN, INT_MIN-1, INT_MIN-2, -2,-1, 0, 1, 2, , INT_MAX-1, INT_MAX
. (10*10 tests)
Also a subset of all combinations, for each values +/- within 2 of sqrt(INT_MAX)
. (10*10 tests)
Also a few million random values in the int
range would be prudent.
This may not be sufficient, yet if code passes this, there are very few corner cases left - which are very dependent on your source code.
See also @Eric Postpischil
回答2:
overflow like underflow are undefined behavior meaning that the compiler can consider they never happen and simplify code that depend on it.so you can't detect if an overflow has already occurred
instead should check if an operation that might overflow is going to overflow
int tmult_ok(int x, int y) {
if (MAX_INT / y >= x)
//throw somthing
return x*y;
}
回答3:
You can check the overflow flag (https://en.wikipedia.org/wiki/Overflow_flag)
In computer processors, the overflow flag (sometime called V flag) is usually a single bit in a system status register used to indicate when an arithmetic overflow has occurred in an operation, indicating that the signed two's-complement result would not fit in the number of bits used for the operation (the ALU width).
Example of how to access it: https://www.linuxquestions.org/questions/programming-9/c-how-to-check-the-overflow-flag-930420/#post4612830
来源:https://stackoverflow.com/questions/50684187/how-do-you-detect-2s-complement-multiplication-overflow