在下面的程序中,您可以看到每个略小于.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></