Могут ли два двойника быть равными и не равными одновременно?

У меня очень странная ошибка в моей программе. Я не смог выделить ошибку в воспроизводимом коде, но в определенном месте в моем коде есть:

    double distance, criticalDistance;
...

if (distance > criticalDistance)
{
std::cout << "first branch" << std::endl;
}
if (distance == criticalDistance)
{
std::cout << "second branch" << std::endl;
}

В отладочной сборке все нормально. Выполняется только одна ветвь.

Но в релизной сборке все чертовски рвется и иногда обе ветви исполняются.

Это очень странно, так как, если я добавлю еще условно:

    if (distance > criticalDistance)
{
std::cout << "first branch" << std::endl;
}
else if (distance == criticalDistance)
{
std::cout << "second branch" << std::endl;
}

Такого не бывает.

Пожалуйста, что может быть причиной этого? я использую gcc 4.8.1 на Ubuntu 13.10 на 32 бит компьютер.

EDIT1:

Я использую флаги прекомпилятора

  • -станд = гну ++ 11
  • -gdwarf-3

EDIT2:

Я не думаю, что это вызвано утечкой памяти. Я проанализировал обе версии: Valgrind Анализатор памяти с отслеживанием унифицированной памяти и обнаружением кода самодиагностики, и я не обнаружил ошибок.

EDIT3:

Изменение декларации на

volatile double distance, criticalDistance;

делает проблему уйти. Это подтверждает ответ WoSstar? Это ошибка компилятора?

EDIT4:

используя опцию gcc -ffloat-магазин также исправляет проблему. Если я правильно понимаю, это вызвано gcc.

4

Решение

if (distance > criticalDistance)
// true
if (distance == criticalDistance)
// also true

Я видел это поведение раньше в моем собственном коде. Это связано с несоответствием между стандартным 64-битным значением, хранящимся в памяти, и 80-битными внутренними значениями, которые процессоры Intel используют для вычисления с плавающей запятой.

По сути, при усечении до 64 битов ваши значения равны, но при тестировании при 80-битных значениях одно немного больше другого. В DEBUG В режиме значения всегда сохраняются в памяти, а затем перезагружаются, поэтому они всегда усекаются. В оптимизированном режиме компилятор повторно использует значение в регистре с плавающей запятой, и оно не усекается.

14

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

Пожалуйста, что может быть причиной этого?

Неопределенное поведение, ака. ошибки в вашем коде.

Не существует значения IEEE с плавающей запятой, которое демонстрирует такое поведение. Так что происходит, что вы делаете что-то неправильно, что нарушает предположение, сделанное вашим компилятором.

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

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

Конечно, также возможно, что вы наткнулись на ошибку компилятора, но ошибка в вашем коде более вероятна. 🙂

И, самое главное, это означает, что у нас нет шансов отладить проблему из фрагмента кода, который вы показали. Мы можем сказать «код не должен вести себя так», но это все.

2

Вы не инициализируете свои двойники, вы уверены, что они всегда получают значение?
Я обнаружил, что неинициализированные переменные в отладке всегда равны 0, но в выпуске они могут быть чем угодно.

1
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector