Можно ли получить доступ к регистру флага переполнения в ЦП с С++?

После выполнения математической операции, например, умножения двух целых чисел, можно ли получить доступ к регистру флага переполнения в ЦП с C++? Если нет, то каковы другие быстрые способы проверки переполнения?


person Loers Antario    schedule 16.01.2013    source источник
comment
Проверьте этот stackoverflow. ком/вопросы/199333/   -  person acrilige    schedule 16.01.2013
comment
@acrilige спасибо, это отвечает на вторую часть моего вопроса, есть идеи о том, как проверить переполнение ПОСЛЕ выполнения вычислений?   -  person Loers Antario    schedule 16.01.2013
comment
По понятным причинам невозможно получить прямой доступ к регистру флага переполнения стандартным переносимым способом. Однако вы можете определить, будет ли операция переполняться, приложив немного усилий, и есть способы проверить это или обнаружить переполнение нестандартным непереносимым способом.   -  person Robert Mason    schedule 16.01.2013
comment
Почему нельзя проверить переполнение перед расчетами?   -  person acrilige    schedule 16.01.2013
comment
Разделите результат на множимое. Если вы не вернете множитель, значит, он переполнен.   -  person Hans Passant    schedule 16.01.2013


Ответы (5)


Нет, вообще это невозможно. Некоторые процессоры даже не имеют такого флага (например, MIPS).

ссылка, представленная в одном из комментариев, даст вам идеи о том, как вы можете выполнять проверки переполнения.

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

person Alexey Frunze    schedule 16.01.2013

Я рекомендую это чтение в каждом подходящем случае. Из Оптимизация программного обеспечения на C++ -

Целочисленное переполнение — еще одна проблема безопасности. Официальный стандарт C говорит, что поведение целых чисел со знаком в случае переполнения "не определено". Это позволяет компилятору игнорировать переполнение или предположить, что оно не происходит. В случае с компилятором Gnu предположение об отсутствии переполнения целого числа со знаком имеет неблагоприятное последствие, заключающееся в том, что оно позволяет компилятору оптимизировать проверку переполнения. Существует ряд возможных способов решения этой проблемы: (1) проверять переполнение до того, как оно произойдет, (2) использовать целые числа без знака — они гарантированно переходят друг в друга, (3) перехватывать целочисленное переполнение с помощью параметра -ftrapv, но это чрезвычайно неэффективно, (4) получить предупреждение компилятора о такой оптимизации с помощью опции -Wstrict-overflow=2 или (5) четко определить поведение переполнения с помощью опции -fwrapv или -fno-strict-overflow.

person SChepurin    schedule 16.01.2013

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

person Ted Percival    schedule 13.03.2018
comment
Странно, что никто больше не упомянул эту опцию. Хотя встроенный ассемблер не является строго C++, это абсолютно приемлемый вариант для всех, кто задает этот вопрос. Конечно, есть ограничение, что он не будет компилироваться для всех архитектур, но это зависит от OP, чтобы решить, важно это или нет. - person Joseph Summerhays; 15.07.2021

Нет. Лучший способ проверить заранее, как здесь

Если нет, то каковы другие быстрые способы проверки переполнения?

Если вам нужно протестировать после операции, вы можете использовать представление с плавающей запятой (двойная точность) - каждое 32-битное целое число может быть представлено точно как число с плавающей запятой. Если все машины, на которые вы нацелены, поддерживают IEEE (что, вероятно, так и есть, если вам не нужно рассматривать мейнфреймы), вы можете просто выполнять операции, а затем использовать isfinite или isinf для результатов. Быстрый (с точки зрения усилий программиста) способ: Стандарт IEEE для арифметики с плавающей запятой (IEEE 754) определяет пять исключений, каждое из которых возвращает значение по умолчанию и имеет соответствующий флаг состояния, который (за исключением некоторых случаев потери значимости) возникает при возникновении исключения. Пять возможных исключений:

  • Недопустимая операция: математически неопределенная, например, квадратный корень из отрицательного числа. По умолчанию возвращает qNaN.
  • Деление на ноль: операция над конечными операндами дает точный бесконечный результат, например, 1/0 или log(0). По умолчанию возвращает ±бесконечность.
  • Переполнение: результат слишком велик для правильного представления (т. е. его показатель степени с неограниченным диапазоном показателей будет больше, чем emax). По умолчанию возвращает ±бесконечность для режимов округления до ближайшего (и следует правилам округления для режимов направленного округления).
  • Underflow: результат очень маленький (за пределами нормального диапазона) и неточный. По умолчанию возвращает субнормальное значение или ноль (в соответствии с правилами округления).
  • Неточный: точный (т.е. неокругленный) результат не может быть точно представлен. По умолчанию возвращает правильно округленный результат.
