BigDecimal以货币价值计算

时间:2015-07-02 20:04:20

标签: java bigdecimal

我有两个浮动值:

float value1 = 1.9f;
float value2 = 20;

我想将它们相乘并得到一个确切的结果,所以我使用BigDecimal并期望得到38:

BigDecimal total = new BigDecimal(value1).multiply(new BigDecimal(value2));

System.out.println(total); // 37.99999952316284179687500

当我用10和1.9进行相同的测试时,我得到18.99999976158142089843750而不是19。

为什么我会失去精确度?

4 个答案:

答案 0 :(得分:2)

javadoc中解释了BigDecimal(double)构造函数:

  

这个构造函数的结果可能有些不可预测。有人可能会假设在Java中编写新的BigDecimal(0.1)会创建一个BigDecimal,它恰好等于0.1(未缩放值为1,标度为1),但它实际上等于0.1000000000000000055511151231257827021181583404541015625。这是因为0.1不能精确地表示为double(或者,就此而言,作为任何有限长度的二进制分数)。因此,传递给构造函数的值并不完全等于0.1,尽管有外观。

虽然你的变量是浮点数,但是没有ctor采用浮点数,因此它们被视为双精度数。就像文档说的那样,如果你使用Strings作为你的价值观,你会得到你期望的确切结果(38)。

答案 1 :(得分:1)

错误恰好在开头:

float value1 = 1.9f;

您可能认为value1现在恰好包含值1.9。但这种情况并非如此。浮点值以二进制形式存储。要记住的重要一点是,某些实数值不能用有限的数字序列表示,例如float。 1.9是这样的数字(就像十进制一样,值1.333 ......不能用有限的数字序列表示)。

所以你应该从一开始就使用BigDecimal。然后可以精确地表示这些值(因为它不是以二进制形式存储,而是以十进制形式存储),并且计算结果为预期答案。

答案 2 :(得分:0)

假设你的value1是double的原始类型,想要输出2个小数位,value1是350. 4432567

 double roundTotal = Math.round(value1 * 100.0) / 100.0;
    or
    double roundTotal = (double) Math.round(value1 * 100) / 100;

Output:
  350.44


Note that the 2 digits precision.  Zeros indicate the wanted number of decimal to display.

Example #2
double roundTotal = (double) Math.round(value1 * 10000) / 10000;
Output:
  350.4432

答案 3 :(得分:0)

您可以使用

Math.floor(float f);
//or
Math.ceil(float f);

用于确切值的函数。或者您可以为BigDecimal类重写这些函数。