【问题标题】:PVS-Studio complaining about float comparisonPVS-Studio 抱怨浮动比较
【发布时间】:2017-12-13 10:42:10
【问题描述】:

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

【问题讨论】:

  • “如何解决这个问题” 完全按照错误消息中的建议。
  • 由于条件*dest == value 在返回时将是true,所以bool 返回值中似乎没有任何值。否则,如果此返回值表明某个“缓存”状态发生了变化,而这是您想要的行为,则忽略该建议 - 因为需要精确比较。
  • 不幸的是,用高达 epsilon 的测试替换完全相等的建议是虚假的。你只需要忽略它。
  • 我们不知道您的代码应该做什么,因此我们无法就如何完成该任务或诊断是否需要对您的代码采取行动提出任何建议部分。
  • @VTT 它应该在那里很合理。那些不太了解浮点的人常犯的一个误解是,认为浮点相等应该始终由与容差的比较来代替。

标签: c++ pvs-studio


【解决方案1】:

谁想知道,我们说的是this 代码。

我将尝试解释 PVS 工作室开发人员试图通过此消息实现的目标。引用他们的reference 关于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' 表达式的结果取决于所使用的处理器、编译器的版本和设置。例如,当我们使用 Visual C++ 2010 编译器时,“b”变量的值为 0.49999999999999994。

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

如果您希望执行一些位表示检查(我真的认为您正在这样做),见下文

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


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

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

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

作为一个副作用,这将消除警告:)

【讨论】:

  • 我是 C++ 新手;让我看看我是否正确。而不是 if (*dest == value) { 我使用 if (fabs(*dest - value)
  • @ThomasMccaffery 在您的特定情况下,您将register_file_-&gt;values[register_name].u32*(uint32_t *)dest 之类的内容进行比较。此外,您可以考虑在他们的错误跟踪器中打开一个问题,看看他们想出了什么,这是一种很好的学习方式:)
  • 是的,我就是这样学习的。我觉得 float 和 double 让我最困惑,我认为这是 C++ 最难的原因。谢谢
  • @ThomasMccaffery 如果您觉得有帮助,也请考虑投票和/或将答案标记为“已接受”。
  • @Thomas 有时是对的,有时是错的。这里看起来很不对劲。我认为在不了解它的情况下更改此代码是愚蠢的。这个静态分析工具肯定看不懂。我不认为你明白。为什么你认为你比原作者更了解。
猜你喜欢
  • 2018-03-09
  • 2014-03-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多