Наиболее эффективное переносное обнаружение переполнения?
Возможный дубликат:
умножение больших чисел, как перехватить переполнение
В непосредственной близости от металлических языков, таких как C, С++ и D, наиболее эффективный разумно переносимый способ (т.е. без использования ассемблера, хотя вы можете предполагать арифметику с двумя дополнениями и поведение оболочки) для обнаружения переполнения без знака 64-разрядное целое число при умножении?
Ответы
Ответ 1
Вы можете заранее обнаружить переполнение путем деления максимального значения, представляемого неподписанным типом, на один из множителей; если результат меньше, чем другой мультипликатор, то их умножение приведет к значению, превышающему диапазон неподписанного типа.
Например, в С++ (с использованием числовых типов точной ширины С++ 0x):
std::uint64_t left = 12;
std::uint64_t right = 42;
if (left != 0 && (std::numeric_limits<std::uint64_t>::max() / left) < right)
{
// multiplication would exceed range of unsigned
}
В C вы можете использовать uint64_t
для типа и UINT64_MAX
для максимального значения. Или, если вам все равно, что тип шириной не менее 64 бит и не обязательно ровно 64 бита, вы можете использовать unsigned long long
и ULLONG_MAX
.
Ответ 2
Хороший ресурс:
http://www.fefe.de/intof.html
Ответ 3
Несколько ответов в этом почти дублированном вопросе. Этот ответ должен работать на языках C, С++ и других подобных языках:
if (b > 0 && a > 18446744073709551615 / b) {
// overflow handling
} else {
c = a * b;
}
Или этот ответ, который выполняет умножение, а затем делит результат на один из аргументов, чтобы убедиться, что он равен другому:
x = a * b;
if (a != 0 && x / a != b) {
// overflow handling
}
Ответ 4
Есть, вероятно, более эффективные методы, но это простой и переносимый способ сделать это:
// assume 'a' and 'b' are the operands to be multiplied
if( ( a != 0 ) && ( UINT64_MAX / a ) < b ) ) {
// overflow
}