【问题标题】:Comparisons involving literals safe? [closed]涉及文字的比较安全吗? [关闭]
【发布时间】:2020-02-29 18:08:30
【问题描述】:

考虑代码:

#define LITERAL 1.0

int main()
{
    double x = LITERAL;

    if (x == LITERAL) return 1;
    else return 0;
}

对于我们设置的任何数字双精度值 LITERAL(不仅仅是 1.0 而是任何其他双精度字面值),这是否保证返回 1

编辑:为什么由于“缺少详细信息”而关闭了问题?这是一个定义明确的 C/C++ 问题,并得到了很好的答案。不需要更多细节,这是关于这些语言如何工作的一般问题。

【问题讨论】:

  • 选择 C ​​或 C++。
  • 您的问题是只涉及double 还是只是一个例子,您也希望float 得到答案?
  • @EricPostpischil 我对两种语言的答案都很感兴趣(如果在这种特殊情况下存在差异),这就是我有意将这两种语言都添加到标签中的原因。
  • 如果你用c++,一般不应该用#define,首选const float LITERAL = 1.0;
  • 一般来说,不应该使用== 与浮点值进行比较。

标签: c++ c floating-point precision literals


【解决方案1】:

首先,您必须假设(试图)符合附件 F 的实现,否则所有赌注都将失败;没有附件 F(IEEE 浮点)C 允许所有浮点结果任意伪造。

然后,根据语言规范,取决于您的 C 实现对 FLT_EVAL_METHOD 的定义,是或否。

如果值为 0 或 1,则为是。文字被解释为doubledouble 对象忠实地存储了该值,而相等运算符产生 1(真),反映了这一点。

如果值为 2,则仅当文字是可表示的 double 的实际十进制表示或以足够的精度表示,它与仅超过 long double 的精度不同的精度表示。否则(例如,如果它类似于0.1),因为在long double 格式中以超精度 解释文字,所以对double 对象的初始化/分配会将精度截断为名义@ 987654331@精度。然后保证相等比较结果为 0(假)。你可以see this in action on Compiler Explorer(注意:删除volatile,你可以看到它优化为返回一个常量0)。

为了让事情更复杂,GCC 会默认错误,除非你使用 -std=c..-fexcess-precision=standard,并且在 C++ 模式下总是出错,并且clang/LLVM 总是做错。因此,在精度过高的目标上(32 位 x86 或 m68k,唯一与现实世界相关的目标,FLT_EVAL_METHOD 不是 0 或 1)会发生可怕的事情。要了解它们的糟糕程度,请参阅 GCC issue 93806 和(递归地)所有“另见”相关问题。

因此,出于实际目的,是的,除了 32 位 x86 和 m68k 之外的所有内容,并且在正确的 C 实现中没有(但也许是的,因为您的编译器可能已损坏)。

【讨论】:

  • 我不认为以下是真实的:“那么相等比较保证结果为0(假)。”如果文字在double 中不能完全表示并且long double 中不能完全表示,最接近的可表示long double 也可以完全表示为double,然后比较返回1,这与您的说法相反。
  • 文字0.1真的可以解释成long double格式吗?我认为只有使用L 后缀时才会出现这种情况?
  • @user3137490:如果FLT_EVAL_METHOD为2,则不仅可以解释为long double精度;它必须是
  • @EOF:我认为你可能是对的,但如果没有很多小数位,这在实践中是不会出现的。您是否有建议的措辞使其更准确?
  • @R..GitHubSTOPHELPINGICE 我会说这是完全可行的。 long double 通常具有大约 21 个十进制数字的精度,因此构造为“1.concat21*'0'concat1”的字符串应该在doublelong double 中四舍五入为1。无论如何,我会说“那么相等比较可能会导致 0(假)。”
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-27
  • 2014-09-25
  • 2011-07-02
  • 1970-01-01
  • 2015-10-12
相关资源
最近更新 更多