我在Java中遇到这个奇怪的问题,我有以下代码:
double velocity = -0.07;
System.out.println("raw value " + velocity*200 );
System.out.println("floored value " + Math.floor(velocity*200) );
我有以下输出:
raw value -14.000000000000002
floored value -15.0
那些traling 0002搞砸了所有东西,顺便说一下那里应该没有那个traling 2,我认为它应该是小数点后全部为零,我可以摆脱那个2吗?
更新:感谢您的帮助,您知道如何在不调用doubleValue方法的情况下对BigDecimal对象进行舍入舍入的任何方法吗?
答案 0 :(得分:4)
因为floor(-14.000000000000002)
确实是-15
!
您看,floor
被定义为小于或等于参数的最大整数。由于-14.000000000000002
不是整数,所以最接近的整数是 -15
。
好吧,现在让我们清楚为什么-0.07 * 200
不完全是-14
。这是因为浮点数的内部表示位于基数2
中,因此分母不是2
幂的分数不能用100%精度表示。 (与您不能将1/3表示为具有有限小数位数的小数部分的方式相同。)因此,velocity
的值不完全是-0.07
。 (当编译器看到常量-0.07
时,它会默默地用二进制分数替换它,该二进制分数非常接近-0.07
,但实际上并不等于。)这就是velocity * 200
不完全正确的原因。 -14
。
答案 1 :(得分:3)
为什么我的数字,如0.1 + 0.2加起来不是很好的一轮0.3,而是我得到一个奇怪的结果,如0.30000000000000004?
因为在内部,计算机使用格式(二进制浮点) 它不能准确地表示0.1,0.2或0.3之类的数字。
编译或解释代码时,您的“0.1”已经存在 四舍五入到该格式的最接近的数字,这导致一个小的 甚至在计算发生之前就会出现舍入错误。
如果您需要的数字完全符合特定的预期值,则无法使用double
。阅读链接到的网站了解详情。
答案 2 :(得分:2)
使用BigDecimal ......上面的问题是在具有有限内存的计算机上使用的表示方案的众所周知的舍入问题。问题是答案在二进制(即基数2)系统中是重复的(即像1/3 = 0.33333333 ...带小数)并且无法正确显示。一个很好的例子是1/10 = 0.1,它是0.000110011001100110011001100110011 ...二进制。在某些点之后,1和0必须结束,导致感知错误。
希望你没有从事生命攸关的事情......例如http://www.ima.umn.edu/~arnold/disasters/patriot.html。由于四舍五入错误,有28人丧生。
答案 3 :(得分:1)
Java双精度遵循IEEE 754浮点运算,它不能代表具有无限精度的每个单个实数。这一轮是正常的。你无法在内部表示中摆脱它。您当然可以使用String.format打印结果。