在C/C++中比较整数和浮点数/双精度数

4
我有以下代码(随意将float替换为double):
class A
{
    public:
        void setValueFloat(float v) {
              m_floatValue = v / 3.6;  // m/s <-> km/h conversion
        }
        void setValueInt(int v1, int v2) { 
              m_intValue1 = v1; m_intValue2 = v2;
        }

        bool conditionIsOk()
        {
             if(m_intValue1 > m_intValue2)
             {
                  if(m_intValue1 - m_intValue2 > m_floatValue)
                  {
                      return true;
                  }
             }
             return false;
        }

    private:
        int m_intValue1, m_intValue2;
        float m_floatValue;

};

同时在其他地方:

A a;
int something = 5; // Intentionally int
int somethingElse = 6; //these are just some numbers, not production data!!!
int moreStuff = 7;

a.setValueFloat(something);
a.setValueInt(somethingElse, moreStuff);
if(a.conditionIsOk())
{
   // Yippee!
}

以下是问题:

  1. 在上述情况下,将整数的算术运算结果与浮点数进行比较有多安全?

  2. 对于这种情况,是否需要使用 (float)m_intValue1 - (float)m_intValue2 > m_floatValue ?

  3. 在 C / C++ 标准中,我可以在哪里找到关于这种情况的说明?

  4. 对于简单的情况 m_intValue1 - m_intValue2 > m_floatValue ,默认会执行哪些类型转换?(如何以一种使他人也能看到的方式展示这一点呢?仅凭信任是不够的:)


2
这绝对不是C语言。 - ciphermagi
2
@ciphermagi 只需删除 class,就可以了。我更感兴趣的是背后的理论。 - Ferenc Deak
忽略类和布尔运算符,可以在C中设置类似于上面的内容,但是您基本上正在询问编写if(2 > 2.5)是否“安全”。 - ciphermagi
发现一篇文章 这里。可能对你有帮助。 - HadeS
仅仅移除 class 是不足以使 C 代码合法的。至少需要移除 public:private: 并重新排列代码。如果帖子涉及到 C 和 C++,请提供一个适用于两者的示例 - 这会让问题的许多观看者更容易理解。此外,可能会涉及到微妙的语言规范,这可能会导致两种不同的答案,因此完整的答案需要对两种语言有深入的了解。这限制了能够回答问题的人数,可能超出您的需求。 - chux - Reinstate Monica
2个回答

6
  1. 这取决于实际的实现(即使用哪个编译器和架构)。在具有32位整数和IEEE754二进制32浮点数的典型系统上,整数可以精确地表示为浮点数,范围为+-2^24,因此不能表示所有可能值的完整范围。因此,一般情况下是不安全的,但如果您的整数(或在这种情况下更准确地说是差异!)和浮点数的使用范围适当限制,则可能是安全的。

  2. 不!事实上,m_intValue1 - m_intValue2 > m_floatValue 更好,因为将转换为浮点数发生在差异计算之后(请参见上面关于差异的注释)。您可以明确地编写 static_cast<float>(m_intValue1 - m_intValue2) > m_floatValue,但这并非必要。

  3. 转换在C++标准的第4章中进行了讨论(请参见草案N3242)。特别是4.9浮点积分转换,还要注意5§10“通常算术转换”,它也适用于比较。由于问题也标记为C,因此在C标准(请参见草案N1570)中,相应的部分是6.3.1,特别是6.3.1.4和6.3.1.8。

  4. 请参见2和3的答案。


5
通常的二元操作中类型提升的规则适用。引用标准(第5章表达式):
9.许多期望算术或枚举类型的操作数的二元运算符会引起转换并以类似的方式产生结果类型。目的是产生一个通用类型,这也是结果的类型。
这种模式称为“通常算术转换”,其定义如下:
如果任一操作数是作用域枚举类型(7.2),则不执行转换; 如果另一个操作数没有相同的类型,则表达式无效。 如果任一操作数是long double类型,则另一个操作数应转换为long double。 否则,如果任一操作数是double类型,则另一个操作数应转换为double。 否则,如果任一操作数是float类型,则另一个操作数应转换为float。 否则,应对两个操作数进行整数提升(4.5)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接