PVS-Studio жалуется на сравнение с плавающей точкой

Я отсканировал свой код с помощью анализатора PVS Studio, и я не понимаю, почему эта ошибка и как ее исправить.

V550 Странное точное сравнение: * dest == value. Вероятно, лучше использовать сравнение с определенной точностью: fabs(A - B)

bool PipelineCache::SetShadowRegister(float* dest, uint32_t register_name) {
    float value = register_file_->values[register_name].f32;
    if (*dest == value) {
        return false;
    }
    *dest = value;
    return true;
}

Я предполагаю изменить код следующим образом:

bool PipelineCache::SetShadowRegister(float* dest, float* epsilon uint32_t register_name) {
    float value = register_file_->values[register_name].f32;
    return fabs(dest - value) < epsilon;
}

1 ответ

Решение

Кто бы ни интересовался, мы говорим об этом коде.

Я попытаюсь объяснить, чего разработчики студии PVS пытались достичь с помощью этого сообщения. Ссылаясь на их ссылку о V550:

Рассмотрим этот пример:

double a = 0.5;
if (a == 0.5) //OK
    x++;

double b = sin(M_PI / 6.0);
if (b == 0.5) //ERROR
    x++;

Первое сравнение 'a == 0.5' верно. Второе сравнение "b == 0,5" может быть как истинным, так и ложным. Результат выражения 'b == 0,5' зависит от процессора, версии компилятора и используемых настроек. Например, значение переменной 'b' было 0,49999999999999994, когда мы использовали компилятор Visual C++ 2010.

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

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

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


В любом случае, вернемся к вашему делу. Как это обычно бывает с PVS-Studio, они не увидели точную ошибку, но указали вам верное направление. Вы действительно хотите сравнить два значения с плавающей точкой, но вы делаете это неправильно. Дело в том, что если оба сравниваемых числа с плавающей запятой содержат NaN (даже в одном и том же битовом представлении), вы получите *dest != value, и ваш код не будет работать так, как вы хотите.

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

Например, в вашем конкретном случае, register_file_->values[register_name] имеет тип xe::gpu::RegisterFile::RegisterValue, который уже поддерживает uint32_t представление.

Как побочный эффект, это уберет предупреждение:)

Другие вопросы по тегам