JAVA浮点运算

JAVA浮点运算,java,Java,我在我的应用程序中做了很多浮点运算,我知道浮点运算不是100%精确的,这很好,但是当涉及到打印结果时,我还没有找到一种方法来正确格式化它 比如说 0.1+0.1=0.19999999999999 Math.sin(Math.PI)=1.2246E16而不是0 还有像1.000000000000000001这样的东西 我正在寻找一种获取这些结果并获得适当舍入值(字符串形式)的通用方法 所以 0.1+0.1=0.19999999999999999->0.2此项需要四舍五入 Math.sin(Math

我在我的应用程序中做了很多浮点运算,我知道浮点运算不是100%精确的,这很好,但是当涉及到打印结果时,我还没有找到一种方法来正确格式化它

比如说

0.1+0.1=0.19999999999999

Math.sin(Math.PI)=1.2246E16而不是0

还有像1.000000000000000001这样的东西

我正在寻找一种获取这些结果并获得适当舍入值(字符串形式)的通用方法

所以 0.1+0.1=0.19999999999999999->0.2此项需要四舍五入

Math.sin(Math.PI)=1.2246E16->0

还有像1.000000000000000001->1这样的东西;而这个需要四舍五入

我还希望避免在结果不确定的情况下丢失数据
1.1234567891234567或1.33333333在这些情况下,结果应保持不变。

格式使用例如
System.out.printf(“%.6f”,myFloat)
如果要避免丢失小数,请使用BigDecimal而不是float。更慢但更准确。

如果要避免使用格式,可以在打印结果之前将结果四舍五入到固定精度,并利用Java将进行少量四舍五入以隐藏表示错误的事实

e、 g.保留至小数点后6位

public static double round6(double d) {
    return Math.round(d * 1e6) / 1e6;
}
round()
1e6
的结果可以精确表示。此外,“需要正确的舍入:也就是说,舍入结果就好像使用了无限精确的算术来计算值,然后舍入”剩下的唯一错误是表示错误,因为它采用了最接近的表示值。Java的toString()假定,当您有一个双精度数时,它的最接近的可表示值是一个较短的十进制数,这就是您想要看到的

e、 g.0.1的实际值为

System.out.println(new BigDecimal(0.1));
印刷品

0.1000000000000000055511151231257827021181583404541015625
但是当Double.toString()被传递这个值时,它确定0.1将被转换成这个Double,所以这就是它应该显示的内容

顺便说一句,在Java6中有一个bug,它没有使用最小位数

for (int i = 1; i <= 9; i++)
    System.out.print(i / 1000.0 + " ");
用Java7打印

0.001 0.002 0.003 0.004 0.005 0.006 0.007 0.008 0.009

如果性能不重要,我经常使用printf,如果性能不重要,我会使用自定义例程将double写入直接ByteBuffer到固定精度(有效地将其舍入),这会更快,因为它不会创建任何对象

我还希望避免在结果为1.1234567891234567或1.33333333333的情况下丢失数据。在这些情况下,结果应保持不变


在这种情况下,在需要显示结果之前不要对结果进行四舍五入。

不可能。程序如何知道它是否应该舍入
0.1999999999999
(因为它是
0.1+0.1
的结果)或不舍入(因为它是
0.2-0.000000000001
的结果?
系统输出.println(0.1+0.1)
生成“0.2”顺便说一句,yyep,很公平-最好在你的问题中使用一个实际显示问题的例子;-)我想你的意思是
1.2246E-16
,而不是
1.2246E16
BigDecimal如何与sin/cos/log/ln这样的函数一起工作?这与精确计算无关,我可以接受1.9999的结果,但当我打印回来时,我希望它是2.0,有什么建议吗?@aviran你为什么不想使用printf?顺便说一句,1
String.format()
采用相同的参数,并为您提供一个
String
还有大量其他类似的格式选项。我不知道它在哪里有这样的示例。我想这是因为用一个整数除以另一个整数时,可以得到的舍入误差是有限的。@Tobiaritzau包含了一个不太容易摇摆的答案;)嗯,还是不满意。如果格式化是你想要的,为什么不使用格式化功能呢?@Tobiaritzau我同意,但OP声明由于某种原因
不使用printf
。我们可以继续下去,我理解你的观点,但仍然认为在几乎所有情况下都有更好的方法:)
0.001 0.002 0.003 0.004 0.005 0.006 0.007 0.008 0.009