Отказ от ответственности: я знаю, что целые числа без знака являются примитивными числовыми типами, но они не переполняются технически, я использую термин "переполнение" для всех примитивных числовых типов вообще.
в C или C++, в соответствии со стандартом или конкретной реализацией, существуют примитивные числовые типы, где задана арифметическая операция, даже если эта операция может переполняться, я могу сохранить результат + плюс часть, которая переполняется?
Даже если это звучит странно, моя идея состоит в том, что регистры на современных процессорах обычно намного больше, чем 32-битный float
или 64-разрядный uint64_t
, поэтому существует возможность фактически контролировать переполнение и хранить его где-то.
Нет, регистры не "обычно намного больше 64 бит uint64_t
".
Там флаг переполнения и для ограниченного числа операций (сложение и вычитание), сопряжение этого единственного дополнительного бита с результатом достаточно, чтобы охватить весь диапазон результатов.
Но в целом вам нужно будет использовать более крупный тип (потенциально реализованный в программном обеспечении) для обработки результатов, которые переполняют тип ввода.
Любые операции, которые делают такие вещи (например, у некоторых 32-разрядных процессоров была 32x32 => 32 высокая, 32 низкоуровневая команда умножения) будут предоставлены вашим компилятором в качестве встроенных функций или встроенной сборкой.
Посмотрите, я нашел 64-битную версию, названную Multiply128, и соответствующий __mul128
instrinsic, доступный в Visual C++
См. @Ben Voigt о более крупных регистрах.
На самом деле может быть только бит переполнения, который мог бы вам помочь.
Другой подход, не прибегая к более широким целям, состоит в том, чтобы проверить переполнение себя:
unsigned a,b,sum;
sum = a + b;
if (sum < a) {
OverflowDetected(); // mathematical result is 'sum' + UINT_MAX + 1
}
Аналогичный подход для int
.
Возможно, это может быть упрощено: просто не делайте этого.
[Edit] Мой ниже apporach имеет potentila UB. Для лучшего способа обнаружения переполнения int
см. Метод Simpler для обнаружения переполнения int
int a,b,sum;
sum = a + b;
// out-of-range only possible when the signs are the same.
if ((a < 0) == (b < 0)) {
if (a < 0) {
if (sum > b) UnderflowDetected();
}
else {
if (sum < b) OverflowDetected();
}
bool f(unsigned a, unsigned b) { return a + b < a; }
оптимизирован компилятором GNU для addl %edi, %esi; setb %al; ret
Насколько это круто?
Для типа с плавающей точкой вы можете "контролировать" переполнение на платформе x86. С помощью этих функций "_control87, _controlfp, __control87_2" вы можете получить и установить управляющее слово с плавающей запятой. По умолчанию библиотеки времени выполнения маскируют все исключения с плавающей запятой; вы можете разоблачить их в своем коде, поэтому, когда произойдет переполнение, вы получите исключение. Однако код, который мы пишем сегодня, все предполагают, что исключения с плавающей запятой маскируются, поэтому, если вы разоблачите их, вы столкнетесь с некоторыми проблемами.
Вы можете использовать эти функции, чтобы получить слово состояния.
Для типов с плавающей точкой результаты хорошо определены аппаратным обеспечением, и вы не сможете получить большой контроль, не работая с C/C++.
Для целых типов, меньших, чем int
, они будут увеличены до int
посредством любой арифметической операции. Вероятно, вы сможете обнаружить переполнение до того, как вы вернете результат обратно в меньший тип.
Для сложения и вычитания вы можете обнаружить переполнение, сравнивая результат с входами. Добавление двух положительных целых чисел всегда даст результат, больший, чем любой из входов, если только не было переполнения.
unsigned short * unsigned short
.
int
,unsigned int
иfloat
илиdouble
основном, все примитивные типы. Плюс вариации какshort
иlong
.