2011-10-11 39 views
36

当乘以一个浮点数,这是非常接近1与一个int> 0,可以将其永远被解释为1.可以将0.99999999999乘以四舍五入为1.0吗?

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

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

是8还是7?

对于一个实际的例子,可以在此经常使用的结构给出一个索引越界的错误:

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

我在为Java和ActionScript 3的答案特别感兴趣,但我想他们都使用浮点算法的相同规则以及任何平台的答案都是有用的。

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

+0

我会很惊讶,如果这样一些*从未*溢出到下一个INT ......但我会等待更好的回答... – bdares

+4

@UdoFholl我不打算使用任何官方的数学符号,只是想表明一个数字有很多很多的九。 –

+0

*当乘以一个非常接近1的浮点数时,是否可以解释为1 * - 是的,如果您乘以0 ;-) JK – aioobe

回答

44

如果用someInt(> 0)乘以低于1.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); 

该片段不产生输出。

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

换句话说,您的线路

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

永远不会产生ArrayIndexOutOfBoundsException。


此外,根据在here马克·狄金森评论,这与双倍增时持有也。

With IEEE 754 floating-point arithmetic in round-to-nearest mode, you can show that x * y < y for any x < 1.0 and any non-tiny positive y . (It can fail if y is either subnormal or the smallest positive normal number.)

+2

很好的答案。 [Java](http://java.sun.com/docs/books/jls/third_edition/html/typesValues.html)使用了最接近的方法:“Java编程语言要求浮点算术的行为如同每个浮点运算符将其浮点结果四舍五入为结果精度;不精确的结果必须舍入为最接近无限精确结果的可表示值;如果两个最近可表示值相等,则最低有效位为零这是IEEE 754标准的默认舍入模式,称为** round to nearest **。“ –

+1

感谢来自Java的卓越课程+1 – mKorbel

+0

接受了这个答案,因为大多数平台都遵循IEEE 754.但是,您是否碰巧知道ActionScript 3/Flash是否也这样做?我听到谣言说它确实在那里出错了。 –

-2

圆刚的话,可能是这样的:

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

' BigDecimal'?这是一个相当昂贵的“修复”(如果实际上需要的话),因为一个简单的陈述可能经常被执行。 –

+1

这不仅代价高昂,而且对于随机分布的统计特性也是一个问题。 – leftaroundabout

+0

不,我的意思是只是例子,你可以使用比bigdecimal更小的其他对象类型 –