Как обнаружить переполнение и переполнение двойной точки с двойной точностью?
У меня есть следующие переменные:
double dblVar1; double dblVar2;
Они могут иметь большие значения, но не более double
макс.
У меня есть различная арифметика над такими переменными, как сложение, умножение и мощность:
- C ++ десятичные типы данных
- Почему GCC не оптимизирует a * a * a * a * a * a to (a * a * a) * (a * a * a)?
- Как красиво форматировать плавающие числа в String без ненужного десятичного числа 0?
- Пример FloatingActionButton с библиотекой поддержки
- Почему Double.NaN == Double.NaN возвращает false?
double dblVar3 = dblVar1 * dblVar2; double dblVar4 = dblVar1 + dblVar2; double dblVar5 = pow(dblVar1, 2);
Во всем выше я должен проверить переполнение и недоиспользование. Как я могу достичь этого в C ++?
- Какова максимальная длина в символах, необходимых для представления любого двойного значения?
- Android Как реализовать нижний лист из документации по материальному дизайну
- C #: преобразовать массив байтов в float
- Почему C не имеет неподписанных поплавков?
- Как вы печатаете EXACT значение числа с плавающей запятой?
- Как выполнить поразрядную операцию с числами с плавающей запятой
- Деление с плавающей запятой против умножения с плавающей запятой
- поплавковые биты и строгий псевдоним
Многое зависит от контекста. Чтобы быть совершенно портативным, вы должны проверить перед операцией, например (для добавления):
if ( (a < 0.0) == (b < 0.0) && std::abs( b ) > std::numeric_limits::max() - std::abs( a ) ) { // Addition would overflow... }
Аналогичную логику можно использовать для четырех основных операторов.
Если все компьютеры, на которые настроена таргетинг, поддерживают IEEE (что, вероятно, имеет место, если вам не нужно учитывать мэйнфреймы), вы можете просто выполнять операции, а затем использовать isfinite
или isinf
для результатов.
Для нижнего streamа первый вопрос заключается в том, считается ли постепенное недоисполнение недостаточным или нет. Если нет, то просто проверьте, равны ли результаты, а a != -b
выполнит трюк. Если вы хотите обнаружить постепенное переполнение (возможно, только в том случае, если у вас есть IEEE), вы можете использовать isnormal
– это вернет false, если результаты соответствуют постепенному переполнению. (В отличие от переполнения, после операции вы проверяете «underflow»).
POSIX, C99, C ++ 11 имеют
(и
для C ++ 11), которые имеют функции для проверки флажков исключений IEEE754 (которые не имеют ничего общего с исключениями C ++, это было бы слишком просто) :
int feclearexcept(int); int fegetexceptflag(fexcept_t *, int); int feraiseexcept(int); int fesetexceptflag(const fexcept_t *, int); int fetestexcept(int);
Флаг является битовым полем со следующими битами:
FE_DIVBYZERO FE_INEXACT FE_INVALID FE_OVERFLOW FE_UNDERFLOW
Таким образом, вы можете очистить их перед операциями, а затем проверить их после. Вам нужно будет проверить документацию о влиянии функций библиотеки на них.
С достойным компилятором (который поддерживает новейший стандарт C ++) вы можете использовать следующие функции:
#include #include int main() { std::feclearexcept(FE_OVERFLOW); std::feclearexcept(FE_UNDERFLOW); double overflowing_var = 1000; double underflowing_var = 0.01; std::cout << "Overflow flag before: " << (bool)std::fetestexcept(FE_OVERFLOW) << std::endl; std::cout << "Underflow flag before: " << (bool)std::fetestexcept(FE_UNDERFLOW) << std::endl; for(int i = 0; i < 20; ++i) { overflowing_var *= overflowing_var; underflowing_var *= underflowing_var; } std::cout << "Overflow flag after: " << (bool)std::fetestexcept(FE_OVERFLOW) << std::endl; std::cout << "Underflow flag after: " << (bool)std::fetestexcept(FE_UNDERFLOW) << std::endl; } /** Output: Overflow flag before: 0 Underflow flag before: 0 Overflow flag after: 1 Underflow flag after: 1 */
ISO C99 определяет функции для запроса и обработки слова состояния с плавающей запятой. Вы можете использовать эти функции для проверки исключенных исключений, когда это удобно, а не беспокоиться о них в середине расчета.
Это обеспечивает
FE_INEXACT FE_DIVBYZERO FE_UNDERFLOW FE_OVERFLOW FE_INVALID
Например
{ double f; int raised; feclearexcept (FE_ALL_EXCEPT); f = compute (); raised = fetestexcept (FE_OVERFLOW | FE_INVALID); if (raised & FE_OVERFLOW) { /* ... */ } if (raised & FE_INVALID) { /* ... */ } /* ... */ }
http://www.gnu.org/software/libc/manual/html_node/Status-bit-operations.html