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
представление.
Как побочный эффект, это уберет предупреждение:)