арифметика между большими примитивными числовыми типами: можно ли сохранить переполнение?

Отказ от ответственности: я знаю, целые числа без знака являются примитивными числовыми типами, но они не переполняются технически, я использую термин «переполнение» для всех примитивных числовых типов в целом здесь.

в C или C ++, в соответствии со стандартом или конкретной реализацией, существуют примитивные числовые типы, в которых задана арифметическая операция, даже если эта операция может переполниться, я могу сохранить результат + плюс часть, которая переполняется?

Даже если это звучит странно, моя идея состоит в том, что регистры на современных процессорах обычно намного больше, чем 32-битные float или 64 бит uint64_tТаким образом, существует возможность фактически контролировать переполнение и хранить его где-нибудь.

0

Решение

Нет, регистры не «обычно намного больше, чем 64-битные uint64_t».

Существует флаг переполнения, и для ограниченного числа операций (сложение и вычитание) достаточно объединения этого единственного дополнительного бита с результатом, чтобы охватить весь диапазон результатов.

Но в целом вам необходимо преобразовать данные в более крупный тип (возможно, реализованный в программном обеспечении) для обработки результатов, которые выходят за пределы типа вашего ввода.

Любые операции, которые делают подобные вещи (например, некоторые 32-разрядные процессоры имели инструкцию умножения 32×32 => 32, 32 или 32), будут предоставлены вашим компилятором как встроенные функции или через встроенную сборку.

смотри, я нашел 64-битную версию, названную Multiply128 а также соответствие __mul128 доступно в Visual C ++

3

Другие решения

Смотрите @Ben Voigt о больших регистрах.

На самом деле может быть только бит переполнения, который мог помочь тебе.

Другой подход, не прибегая к более широким целым числам, заключается в тестировании переполнения самостоятельно:

unsigned a,b,sum;
sum = a + b;
if (sum < a) {
OverflowDetected();  // mathematical result is `sum` + UINT_MAX + 1
}

Подобный подход для int,
Следующее, вероятно, может быть упрощено — просто не имейте под рукой.

[Редактировать] Мой нижний аппорач имеет потенциал UB. Для лучшего способа обнаружения int переполнение, см Более простой метод для обнаружения переполнения 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();
}
2

Для типа с плавающей точкой вы можете фактически контролировать переполнение на платформе x86. С этими функциями «_control87, _controlfp, __control87_2», Вы можете получить и установить управляющее слово с плавающей точкой. По умолчанию библиотеки времени выполнения маскируют все исключения с плавающей точкой; вы можете разоблачить их в своем коде, поэтому при переполнении вы получите исключение. Однако в коде, который мы пишем сегодня, все предполагают, что исключения с плавающей запятой замаскированы, поэтому, если вы снимите их, вы столкнетесь с некоторой проблемой.

Вы можете использовать эти функции чтобы получить статусное слово.

1

Для типов с плавающей запятой результаты хорошо определены аппаратным обеспечением, и вы не сможете получить много контроля, не работая с C / C ++.

Для целочисленных типов меньше чем intони будут увеличены до int любой арифметической операцией. Вероятно, вы сможете обнаружить переполнение, прежде чем вернуть результат в меньший тип.

Для сложения и вычитания вы можете обнаружить переполнение, сравнивая результат с входными данными. Добавление двух натуральных чисел всегда будет давать результат, больший, чем любой из входных данных, если только не было переполнения.

1
По вопросам рекламы [email protected]