0

我在我的应用程序中做了很多浮点运算,我知道浮点运算不是 100% 准确的,但在打印结果时我还没有找到正确格式化它的方法.

例如

0.1 + 0.1 = 0.19999999999999999999999

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

和1.000000000000000001之类的东西

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

所以 0.1 + 0.1 = 0.19999999999999999999999 -> 0.2 这个需要四舍五入

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

和 1.000000000000000001 -> 1 之类的东西;而这个需要四舍五入

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

4

3 回答 3

1

使用例如格式System.out.printf("%.6f", myFloat)

于 2012-10-31T13:03:25.573 回答
1

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

例如到小数点后 6 位

public static double round6(double d) {
    return Math.round(d * 1e6) / 1e6;
}

round()和的结果1e6可以精确表示。此外,“ IEEE 754要求正确舍入:也就是说,舍入结果就像使用无限精确算术来计算值然后舍入一样” 剩下的唯一错误是表示错误,因为它采用最接近的可表示值。Java 的 toString() 假设当您有一个具有较短小数的最接近的可表示值的双精度数时,这就是您想要看到的。

例如 0.1 的实际值是

System.out.println(new BigDecimal(0.1));

印刷

0.1000000000000000055511151231257827021181583404541015625

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

顺便说一句,在 Java 6 中有一个错误,它不使用最小位数。

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

在 Java 6 中打印

0.0010 0.0020 0.0030 0.0040 0.0050 0.0060 0.0070 0.0080 0.0090

并在 Java 7 中打印

0.001 0.002 0.003 0.004 0.005 0.006 0.007 0.008 0.009

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

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

在这种情况下,不要对结果进行四舍五入,直到需要显示它们。

于 2012-10-31T13:13:36.097 回答
0

如果您想避免丢失小数,请使用 BigDecimal 而不是 float。更慢但更准确。

于 2012-10-31T13:04:02.823 回答