如何正确地将Java中的双精度放到两位数

Jos*_*ong 5 java math double floor

我试图在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
    }
}
Run Code Online (Sandbox Code Playgroud)

其他的解决方案,如Math.floor(value * 100.0) / 100.0没有这个问题,但有其他的问题,比如错误地地板2.32.29.

Java的地板解决方案是否适用于所有情况?

Lin*_*k64 7

BigDecimal实现工作正常.

BigDecimal value = new BigDecimal(-0.0001);
value = value.setScale(2, BigDecimal.ROUND_FLOOR);
System.out.println(value.toPlainString());
Run Code Online (Sandbox Code Playgroud)

输出:-0.01

2.3仍将落地2.29.这不是地板的结果,而是写作2.3双重的结果.最接近的64位IEEE754表示为2.32.29999...

在实例化BigDecimal时,您可以改为提供一个new BigDecimal("2.3")不会导致此类错误的字符串.


编辑:正如@Hulk所提到的,您可以/应该使用BigDecimal.valueOf(),这将调用Double.toString()实例化.Double.toString()不使用的确切值,double而是"舍入"到最接近的唯一值.

Double JavaDoc的:

必须至少有一个数字来表示小数部分,并且除此之外必须有多个,但只需要多少,更多的数字来唯一地区分参数值和double类型的相邻值.

这里是长值(与所用的小桌子Double.longBitsToDouble(long)和他们BigDecimalDouble.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
Run Code Online (Sandbox Code Playgroud)

  • 值得一提的是,从 `double` 或 `float` 创建 `BigDecimal`s 的首选方法是 [`BigDecimal.valueOf`](https://docs.oracle.com/javase/9​​/docs/api/ java/math/BigDecimal.html#valueOf-double-),它像字符串构造函数一样工作并产生更直观的结果,避免了 2.3 问题:“这通常是将双精度(或浮点)转换为双精度的首选方法BigDecimal,因为返回的值等于从使用 Double.toString(double) 的结果构造一个 BigDecimal 的结果。” (2认同)