Как я использую попытку … выгода для фиксации ошибок с плавающей точкой?

Я использую C++ в экспрессе Visual Studio для генерации случайных деревьев выражений для использования в типе генетического алгоритма программы.

Поскольку они случайны, деревья часто генерируют: разделитесь на нуль, переполнение, потерю значимости, а также возвращающийся "inf" и другие строки. Я могу записать обработчики для строк, но литература оставила меня экранированным о других. Если я понимаю это правильно, я должен установить некоторые флаги сначала?

Совет и/или указатель на некоторую литературу ценились бы.Править: значения, возвращенные в двойной переменной, 1.#INF или-1.#IND. Я был неправ назвать их строками.

11
задан Peter Stewart 5 May 2010 в 10:02
поделиться

3 ответа

Вы уверены, что хотите поймать их, а не просто игнорировать? Предполагая, что вы хотите просто игнорировать их:

См. это: http://msdn.microsoft.com/en-us/library/c9676k6h.aspx

Для маски _MCW_EM очистка маски устанавливает исключение, что позволяет аппаратное исключение; установка маски скрывает исключение.

Поэтому вы захотите сделать что-то вроде этого:

#include <float.h>
#pragma fenv_access (on)

void main()
{
    unsigned int fp_control_word;
    unsigned int new_fp_control_word;

    _controlfp_s(&fp_control_word, 0, 0);

    // Make the new fp env same as the old one,
    // except for the changes we're going to make
    new_fp_control_word = fp_control_word | _EM_INVALID | _EM_DENORMAL | _EM_ZERODIVIDE | _EM_OVERFLOW | _EM_UNDERFLOW | _EM_INEXACT;
    //Update the control word with our changes
    _controlfp_s(&fp_control_word, new_fp_control_word, _MCW_EM)


}

Некоторая путаница здесь может быть связана с использованием слова "исключение". В C++ это обычно относится к встроенной в язык системе обработки исключений. Исключения с плавающей запятой - это совсем другой зверь. Все исключения, которые должен поддерживать стандартный FPU, определены в стандарте IEEE-754. Они происходят внутри блока с плавающей точкой, который может делать разные вещи в зависимости от того, как настроены управляющие флаги блока с плавающей точкой. Обычно происходит одно из двух: 1) Исключение игнорируется, и FPU устанавливает флаг, указывающий на возникновение ошибки, в своем регистре (регистрах) состояния. 2) Исключение не игнорируется FPU, поэтому вместо него генерируется прерывание, и вызывается обработчик прерывания, который был установлен для ошибок с плавающей запятой. Обычно это делает что-нибудь приятное для вас, например, заставляет вас прерваться на этой строке кода в отладчике или генерирует файл ядра.

Подробнее о IEE-754 вы можете узнать здесь: http://www.openwatcom.org/ftp/devel/docs/ieee-754.pdf

Некоторые дополнительные ссылки по плавающей точке: http://docs.sun.com/source/806-3568/ncg_goldberg.html http://floating-point-gui.de/

7
ответ дан 3 December 2019 в 07:36
поделиться

Никогда не пробовал, но если предположить, что деление на ноль вызывает исключение, вы можете просто заключить код в команду try / catch следующим образом:

try { // потенциальное деление на ноль ... } catch (...) { // ... перехватывает ВСЕ исключения }

{ {1}}
-2
ответ дан 3 December 2019 в 07:36
поделиться

Среда выполнения C++ не окажет вам здесь ни малейшей помощи. Вам придется выполнять эти проверки самостоятельно, явно в своем коде. Если, конечно, функции, которые вы вызываете, не выполняют эти проверки - в этом случае все зависит от того, как они поведут себя в случае ошибки.

Позвольте мне объяснить:

double divide(double a, double b) {
    return a / b;  // undefined if b is zero
}

Должно быть на самом деле

double divide(double a, double b) {
    if( b == 0 ) {
        // throw, return, flag, ...  you choose how to signal the error
    }
    return a / b;  // b can't possibly be zero here
}

Если код, который не работает при делении на ноль и тому подобном, не ваш, то вам придется копнуть глубже, чтобы найти, что он делает в случае угрозы ошибки. Выбрасывает ли он? Устанавливает флаг? Спросите автора и/или прочитайте источник.

Вот пример для исключения:

struct bad_value : public std::exception { };

double divide(double a, double b) {
    if( b == 0 ) throw bad_value("Division by zero in divide()");
    return a / b;  // b can't possibly be zero here
}

// elsewhere (possibly in a parallel universe) ...

    try {
        double r1 = divide(5,4);
        double r2 = divide(5,0);
    } catch( bad_value e ) {
        // ...
    }
1
ответ дан 3 December 2019 в 07:36
поделиться
Другие вопросы по тегам:

Похожие вопросы: