java为什么用到数学,关于Java:为什么数学?Math.round(0.4999999999999999)返回1?

在下面的程序中,您可以看到每个略小于.5的值都向下取整,0.5除外。

for (int i = 10; i >= 0; i--) {

long l = Double.doubleToLongBits(i + 0.5);

double x;

do {

x = Double.longBitsToDouble(l);

System.out.println(x +" rounded is" + Math.round(x));

l--;

} while (Math.round(x) > i);

}

印刷品

10.5 rounded is 11

10.499999999999998 rounded is 10

9.5 rounded is 10

9.499999999999998 rounded is 9

8.5 rounded is 9

8.499999999999998 rounded is 8

7.5 rounded is 8

7.499999999999999 rounded is 7

6.5 rounded is 7

6.499999999999999 rounded is 6

5.5 rounded is 6

5.499999999999999 rounded is 5

4.5 rounded is 5

4.499999999999999 rounded is 4

3.5 rounded is 4

3.4999999999999996 rounded is 3

2.5 rounded is 3

2.4999999999999996 rounded is 2

1.5 rounded is 2

1.4999999999999998 rounded is 1

0.5 rounded is 1

0.49999999999999994 rounded is 1

0.4999999999999999 rounded is 0

我正在使用Java 6更新31。

在我的例子中,答案是0而不是1,最后一行不打印,因为它在这里中断了循环。这是我的输出……8.499999999998舍入为8 7.5舍入为8 7.499999999999舍入为7 6.5舍入为7 6.4999999999999舍入为6 5.5舍入为6 5.4999999999999舍入为5 4.5舍入为5 4.4999999999999舍入为4 3.5舍入为4 3.49999999999999999996舍入为3 2.5舍入为3 2.49999999999999999996舍入为2 1.5舍入为2 1.499999999999998 8舍入为1 0.5舍入为1 0.499999999994舍入为0

在Java1.7.0上运行OK I.GGURUR.COM/HZEQX.PNG

@ Adel:请参见我对Oli的回答的评论,看起来Java 6实现了这一点(以及它所做的文档),可以通过增加EDCOX1对0的数量,然后使用EDCOX1 1来实现进一步的精度损失;Java 7不再以这种方式文档化(大概是因为他们修复了它)。

这是我写的一个测试程序中的一个错误。;)

好发现啊!我在旧的squak smalltalk bugs.squak.org/view.php中发现了地板(x+0.5)的另一个问题?ID=7134

因为精度问题

另一个显示浮点值的示例不能采用面值。

@Micha&235;lroy,尤其是在精确边缘工作时。我最喜欢的例子是1.0 % 0.1很难解释。

在考虑之后。我没看到问题。0.499999999994大于小于0.5的最小可表示数,而十进制人类可读形式的表示本身就是一种试图愚弄我们的近似值。

@Micha&235;lroy 0.49999999999999994 < 0.5as doubles is true.因为它小于0.5,所以应该四舍五入。

我确实理解。误差是精度的一半。它本身就是一次添加后精度的一半。在某种程度上,这类似于采样噪声。

摘要P></

在Java 6(和presumably earlier),要实现round(x)is as this is a bug floor(x+0.5).1规范这一病理,precisely for Java 7周case.2不断implementation.3 mandates thisP></

the问题P></

确切的说因为是0.49999999999999994 0.5 + 1是双精度:P></

static void print(double d) {

System.out.printf("%016x

", Double.doubleToLongBits(d));

}

public static void main(String args[]) {

double a = 0.5;

double b = 0.49999999999999994;

print(a);      // 3fe0000000000000

print(b);      // 3fdfffffffffffff

print(a+b);    // 3ff0000000000000

print(1.0);    // 3ff0000000000000

}

这是因为0.49999999999999994 has a指数比0.5小时,知道他们的增值,其尾数移is,and the ULP变得大。P></

the solutionP></

因为Java 7(for example,OpenJDK恩thus implements):4P></

public static long round(double a) {

if (a != 0x1.fffffffffffffp-2) // greatest double value less than 0.5

return (long)floor(a + 0.5d);

else

return 0;

}

1。http:/ / / / 6 docs.oracle.com javaSE /文档/ / / / math.html Java API #圆朗28double 29 % %></分P></

2。http:/ / / / bugs.java.com bugdatabase _ bug.do视图?_ id = 6430675 BUG(这simonnickerson for this to @测距)></分P></

3。http:/ / / / docs.oracle.com javaSE 7 /文档/ / / / math.html Java API #圆朗28double 29 % %></分P></

4。http:/ / / / / grepcode.com文件repository.grepcode.com JDK Java /根/ / / / 7u40 OpenJDK的B43 - Java /郎/ math.java # math.round 28double 29 % %></分P></

在JavaDoc for Math.round或Math类的概述中,我看不到round的定义。

@T.J克劳德:它肯定在SE6文档中。

OLI:哦,有趣的是,他们把这一点拿出来给Java 7(我连接的文档)——也许是为了避免触发这种(进一步)的精度损失,从而导致这种奇怪的行为。

@克劳德:是的,很有趣。你知道是否有任何类型的"发行说明"/"改进"文档为各个Java版本,所以我们可以验证这个假设吗?

@奥利:我想一定有什么东西埋在这里:oracle.com/technetwork/java/javase/jdk7-relnotes-429209.html很难看到树木和森林的关系。

你能给我解释一下最后两行吗?"这是因为0.499999999994………"

@Mohammadfadin:看看最后一个位置的en.wikipedia.org/wiki/single_precision和en.wikipedia.org/wiki/Unit_。

在我看来,对于(例如)a = 5e15 + 1,您所显示的openjdk 7代码仍然失败:有了这个值,a + 0.5d就不完全可表示了,因此,即使是与求和结果之间的舍入关系,也会舍入到5e15 + 2中(当然,地板也不会有任何效果)。我错过了什么?(fwiw,python 2.5有这个bug,以及op描述的bug;round(5e15 + 1)给5000000000000002.0。两者都在python 2.6和更高版本中修复。)

@马克迪金森:也许有两个错误:)

@markdickinson:添加0x1.fffffffffffffp-2,然后添加0x0.000000000001 p-2,而不是直接添加0.5,是一个好方法吗?添加前一个值等于添加0.5,除非结果非常接近零或太大而无法精确添加0.5。

我情不自禁地认为这个修复只是表面的,因为零是最明显的。毫无疑问,这种舍入误差会影响许多其他浮点值。

this appears to be known臭虫(臭虫在Java 6430675 surprising行为:math.round has been for which has 0x1.fffffffffffffp-2)在Java 7固定。P></

+1:很好的发现!与Java 6和7之间文档的差异联系在一起,正如我的答案中所解释的。

实现round()比大多数人想象的要困难得多

6:在JDK的源代码P></

public static long round(double a) {

return (long)Math.floor(a + 0.5d);

}

7:在JDK的源代码P></

public static long round(double a) {

if (a != 0x1.fffffffffffffp-2) {

// a is not the greatest double value less than 0.5

return (long)Math.floor(a + 0.5d);

} else {

return 0;

}

}

when the value is 0.49999999999999994d JDK 6,因此,它将返回1楼和呼叫,但在JDK 7,检查是否ifcondition is the the number is the Greatest双值0.5 or not less。as the number is not in this家最伟大的双值else知道the less 0.5块,返回0。P></

你可以尝试0.49999999999999999d,which will返回1,but not because this is the Greatest 0,less双值0.5。P></

那么1.4999999999999994发生了什么?返回2?它应该返回1,但这会得到与前面相同的错误,但带有1。?

1.4999999999999994不能用双精度浮点表示。1.4999999999998是小于1.5的最小两倍。从问题中可以看出,floor方法对其进行了正确的舍入。

关键是双打不均匀分布。

我有一样的JDK 1.6由32位,64位Java在线但我有7 0 0 rounded 0.49999999999999994 which is for the last is not印刷和在线。在VM的问题似乎是,不管一个人多,使用浮动点,你应该指望有什么不同的结果在不同的网络环境(位或32的CPU,64位模式)。P></

当使用布尔矩阵,round或位反转,等,这些可以使在巨大的差。P></

x64输出:P></

10.5 rounded is 11

10.499999999999998 rounded is 10

9.5 rounded is 10

9.499999999999998 rounded is 9

8.5 rounded is 9

8.499999999999998 rounded is 8

7.5 rounded is 8

7.499999999999999 rounded is 7

6.5 rounded is 7

6.499999999999999 rounded is 6

5.5 rounded is 6

5.499999999999999 rounded is 5

4.5 rounded is 5

4.499999999999999 rounded is 4

3.5 rounded is 4

3.4999999999999996 rounded is 3

2.5 rounded is 3

2.4999999999999996 rounded is 2

1.5 rounded is 2

1.4999999999999998 rounded is 1

0.5 rounded is 1

0.49999999999999994 rounded is 0

在Java 7(您正在使用的测试版本)中,错误是固定的。

我想你的意思是32位。我怀疑.Eng.org/wiki/ZEBAAY%28计算机29可以运行Java,我怀疑从那时起就有33位机器了。

@很明显,因为我以前写过32位:)

(long)Math.floor(a + 0.5d)

双Arguments for。我厂usually expected this定义as the result of,它给surprising Rather比0,1,0x1.fffffffffffffp-2(0.49999999999999994 for)。P></

最伟大的0.49999999999999994 is the value less浮点值0.5。as a浮点值literal hexadecimal its is which is equal to 0x1.fffffffffffffp-2,(2 - 2 - 2 * 2(52)。=(0.5~2 54)。therefore the value of the sum,精确P></

(0.5 - 2^54) + 0.5

是1 - 2 54。This is between the已经两相邻的浮点数字(1 - 2和1 53)。在IEEE 754 arithmetic to the used最近甚至rounding回合模式java模式,当浮点结果是接近两inexact of the,表示浮点值which must be returned the result支架精确值;如果都是equally Close the last one which is its returned零位。这房子在正确的返回值(1)is from the less not the Greatest,值1。P></

while the method is defined as the operating on this is,甚surprising输入行为规范;the amended to something like是"to the closest桑圆长,rounding关系会跟进,"which allow the to be changed on this输入的行为。P></

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值