【问题标题】:Is using floats and comparison as error code portable?使用浮点数和比较作为错误代码可移植吗?
【发布时间】:2018-02-22 07:35:00
【问题描述】:

我计划使用特殊的浮点值从函数中重新运行错误代码,例如 99.75f 可以在 IEEE-754 中表示:

float myFunction(void)
{
    /* Do some stuff */
    if(error) return 99.75f;
}

稍后检查如下值:

float result = myFunction();
if(result == 99.75f) printf("Error !");

假设我的编译器符合 C90 或 C99 标准,此解决方案是否可移植?它适用于任何平台吗? 或者编译器是否允许做一些魔法或一些优化,将浮点数转换为双精度,改变它的表示等,这会破坏相等性检查吗?

著名的What Every Computer Scientist Should Know About Floating-Point Arithmetic 似乎没有涵盖这种情况(特定于C)。 与 FLT_EPSILON 或 ULP 进行比较是无关紧要的,因为我确实想检查浮点数的表示...

【问题讨论】:

  • 便携?也许(如果您只关心使用 IEEE-754 的实现)。好习惯?绝对不。另一种选择是单独返回错误指示,即float myFunction(int *error)int myFunction(float *result)
  • @user3386109 您能否详细说明答案中的不良做法? (请注意,CPython 源代码做了一些事情very similar。)
  • @MarkDickinson 那么也许你应该是一个发布答案的人,指出 CPython 是一个良好实践的例子。
  • @user3386109:是的,这是一种糟糕的做法,就像使用函数中的int 返回码有时返回一个值(传输的字节数、流数、转换的参数数),有时返回返回错误指示(资源不可用,EOF)或使用指针表示地址或缺少地址 (NULL)。
  • 我所要做的就是等待,因为要进行维护。不了解浮点数所有细微差别的人会触及该代码,整个事情就会爆炸。这就是使它成为不好的做法的原因。不像说返回NULL。使用NULL,您不需要一堵文字墙来解释为什么您绝对确定自己可能相当安全。

标签: c floating-point comparison portability


【解决方案1】:

C 标准对浮点行为没有太多保证。它确实说:

相同源形式的所有浮动常量都应转换为具有相同值的相同内部格式。

这意味着99.75f 将产生相同的值,无论它出现在您的程序中的什么位置。它不能保证99.750f 将转换为相同的值,因此您必须确保每次出现时使用完全相同的源文本。它也不保证其他源文本(例如99.76f)不会转换为相同的值。因此,您需要确保您使用的特殊值与计算中出现的任何值完全分开。

C 标准不保证浮点系统的基数是 2 或 10。因此,仅依靠标准,您不能确定 99.75 是可表示的。当然,您不太可能遇到使用 base 3 的实现。

C 标准允许实现以额外的范围和精度评估表达式。然而,一旦99.75f 被转换为浮点,仅仅给它额外的范围和精度并不会改变它。诸如+-*/ 和库例程之类的操作可能会产生近似的结果,但可能您没有在此值上进行操作。

C 标准似乎暗示只有一个基数将用于浮点类型,至少对于普通类型而言,因为它仅定义 FLT_RADIX 来报告用于浮点系统的基数,但定义FLT_MANT_DIGDBL_MANT_DIG 报告在 floatdouble 的有效数字中使用的位数。因此,您不必担心从 float 转换为 double 或扩展精度时 99.75 会发生变化。它应该只用相同基数中的更多数字表示,而不是转换为新基数,因此额外的数字将为零。 (当然,缩小转换可能会改变它,因此您可能希望根据float 定义特殊值,这样它只会变得更宽。)

总的来说,我希望你在这方面相当安全。然而,它不一定是好的设计。当然,特殊值应该在源文本中只指定一次,通过使用预处理器宏或定义为常量值的标识符。

【讨论】:

  • "....保证基数..." 这里我认为FLT_RADIX 必须是 10 或 2 的幂。但在 C 中找不到这个支持,只是 FLT_RADIX > 1。 LSNED。
  • @chux: 16 是另一种可能性。我认为施乐 Sigma 9 使用了 16,但这是一个模糊的记忆,所以可能是错误的。
  • 我研究过的一些旧系统使用 16,a power of 2,例如 IBM/370 或 10:GP L3055。这些天不常见。
猜你喜欢
  • 2013-11-30
  • 2010-09-08
  • 1970-01-01
  • 1970-01-01
  • 2012-05-13
  • 2021-04-14
  • 2015-01-20
  • 1970-01-01
  • 2011-02-23
相关资源
最近更新 更多