BigDecimal 值货币

BigDecimal to values monetary

我有两个浮点值:

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。

为什么我会丢失精度?

假设您的 value1 是一个 double as primitive type 并且想要输出 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

您可以使用

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

精确值的函数。或者您可以为 BigDecimal class.

覆盖这些函数

这在 BigDecimal(double) 构造函数的 javadoc 中有解释:

The results of this constructor can be somewhat unpredictable. One might assume that writing new BigDecimal(0.1) in Java creates a BigDecimal which is exactly equal to 0.1 (an unscaled value of 1, with a scale of 1), but it is actually equal to 0.1000000000000000055511151231257827021181583404541015625. This is because 0.1 cannot be represented exactly as a double (or, for that matter, as a binary fraction of any finite length). Thus, the value that is being passed in to the constructor is not exactly equal to 0.1, appearances notwithstanding.

虽然你的变量是浮点数,但没有接受浮点数的构造函数,所以它们被转换为双精度数。就像文档所说的那样,如果您使用字符串作为您的值,您将得到您期望的确切结果 (38)。

错误就在开头:

float value1 = 1.9f;

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

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