Наиболее эффективное переносное обнаружение переполнения?

Возможный дубликат:
умножение больших чисел, как перехватить переполнение

В непосредственной близости от металлических языков, таких как 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.

Ответ 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
}