如何将BigDecimal限制为固定分数?

时间:2013-12-20 22:17:05

标签: java math bigdecimal

我正在尝试创建一个始终具有固定最大分数的BigDecimal类。 但是当打印这个数字时,它不会被切割成我在比例中定义的分数。为什么呢?

class MyDecimal extends BigDecimal {
    public MyDecimal(double val) {
        super(val); 
        setScale(4, RoundingMode.HALF_UP);
    }
}


Sysout(new MyDecimal(0.0001));
//0.000100000000000000008180305391403130954586231382563710212707519531254

3 个答案:

答案 0 :(得分:4)

BigDecimal是不可变的,不应该扩展。 setScale()不会修改BigDecimal实例。它返回BigDecimal实例的副本,并修改了比例(与BigDecimal的每个其他“变异”方法一样,因为它是不可变的)。因此调用它并忽略返回的值是没用的。

不是扩展BigDecimal,而是创建工厂方法:

public static BigDecimal createWithScale4(double d) {
    BigDecimal temp = new BigDecimal(d);
    return temp.setScale(4);
}

答案 1 :(得分:2)

问题在于您将输入作为双精度输入。这是来自javadoc:

  

这个构造函数的结果可能有些不可预测。一   可能会假设在Java中编写新的BigDecimal(0.1)会创建一个   BigDecimal正好等于0.1(未缩放的值为1,带有   比例为1),但它实际上等于   0.1000000000000000055511151231257827021181583404541015625。这是因为0.1不能完全表示为double(或者为此)   重要的是,作为任何有限长度的二进制分数)。因此,价值   传入构造函数的不完全等于   0.1,尽管出现

由于您使用的是double,因此将其存储为浮点数,将存储为精度数。然后,它将该非精度浮点数转换为精度BigDecimal,然后将其作为精确数字输出。但是,如果输入是String,则它会起作用,因为String只是文本,并将字符串直接转换为BigDecimal。请参阅here

  

从(标量)double创建一个大小数很简单:

     

bd = new BigDecimal(1.0);

     

要从Double获取BigDecimal,请获取它   doubleValue()首先。

     

然而,使用字符串构造函数是个好主意:

     

bd = new BigDecimal(“1.5”);

     

如果您不这样做,那么您将获得以下内容,

     

bd = new BigDecimal(1.5);

     

bd.toString(); // => 0.1499999999999999944488848768742172978818416595458984375

所以这样做:

Sysout(new MyDecimal("0.0001"));

另外,正如@JBNizet指出的那样,你正在扩展一个不可变对象,BigDecimal。您忽略了设置比例的返回值。这可以通过使用如下方法来改变:

public static BigDecimal createBigDecimal(String s) {
    BigDecimal bigdeci = new BigDecimal(s);
    return bigdeci.setScale(4);
}

答案 2 :(得分:1)

问题是你将参数传递为double而不是字符串。在参数到达大十进制之前,它已经被转换为二进制形式以存储为double,这引入了一个小错误(它等同于尝试将1/3作为小数写入并获得0.3333333333;它将不会相当正确,除非你有无限的精确度。)

相反,请尝试:

Sysout((new BigDecimal("0.0001")).setScale(4,RoundingMode.HALF_UP));