PVS-Studio 抱怨浮动比较

PVS-Studio complaining about float comparison

我用 PVS Studio 分析器扫描了我的代码,我对为什么会出现这个错误以及如何解决这个问题感到困惑。

V550 奇怪的精确比较:* dest == value。使用具有定义精度的比较可能更好:fabs(A - B) < Epsilon.

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;
}

谁想知道,我们正在谈论 this 代码。

我将尝试解释 PVS 工作室开发人员试图通过此消息实现的目标。引用他们 reference 关于 V550 的内容:

Consider this sample:

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

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

The first comparison 'a == 0.5' is true. The second comparison 'b == 0.5' may be both true and false. The result of the 'b == 0.5' expression depends upon the processor, compiler's version and settings being used. For instance, the 'b' variable's value was 0.49999999999999994 when we used the Visual C++ 2010 compiler.

他们想说的是,比较浮点数很棘手。如果您只是分配浮点数,将其存储并在内存中移动,以便稍后在此函数中与自身进行比较 - 请随时消除此错误消息。

如果您希望执行一些位表示检查(老实说我认为您正在做),请参阅下文

如果您正在对浮点数进行大量计算,并且您是一名游戏开发人员,正在计算敌方战列巡洋舰的坐标 - 此警告是您的 最好的朋友之一 .


无论如何,让我们return处理您的情况。正如 PVS-Studio 通常发生的那样,他们没有看到确切的错误,但他们为您指明了正确的方向。您实际上想要比较两个浮点值,但您这样做错误。问题是,如果您比较的两个浮点数都包含 NaN(即使在相同的位表示中),您将得到 *dest != value,并且您的代码将无法按您想要的方式工作。

在这种情况下,您最好将 float * 下的内存重新解释为 uint32_t(或与目标上的 float 具有相同大小的任何整数类型)并进行比较。

例如,在您的特定情况下,register_file_->values[register_name] 属于 type xe::gpu::RegisterFile::RegisterValue,它已经支持 uint32_t 表示。

作为副作用,这会消除警告:)