【问题标题】:Express highest floating point quantity that is less than 1表示小于 1 的最大浮点数
【发布时间】:2010-12-29 08:23:19
【问题描述】:

我正在做一些四舍五入的计算,偶然发现了一个问题。对于给定的浮点类型,如何表示小于 1 的最大数量?

也就是说,我如何编写/表示值 x 使得 x < 1, x + y >= 1 代表任何 y > 0

在分数中,这将是x = (q-1)/q,其中q 是类型的精度。例如,如果您以1/999 为增量进行计数,则为x = 998/999

对于给定的类型(float、double、long double),如何在代码中表达值x


我还想知道y 的所有值是否都存在这样的值。也就是说,随着y's 指数变小,这种关系可能不再成立。因此,对y 有一定范围限制的答案也是可以接受的。 (我想要的x的值还是存在的,只是关系可能表达的不好。)

【问题讨论】:

  • 您在寻找某种公式吗?一个常数?找到它的算法?
  • 最好使用常量,但也可以使用函数。
  • 看看 dlamch over at netlib

标签: c++ c math


【解决方案1】:

C99 定义了nextafter() 函数。像这样使用它

#include <math.h>
double under_one = nextafter(1, 0);

【讨论】:

  • @Chris 1 精确地以二进制表示,所以像我写的那样使用它会给你最大可能的“小于 1”双值
  • 是的,这似乎正是我想要的。有没有办法将此值表示为常数?也就是说,如果我希望将其用作默认参数?
  • 如果我们假设 epsilon 向 0.0 比向 2.0 精细两倍,我们可以使用 FLT_EPSILON 常数,将其除以 2。
  • @Chris:1 不是 1 的实现在所有可用性之外都是无望的。 C 可能允许这样的损坏,但是除非您假设理智,否则编写任何浮点代码都没有什么意义。就我个人而言,我总是假设 IEEE 754 语义和表示。
【解决方案2】:

Altouht 其他人是对的,小于 1 的值更大是 1-FLT_EPSILON,在浮点数中它不能满足条件 x &lt; 1, x + y &gt;= 1 对于任何 y &gt; 0,除非您使用向上舍入.

原因是 1 和它之前的距离(即FLT_EPSILON ~ 1.2E-7)远大于最小可表示正数FLT_MIN,即 ~ 1.2E-38。因此存在一类数字(FLT_MIN ... FLT_EPSILON/2 舍入到最接近时,这是大多数系统的默认值),其中(1-FLT_EPSILON)+y == (1-FLT_EPSILON) &lt; 1

【讨论】:

  • 这也很高兴知道。它解决了我对这样一个数字是否可能的担忧。
  • 这不是暗示从 1.0 到 0.0 的 epsilon 是 FLT_EPSILON/2 吗?
  • 我不确定是这样,但似乎是。我可能在细节上是错误的。范围可能是 FLT_MIN...FLT_EPSILON/4,而不是 /2,因为它是实际 epsilon 的一半,但它存在。
【解决方案3】:

有一种方法可以获得最小的数量,即加到 1 会产生大于 1 的最小可表达数量。那就是 std::numeric_limits&lt;type&gt;::epsilon()。如果你证明这个数量等于你搜索的那个,那就是你想要的:

模板静态 _Tp std::numeric_limits::epsilon () throw () [内联,静态] 机器 epsilon:1 与可表示的大于 1 的最小值之间的差。

【讨论】:

  • 是否保证1 - epsilon + epsilon == 1
  • 答案可能是“不”。我尝试了 nextafter() 函数,试图让 epsilon 从 1.0 到 0.0 和 2.0 - 结果是不同的。接近 2.0 的 Epsilon 正好是接近 0.0 的两倍 - 可能是因为后者是使用非规范化数字表示的,其精度多 1 位。
  • 对于二进制浮点,1-epsilon 会太大。以 3 个二进制数字的 FP 格式为例:1.00 之后的下一个数字是 1.01,因此 epsilon 是 0.01,而 1.00 之前的数字是 0.111。
  • @edA:C 对浮点结果不做任何保证。 IEEE 754 当然可以保证这一点,因为所涉及的所有值都是准确的。
【解决方案4】:

IEEE 754 浮点表示具有这样的属性,即对于正数而不是 NaN,其顺序与被视为整数的位模式的顺序相同。

因此,您可以将浮点数 1.0 的位模式重新解释为整数,将该整数递减,然后再次将其重新解释为浮点数,以获得略低于 1 的浮点数。

【讨论】:

    【解决方案5】:

    根据 IEEE 754 标准,单精度(32 位)1.0 的表示形式为 0x3F800000。我们可以用二进制写成 0 01111111 (1)00000000000000000000000,意思是:

    sign = 0
    biased exponent = 01111111 = 0x7F, so exponent = -23 (decimal)
    mantissa = 0x800000 (the (1) in parentheses is the implied msb)
    

    所以值为0x800000 * 2^-23,即1.0。下一个最小的单精度数是

    0 01111110 (1)11111111111111111111111
    

    或0x3F7FFFFF,或0xFFFFFF * 2^-24,大约为0.99999994。

    【讨论】:

    • AFAIK,IEEE-754 表示意味着隐藏的 MSB 始终等于 1(除非它是非正规数)。因此,低于 1.0 的最高数量将表示为全为 (1) 尾数和 (-1) 指数。该数字的 MSB 将是隐含的 (1),因此尾数有效地接收了一位。这就是为什么 0.0 的 epsilon 比 2.0 的 epsilon 好 2 倍。
    【解决方案6】:

    nextafter() 函数运行良好 @qrdl

    #include <math.h>
    // find next double from 1.0 working towards 0.0
    double before_1 = nextafter(1.0, 0.0);
    

    尚未在编译时这样做,正如@OP 以高度可移植的方式评论的那样:

    #include <float.h>
    double before_1 = 1.0 - DBL_EPSILON/FLT_RADIX;
    

    DBL_EPSILON是1.0和下一个更大double之间的绝对差。

    FLT_RADIX 是浮点系统的基数(基数)。通常 2. 使用了 16 和 10 之类的值。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-04-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多