【问题标题】:Why the output of printf("%d",1/0.0) is 0?为什么 printf("%d",1/0.0) 的输出为 0?
【发布时间】:2013-12-03 03:31:33
【问题描述】:

我使用 代码块

当代码是:

printf("%d",1/0);

程序无法运行,出现错误。但是当我写这个时:

printf("%d",1/0.0);

程序可以运行,输出为0。我想知道为什么。

【问题讨论】:

  • 下面这些人都没有告诉你的是,浮点变量中存在错误,这些错误非常很小,而且几乎从不为零,由于所谓的浮点错误。这就是 为什么 你会得到价值 inf。这与在 x 接近 0 时取 1/x 的限制相同。您的结果接近无穷大。整数除法 1/0 在数学上只是 1/0。
  • 0.0 同样为零。如果您的浮点硬件设置为将其提升为 1 而不是仅返回 Inf,则浮点除以零 可能 是错误的。 (至少,如果是 758 就可以)。
  • @JonahNelson:浮点舍入与此问题中的问题行为无关。在支持无穷大的浮点系统中将源文本0.0 转换为零没有错误,执行 1 除以 0 也没有错误;结果是“完全”无穷大,没有舍入误差。观察到“0”输出的原因是 OP 正在打印带有错误说明符 %ddouble 值。
  • @hobbs:这里与硬件无关。这种情况会受到常量折叠的影响,任何类似的除法都将在编译时用这种除法的结果代替。这里的问题是编译器在不应该的情况下在这里编译除以零。如果它是 3.0/2.0 - 例如 - 它不会在运行时计算,而是在编译时计算。

标签: c floating-point printf undefined-behavior divide-by-zero


【解决方案1】:

1/01/0.0 都是未定义的行为:

C11 §6.5.5 乘法运算符

/ 运算符的结果是第一个操作数除以 第二; % 运算符的结果是余数。 在这两种操作中,如果第二个操作数的值为零,则行为未定义。

【讨论】:

  • 实际上,我打算选择其他答案之一,因为我认为浮点 1/0 总是给出无穷大。但你是绝对正确的,它 UB。一旦出现这种情况,您使用什么格式说明符并不重要,损害已经完成:-) +1。我受过教育。
  • @paxdiablo 这并不完全正确,因为大多数平台都支持 IEEE,所以它很可能会导致 inf 由于错误的格式说明符而继续调用未定义的行为,所以他们两者都很重要。未定义并不意味着实现不能定义它你只需要了解你的实现。我只是希望我能找到一个很好的 IEEE 参考资料,很容易分享。
  • Shafik,实际上未定义意味着无论实施状态如何,您都不能依赖它。你可能会抱怨一个实现是错误的,如果它声明它返回 inf 然后没有,但它仍然符合标准。其他较小的领域(定义的实现、特定区域等)问题较少。
  • @paxdiablo:当 C 标准未定义行为时,这仅意味着 C 标准对行为没有要求。这并不意味着您不能依赖实现指定的行为。 C 标准没有定义其使用“未定义”来覆盖实现规范。事实上,C 标准被设计为可通过实现进行扩展。本质上,除了纯计算之外的每个实际程序都使用 C 标准之外的行为(例如,供应商库提供的行为)。
  • @paxdiablo:没有理由相信,在观察到的关于这个问题的行为中,C 实现违反了它自己的文档。 OP 报告的行为完全可以通过%d 被错误地用于打印double 的事实来解释。它几乎肯定不是由浮点除以零引起的。
【解决方案2】:

标准部分草案6.5.5 乘法运算符5段说,您正在调用undefined behavior的两种不同形式的一种除以零(强调我的):

/ 运算符的结果是第一个操作数除以 第二; % 运算符的结果是余数。在这两种操作中,如果第二个操作数的值为零,则行为未定义

第二次在 printf 中使用了错误的格式说明符,您应该使用 %f,因为 1/0.0 的结果是 double 而不是 int。 C99 草案标准部分 7.19.6.1 fprintf 函数 也涵盖了第 9 段中的 pritnf 说:

如果转换规范无效,则行为未定义。248) 如果任何参数不是相应转换规范的正确类型,则行为是 不明确的。

虽然如果实现支持 IEEE 754 浮点除以零应该导致 +/- inf。和0/0.0 将产生NaN。需要注意的是,依赖于 __STDC_IEC_559__ 的定义可能无法正常工作,正如我在此 comment 中所指出的那样。

【讨论】:

    【解决方案3】:

    理论上,1/0.0 的结果在 C 实现中可能是未定义的,因为它在 C 标准中是未定义的。但是,在您使用的 C 实现中,结果可能是无穷大的。这是因为大多数常见的 C 实现(大部分)使用 IEEE 754 进行浮点运算。

    在这种情况下,您看到输出的原因是1/0.0 具有double 类型,但您使用%d 打印它,这需要int 类型。您应该使用接受double 类型的说明符打印它,例如%g

    【讨论】:

      猜你喜欢
      • 2011-11-14
      • 1970-01-01
      • 1970-01-01
      • 2013-10-03
      • 2012-08-05
      • 1970-01-01
      • 1970-01-01
      • 2020-12-28
      • 1970-01-01
      相关资源
      最近更新 更多