person Vlad Novakovsky    schedule 12.04.2020
comment
Обратите внимание, что этот вопрос помечен integer-overflow и касается переполнения целого числа со знаком. Не переполнение FP до +-Inf. Вы можете получить доступ к флагам FP через fenv: en.cppreference.com /w/c/числовой/fenv. fetestexcept(FE_OVERFLOW) проверяет флаг переполнения FP. (Правильно работает, только если вы используете #pragma STDC FENV_ACCESS ON или параметры командной строки для некоторых компиляторов. ru. cppreference.com/w/c/numeric/fenv/fetestexcept есть пример.) - person Peter Cordes; 12.04.2020
comment
Я вижу - каждое целое число может быть представлено как число с плавающей запятой, и других быстрых способов нет. Кроме предварительной проверки. - person Vlad Novakovsky; 13.04.2020
comment
double может представлять каждый int32_t, но не каждый int64_t. Так что да, вы можете проверить диапазон double перед преобразованием обратно в int. Это вряд ли эффективно, так что ИДК, в чем ваша точка зрения. Некоторые машины будут иметь 80-битную или более широкую long double, которая может представлять каждую int64_t, но многие реализации C++ имеют только 64-битную FP. Кроме того, переполнение FP не имеет отношения к этой проблеме (если только вы не выполняете несколько умножений, которые фактически приводят к переполнению FP). - person Peter Cordes; 13.04.2020
comment
число с плавающей запятой с двойной точностью ограничено 10^308. Более 10^64. IEEE 754 поддерживает одинарную и двойную точность. - person Vlad Novakovsky; 13.04.2020
comment
Да, это наивысшее конечное double, но первое непредставимое целочисленное double равно 2^53 + 1, потому что оно имеет 53-битную мантисса. en.wikipedia.org/wiki/Double-precision_format_floating-point. 64-битный double может представлять некоторые числа, отличные от возможных значений int64_t, поэтому по принципу сортировки должны быть некоторые значения int64_t, которые не имеют double битового шаблона для их представления. См. Какое первое целое число не может быть точно представлено числом с плавающей запятой IEEE 754? - person Peter Cordes; 13.04.2020
comment
Скорее всего вы пишете. Затем этот подход можно использовать для 32-битных целых чисел. Странно - я предполагаю, что в С# преобразование из любого целого числа, включая 64-битное, неявно преобразуется в двойное. А неявное преобразование касается только приведения без потери информации. Но вы заметили, что мантисса, вероятно, правильная - в представлении должны быть пробелы - потеря точности - person Vlad Novakovsky; 13.04.2020
comment
Определенно вы пишете: принцип сортировки можно распространить на множества, сформулировав его в терминах количественных чисел: если мощность множества L больше, чем мощность множества D, то инъекция из L в D невозможна. 2) Оба double и long long (int64_t) имеют 2^64 состояния. Пусть L — это набор возможных длинных значений int64_t, а D — это набор возможных двойных значений (не NaN). Некоторые состояния в double используются для сигнальных значений, поэтому мощность L больше, чем мощность D, и нет инъекции из L в D. - person Vlad Novakovsky; 13.04.2020
comment
Да, помимо сигнализации NaN, double также имеет множество нецелочисленных значений. Половина double битовых шаблонов представляют значения от -1,0 до +1,0, и между меньшими целыми числами есть много дробных значений. (К вашему сведению, английское слово, которое вы здесь ищете, правильное, а не писать. Произносится одинаково, пишется по-разному.) Я не только что изобрел это доказательство; это общеизвестный факт. Но рад, что смог помочь и указать на это вам. В любом случае, вам может понравиться randomascii.wordpress. com/2012/02/25/ — отличная серия статей о FP - person Peter Cordes; 13.04.2020
comment
Спасибо-хорошая статья. Я помню про (0..1) - для доказательства достаточно упомянуть разную мощность. Также я боялся, что в моей книге по C# есть ошибка: Неявные преобразования разрешены, если выполняются оба следующих условия: 1) Компилятор может гарантировать, что они всегда будут успешными. 2) При преобразовании информация не теряется. Но я не заметил, что в нижнем колонтитуле книги есть примечание: небольшая оговорка заключается в том, что очень большие длинные значения теряют некоторую точность при преобразовании в двойные... Это связано с тем, что типы с плавающей запятой всегда имеют большую величину, чем целочисленные типы, но могут иметь меньше точности. Так что книга правильная. - person Vlad Novakovsky; 13.04.2020

Это, вероятно, не то, что вы хотите сделать по двум причинам:

  1. не каждый процессор имеет флаг переполнения
  2. используя С++, на самом деле нет способа получить доступ к флагу переполнения

советы по проверке переполнения, которые люди размещали ранее, могут быть полезны.

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

person abhoriel    schedule 28.01.2013