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

0

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

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

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

  • 2
    Вы уверены, что действительно имеете в виду типы POD ? не скалярные типы?
  • 0
    @BryanChen чертовы аббревиатуры, всегда есть кто-то еще, кто интерпретирует вещи по-другому! Хорошо, я имею в виду int , unsigned int и float или double основном, все примитивные типы. Плюс вариации как short и long .
Показать ещё 11 комментариев
Теги:
math
primitive-types
primitive

4 ответа

3
Лучший ответ

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

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

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

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

Посмотрите, я нашел 64-битную версию, названную Multiply128, и соответствующий __mul128 instrinsic, доступный в Visual C++

  • 0
    Регистры AVX имеют ширину даже 256 бит, это 64 бит 4 ...
  • 0
    @ user2485710: регистр AVX не является одной 256-битной величиной, он действует скорее как массив отключенных меньших регистров.
Показать ещё 4 комментария
2

См. @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();
  }
  • 1
    Ничего себе, bool f(unsigned a, unsigned b) { return a + b < a; } оптимизирован компилятором GNU для addl %edi, %esi; setb %al; ret Насколько это круто?
1

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

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

  • 3
    Если вы используете компилятор Microsoft на платформе x86.
  • 0
    @Oli: Имена могут отличаться, но все компиляторы для x86 должны предоставить это.
1

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

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

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

  • 0
    что вы имеете в виду под "вероятно, быть в состоянии обнаружить переполнение"? Как ?
  • 0
    @ user2485710, посмотрев на результат, чтобы увидеть, является ли он больше, чем может вместить меньший тип. Я могу думать только об одном случае, когда он не улавливает каждое переполнение - unsigned short * unsigned short .

Ещё вопросы

Сообщество Overcoder
Наверх
Меню