tmult_ok(x, y)
терпит неудачу в любое время x*y
в int p = x*y;
переполняется, поскольку это неопределенное поведение (UB).
Он также терпит неудачу в угловом регистре, как tmult_ok(INT_MIN, -1)
по той же причине.
Это не переносимо "работает".
Альтернатива (и другие для /, -, + ), которая не зависит от дополнения 2.Обратите внимание, что это возвращает противоположность 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
}
Как я могу гарантировать, что p! = X * y при переполнении?
Переносимый код не может.С целочисленной математикой со знаком в C, переполнение UB.Код должен обнаружить потенциальное переполнение без предварительного умножения. @ Квентин @ Евгений Ш.
как мне доказать его правильность во всех случаях?
Сформируйте контрольный тест с использованием математики 2x.Если int
является 32-битным, сравните tmult_ok()
с умножением с использованием 64-битной математики и посмотрите, находится ли продукт в диапазоне. @ rici
int tmult_ok_ll(int x, int y) {
long long prod = x;
prod *= y;
return (prod >= INT_MIN && prod <= INT_MAX);
}
Попытка всех комбинаций - это грубый метод - вероятно, слишком долго для 32-битного int
.
Попробуйте подмножество всех комбинаций,для каждого x,y
попробуйте INT_MIN, INT_MIN-1, INT_MIN-2, -2,-1, 0, 1, 2, , INT_MAX-1, INT_MAX
.(10 * 10 тестов)
Также подмножество всех комбинаций, для каждого значения +/- в пределах 2 от sqrt(INT_MAX)
.(10 * 10 тестов)
Также было бы разумно несколько миллионов случайных значений в диапазоне int
.
Этого может быть недостаточно, однако, если код проходит это, очень малооставлены угловые случаи - которые очень зависят от вашего исходного кода.
См. также @ Eric Postpischil