如何正确地将 Java 中的双精度值加倍到两位数
How to correctly floor doubles in Java to two digits
我正在尝试在 Java 应用程序中将底数(不是四舍五入!)加倍到两位数。我为此使用 DecimalFormat
,但注意到对于接近零的负值,这些值不是四舍五入到 -0.01
,而是四舍五入到 -0.00
。
public class MyTest {
void formatAndPrint(double value) {
DecimalFormat df = new DecimalFormat("0.00");
df.setRoundingMode(RoundingMode.FLOOR);
System.out.println(value + " => " + df.format(value));
}
@Test
public void testFloor() {
formatAndPrint(2.3289); // 2.32
formatAndPrint(2.3); // 2.30
formatAndPrint(-1.172); // -1.18
formatAndPrint(0.001); // 0.00
formatAndPrint(0.0001); // 0.00
formatAndPrint(-0.001); // -0.01
formatAndPrint(-0.0001); // -0.00 WRONG, expected: -0.01
}
}
其他解决方案,如 Math.floor(value * 100.0) / 100.0
没有这个问题,但有其他问题,如错误地将 2.3
设置为 2.29
。
是否有适用于所有情况的 Java 地板解决方案?
BigDecimal 实现工作正常。
BigDecimal value = new BigDecimal(-0.0001);
value = value.setScale(2, BigDecimal.ROUND_FLOOR);
System.out.println(value.toPlainString());
输出:-0.01
2.3
仍会下降到 2.29
。这不是 flooring 的结果,而是将 2.3
写成 double 的结果。 2.3 最接近的 64 位 IEEE754 表示是 2.29999...
在实例化 BigDecimal 时,您可以提供类似 new BigDecimal("2.3")
的字符串,这样不会导致此类错误。
编辑:正如@Hulk 提到的,您 can/should 使用 BigDecimal.valueOf()
代替,这将调用 Double.toString()
进行实例化。 Double.toString()
不使用 double
的精确值,而是 "round" 最接近的唯一值。
There must be at least one digit to represent the fractional part, and beyond that as many, but only as many, more digits as are needed to uniquely distinguish the argument value from adjacent values of type double.
这是一个小的 table 长值(与 Double.longBitsToDouble(long)
及其 BigDecimal
和 Double.toString()
对应物一起使用:
long value Double.toString() new BigDecimal()
4612361558371493473 - 2.2999999999999976 - 2.299999999999997601918266809661872684955596923828125
4612361558371493474 - 2.299999999999998 - 2.29999999999999804600747665972448885440826416015625
4612361558371493475 - 2.2999999999999985 - 2.299999999999998490096686509787105023860931396484375
4612361558371493476 - 2.299999999999999 - 2.2999999999999989341858963598497211933135986328125
4612361558371493477 - 2.2999999999999994 - 2.299999999999999378275106209912337362766265869140625
4612361558371493478 - 2.3 - 2.29999999999999982236431605997495353221893310546875
4612361558371493479 - 2.3000000000000003 - 2.300000000000000266453525910037569701671600341796875
4612361558371493480 - 2.3000000000000007 - 2.300000000000000710542735760100185871124267578125
4612361558371493481 - 2.300000000000001 - 2.300000000000001154631945610162802040576934814453125
4612361558371493482 - 2.3000000000000016 - 2.30000000000000159872115546022541821002960205078125
我正在尝试在 Java 应用程序中将底数(不是四舍五入!)加倍到两位数。我为此使用 DecimalFormat
,但注意到对于接近零的负值,这些值不是四舍五入到 -0.01
,而是四舍五入到 -0.00
。
public class MyTest {
void formatAndPrint(double value) {
DecimalFormat df = new DecimalFormat("0.00");
df.setRoundingMode(RoundingMode.FLOOR);
System.out.println(value + " => " + df.format(value));
}
@Test
public void testFloor() {
formatAndPrint(2.3289); // 2.32
formatAndPrint(2.3); // 2.30
formatAndPrint(-1.172); // -1.18
formatAndPrint(0.001); // 0.00
formatAndPrint(0.0001); // 0.00
formatAndPrint(-0.001); // -0.01
formatAndPrint(-0.0001); // -0.00 WRONG, expected: -0.01
}
}
其他解决方案,如 Math.floor(value * 100.0) / 100.0
没有这个问题,但有其他问题,如错误地将 2.3
设置为 2.29
。
是否有适用于所有情况的 Java 地板解决方案?
BigDecimal 实现工作正常。
BigDecimal value = new BigDecimal(-0.0001);
value = value.setScale(2, BigDecimal.ROUND_FLOOR);
System.out.println(value.toPlainString());
输出:-0.01
2.3
仍会下降到 2.29
。这不是 flooring 的结果,而是将 2.3
写成 double 的结果。 2.3 最接近的 64 位 IEEE754 表示是 2.29999...
在实例化 BigDecimal 时,您可以提供类似 new BigDecimal("2.3")
的字符串,这样不会导致此类错误。
编辑:正如@Hulk 提到的,您 can/should 使用
BigDecimal.valueOf()
代替,这将调用 Double.toString()
进行实例化。 Double.toString()
不使用 double
的精确值,而是 "round" 最接近的唯一值。
There must be at least one digit to represent the fractional part, and beyond that as many, but only as many, more digits as are needed to uniquely distinguish the argument value from adjacent values of type double.
这是一个小的 table 长值(与 Double.longBitsToDouble(long)
及其 BigDecimal
和 Double.toString()
对应物一起使用:
long value Double.toString() new BigDecimal()
4612361558371493473 - 2.2999999999999976 - 2.299999999999997601918266809661872684955596923828125
4612361558371493474 - 2.299999999999998 - 2.29999999999999804600747665972448885440826416015625
4612361558371493475 - 2.2999999999999985 - 2.299999999999998490096686509787105023860931396484375
4612361558371493476 - 2.299999999999999 - 2.2999999999999989341858963598497211933135986328125
4612361558371493477 - 2.2999999999999994 - 2.299999999999999378275106209912337362766265869140625
4612361558371493478 - 2.3 - 2.29999999999999982236431605997495353221893310546875
4612361558371493479 - 2.3000000000000003 - 2.300000000000000266453525910037569701671600341796875
4612361558371493480 - 2.3000000000000007 - 2.300000000000000710542735760100185871124267578125
4612361558371493481 - 2.300000000000001 - 2.300000000000001154631945610162802040576934814453125
4612361558371493482 - 2.3000000000000016 - 2.30000000000000159872115546022541821002960205078125