我想知道如何将浮点数舍入为机器浮点数(例如double)。数字“0.01111116”不能用机器浮点数表示,在某些舍入模式下,这个数字应该表示为“0.011111159999999995”,但有一定的精度损失。但我不知道如何在 Java 中完成这个?所以我想知道设置舍入模式的API,以获得Java中机器浮点数的精确表示。谢谢!
3 回答
Java 规范没有提供任何方法来控制浮点舍入模式。使用四舍五入。
通常不可能安排浮点运算来产生数学上精确的结果,因此必须设计软件以容忍和调整错误,或者在非常特殊的情况下,通过格外小心来获得精确的结果。
如果您在程序的源代码中谈论文字0.01111116
,Java 编译器会在编译时将其转换为二进制浮点表示。
如果您正在谈论(例如)包含字符“0.01111116”的字符串,如果/当您调用(例如)时,它将转换为二进制浮点表示Double.parseDouble(...)
。
无论哪种方式,转换都发生在幕后,您无法控制实际的舍入。但从某种意义上说,它是没有实际意义的。某些舍入发生在表示的性质中是固有的,并且结果通常是从数学角度可以得到的“最准确的”......给定您选择的浮点类型。
如果您真的希望转换使用不同的舍入/截断规则,您可以在事后执行此操作(例如舍入或截断转换后的值),或者您可以实现自己的字符串到浮点的转换方法。
您将无法更改 Java 编译器转换文字的方式。它是语言规范的一部分。
所以我想知道设置舍入模式的API,以获得Java中机器浮点数的精确表示。
对此还有另一种思考方式。
机器浮点数的精确表示是 32 位或 64 位二进制数据。double
您可以通过以下几种方式将a 的位渲染为十六进制:
Double::doubleToLongBits
或Double::doubleToRawLongBits
后跟Long::toHexString
给出精确但无用的渲染,或Double::toHexString
给出十六进制浮点表示.
所有这些效果图都是 的精确(无舍入误差)表示double
,但大多数读者不会理解它们。(“原始”版本最适合处理涉及变体 NaN 值的边缘情况。)
有等效的方法float
。
尝试 commons-math3 Precision http://commons.apache.org/proper/commons-math/apidocs/org/apache/commons/math3/util/Precision.html
double d = 0.1 + 0.2;
System.out.println(d);
d = Precision.round(d, 1); <-- 1 decimal place
System.out.println(d);
输出
0.30000000000000004
0.3