Java 如何使用BigDecimal.round\u HALF\u将0.745四舍五入到0.75?

Java 如何使用BigDecimal.round\u HALF\u将0.745四舍五入到0.75?,java,bigdecimal,rounding,Java,Bigdecimal,Rounding,我试了以下方法 double doubleVal = 1.745; double doubleVal1 = 0.745; BigDecimal bdTest = new BigDecimal( doubleVal); BigDecimal bdTest1 = new BigDecimal( doubleVal1 ); bdTest = bdTest.setScale(2, BigDecimal.ROUND_HALF_UP); bdTest1 = bdTes

我试了以下方法

   double doubleVal = 1.745;
   double doubleVal1 = 0.745;
   BigDecimal bdTest = new BigDecimal(  doubleVal);
   BigDecimal bdTest1 = new BigDecimal(  doubleVal1 );
   bdTest = bdTest.setScale(2, BigDecimal.ROUND_HALF_UP);
   bdTest1 = bdTest1.setScale(2, BigDecimal.ROUND_HALF_UP);
   System.out.println("bdTest:"+bdTest); //1.75
   System.out.println("bdTest1:"+bdTest1);//0.74    problemmmm ????????????  

但结果很奇怪。为什么?

这可能会给你一个错误的提示

import java.math.BigDecimal;

public class Main {
    public static void main(String[] args) {
        BigDecimal bdTest = new BigDecimal(0.745);
        BigDecimal bdTest1 = new BigDecimal("0.745");
        bdTest = bdTest.setScale(2, BigDecimal.ROUND_HALF_UP);
        bdTest1 = bdTest1.setScale(2, BigDecimal.ROUND_HALF_UP);
        System.out.println("bdTest:" + bdTest); // prints "bdTest:0.74"
        System.out.println("bdTest1:" + bdTest1); // prints "bdTest:0.75"
    }
}
问题是,您的输入(a
double x=0.745;
)不能精确表示0.745。它实际上保存了一个略低的值。对于
大小数
,这已经低于0.745,所以它四舍五入


尽量不要使用
BigDecimal(double/float)
构造函数。

永远不要从float或double构造BigDecimal。从整数或字符串构造它们。浮动和加倍松散精度

此代码按预期工作(我刚刚将类型从double更改为String):

产出:

1.74500000000000010658141036401502788066864013671875
0.74499999999999999555910790149937383830547332763671875
这显示了两个双精度的实际值,并解释了得到的结果。正如其他人所指出的,不要使用double构造函数(除了您希望看到double的实际值的特定情况)

有关双精度的更多信息:


出于您的兴趣,请使用
double

double doubleVal = 1.745;
double doubleVal2 = 0.745;
doubleVal = Math.round(doubleVal * 100 + 0.005) / 100.0;
doubleVal2 = Math.round(doubleVal2 * 100 + 0.005) / 100.0;
System.out.println("bdTest: " + doubleVal); //1.75
System.out.println("bdTest1: " + doubleVal2);//0.75
或者只是

double doubleVal = 1.745;
double doubleVal2 = 0.745;
System.out.printf("bdTest: %.2f%n",  doubleVal);
System.out.printf("bdTest1: %.2f%n",  doubleVal2);
都是印刷品

bdTest: 1.75
bdTest1: 0.75
我更喜欢让代码尽可能简单


正如@mshutov所指出的,您需要再添加一点,以确保半个值总是四舍五入。这是因为像
265.335
这样的数字比它们显示的要小一些。

使用
BigDecimal.valueOf(double d)
而不是
新的BigDecimal(double d)
。最后一个具有浮点和双精度误差。

可提供多种选项,例如:

 Double d= 123.12;
BigDecimal b = new BigDecimal(d, MathContext.DECIMAL64); // b = 123.1200000
b = b.setScale(2, BigDecimal.ROUND_HALF_UP);  // b = 123.12

BigDecimal b1 =new BigDecimal(collectionFileData.getAmount(), MathContext.DECIMAL64).setScale(2, BigDecimal.ROUND_HALF_UP)  // b1= 123.12

 d = (double) Math.round(d * 100) / 100;
BigDecimal b2 = new BigDecimal(d.toString());  // b2= 123.12




如果使用
BigDecimal.valueOf(double)
,这是一种静态工厂方法,优于构造函数(在javadocs中有说明),使用
BigDecimal bdTest=BigDecimal.valueOf(1.745),则无需使用字符串即可正常工作;BigDecimal bdTest1=BigDecimal.valueOf(0.745)给出了相同的结果(0.75)@JoshuaGoldberg你不是说
BigDecimal.valueOf(“0.745”)而不是
BigDecimal.valueOf(1.745)。。。可能不是,没有这样的
BigDecimal.valueOf(String)
:-/Yes,注释的关键是缺少引号。从
BigDec.valueOf(double)
的javadoc中可以看出:“注意:这通常是将double(或float)转换为BigDecimal的首选方法,因为返回的值等于使用double.toString(double)的结果构造BigDecimal的结果。”如果我的
BigDecimal
是从Spring导入的
@ConfigurationProperties
?我无法控制它是如何从
application.yml
构造的,它假定已经以
字符串提供了值,但仍然以相同的舍入问题结束。您可能会得到意外的结果。例如:Math.round(265.335*100)/100.0!=265.34见对的评论
bdTest: 1.75
bdTest1: 0.75
 Double d= 123.12;
BigDecimal b = new BigDecimal(d, MathContext.DECIMAL64); // b = 123.1200000
b = b.setScale(2, BigDecimal.ROUND_HALF_UP);  // b = 123.12

BigDecimal b1 =new BigDecimal(collectionFileData.getAmount(), MathContext.DECIMAL64).setScale(2, BigDecimal.ROUND_HALF_UP)  // b1= 123.12

 d = (double) Math.round(d * 100) / 100;
BigDecimal b2 = new BigDecimal(d.toString());  // b2= 123.12