【问题标题】:Can 0.99999999999 be rounded to 1.0 when multiplying?0.99999999999相乘时可以四舍五入到1.0吗?
【发布时间】:2011-12-05 03:25:12
【问题描述】:

当一个非常接近 1 的浮点数乘以 int > 0 时,它是否可以被解释为 1。

也就是说,如果Math.random() 返回其可能的最高结果(比 1.0 低 1 步),将

(int)(Math.random() * 8)

是 8 还是 7?

举个实际的例子,这个经常使用的构造能否给出索引越界错误:

someArray[(int)(Math.random() * someArray.length)];

我对 Java 和 ActionScript 3 的答案特别感兴趣,但我想它们都使用相同的浮点运算规则,并且任何平台的答案都会很有用。

更新:虽然我已经接受了一个答案,但我仍然希望确认这在 ActionScript 3 中也不会出错,因为一位同事报告说他曾经看到它出错了部分促使我提出这个问题。

【问题讨论】:

  • 如果这样的数字 never 溢出到下一个整数中,我会感到非常惊讶......但我会等待更好的答案......
  • @UdoFholl 我不打算使用任何官方的数学符号,只是想用很多个九来表示一个数字。
  • 当乘以一个非常接近 1 的浮点数时,它是否可以被解释为 1 -- 是的,如果你将它乘以 0 ;-) JK跨度>
  • @JoshLee:从数学上讲,0.99999999999999999999999... 与 1.0 相同,但计算机不能用浮点数或双精度数表示 0.9999999...让随机数生成器生成它。
  • @Josh:不过,这无关紧要,因为 RNG(作为计算机程序)不会生成计算机无法准确表示的数字。

标签: java actionscript-3 math floating-point


【解决方案1】:

如果将小于 1.0 的最大值乘以 someInt (> 0),则结果永远不会是 someInt

这可以针对这样的整数进行详尽的测试:

Double greatestLessThanOne = Double.longBitsToDouble(4607182418800017407L);

// Assert that greatestLessThanOne is indeed the largest double less than 1.
//assert 1.0 == greatestLessThanOne + Math.ulp(greatestLessThanOne);

for (int i = 1; i >= 0; i++)
    if ((int) (greatestLessThanOne * i) == i)
        System.out.println("Exception found: " + i);

sn-p 不产生任何输出。

Math.ulp 返回给定双精度值和下一个更大的双精度值之间的距离。因此,断言确保 greatestLessThanOne 确实是小于 1.0 的最大值。)

换句话说,你的线

Object element = elementArray[(int)(Math.random() * elementArray.length)];

永远不会引发 ArrayIndexOutOfBoundsException。


此外,根据 Mark Dickinsons 对 here 的评论,这也适用于乘以双精度数。

使用 IEEE 754 浮点算法在四舍五入模式下,您可以证明任何 x < 1.0 和任何非微小正数 yx * y < y。 (如果y 是次正规数或最小的正正规数,它可能会失败。)

【讨论】:

  • 好答案。而Java 使用最近舍入:“Java 编程语言要求浮点算术表现得好像每个浮点运算符都将其浮点结果四舍五入到结果精度。不精确的结果必须四舍五入到可表示的值最接近无限精确的结果;如果两个最接近的可表示值同样接近,则选择其最低有效位为零的那个。这是 IEEE 754 标准的默认舍入模式,称为 round to nearest。 "
  • 接受了这个答案,因为大多数平台都将遵循 IEEE 754。不过,您是否碰巧知道 ActionScript 3 / Flash 是否也这样做?我听说那里实际上可能会出错。
  • ActionScript 也一样。 Specs 说它应该使用 IEEE 格式(并且舍入到最近是默认舍入模式。)
【解决方案2】:

圆一下,可能是这样的:

BigDecimal bd = new BigDecimal(Double.toString(d));
bd = bd.setScale(decimalPlace,BigDecimal.ROUND_HALF_UP);

【讨论】:

  • BigDecimal?对于一个可能执行得太频繁的简单语句,这是一个非常昂贵的“修复”(如果实际上需要)。
  • 这不仅成本高,而且对于随机分布的统计特性也是一个问题。
  • 不,我的意思只是示例,您可以使用小于 bigdecimal 的其他对象类型
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-09-21
  • 2020-08-04
  • 1970-01-01
  • 2023-01-12
  • 2012-08-04
  • 2023-03-26
  • 1970-01-01
相关资源
最近更新 更多