Java BigDecimal setScale方法的工作方式与我期望的完全相反

Java BigDecimal setScale方法的工作方式与我期望的完全相反,java,rounding,bigdecimal,Java,Rounding,Bigdecimal,考虑以下代码: import java.math.BigDecimal; import java.math.RoundingMode; public class RoundingTests { public static void main(String[] args) { BigDecimal bd1 = new BigDecimal(265.345d); BigDecimal bd2 = new BigDecimal(265.335d);

考虑以下代码:

import java.math.BigDecimal;
import java.math.RoundingMode;

public class RoundingTests {

    public static void main(String[] args) {
        BigDecimal bd1 = new BigDecimal(265.345d);
        BigDecimal bd2 = new BigDecimal(265.335d);

        System.out.println("Setting scale 265.345: " + bd1.setScale(2, RoundingMode.HALF_EVEN));
        System.out.println("Setting scale 265.335: " + bd2.setScale(2, RoundingMode.HALF_EVEN));
    }
}
输出为:

Setting scale 265.345: 265.35
Setting scale 265.335: 265.33
Rounding 265.345: 2.7E+2
Rounding 265.335: 2.7E+2
现在这与我的预期正好相反。使用
RoundingMode.HALF_偶数
(也称为银行家舍入),我希望这两个值都成为
265.34

请注意,我不是故意使用
BigDecimal.round
方法,因为它也不符合我的需要。如果我添加此代码(并导入java.math.MathContext):

那么输出是:

Setting scale 265.345: 265.35
Setting scale 265.335: 265.33
Rounding 265.345: 2.7E+2
Rounding 265.335: 2.7E+2
这是意料之中的,在中也有解释,但这意味着它对我的目的基本上是无用的

有人能解释一下这个问题吗


更新:所以这只是另一个浮点问题,没有简单的方法来解决它,而不是从一开始就使用BigDecimal。

您可能希望将代码更改为使用
BigDecimal.valueOf()
而不是
新的BigDecimal()

代码

  Double dValue = 265.345d;
  Double dValue2 = 265.335d;
  BigDecimal value = BigDecimal.valueOf(dValue);
  BigDecimal bd1 = new BigDecimal(265.345d);
  BigDecimal bd2 = new BigDecimal(265.335d);
  BigDecimal value2 = BigDecimal.valueOf(dValue2);
  System.out.println("BigDecimal.valueOf(dValue);");
  System.out.println(value.toPlainString());
  System.out.println(String.valueOf(dValue));
  value = value.setScale(2, BigDecimal.ROUND_HALF_EVEN);
  System.out.println(value);
  System.out.println("BigDecimal.valueOf(dValue2);");
  System.out.println(value2.toPlainString());
  System.out.println(String.valueOf(dValue2));
  value2 = value2.setScale(2, BigDecimal.ROUND_HALF_EVEN);
  System.out.println(value2);
  System.out.println("BigDecimal bd1 = new BigDecimal(265.345d);");
  System.out.println(bd1.setScale(2, BigDecimal.ROUND_HALF_EVEN));
  System.out.println("BigDecimal bd2 = new BigDecimal(265.335d);");
  System.out.println(bd2.setScale(2, BigDecimal.ROUND_HALF_EVEN));
产出:

BigDecimal.valueOf(dValue);
265.345
265.345
265.34
BigDecimal.valueOf(dValue2);
265.335
265.335
265.34
BigDecimal bd1 = new BigDecimal(265.345d);
265.35
BigDecimal value2 = BigDecimal.valueOf(dValue2);
265.33

问题在于浮点常量。尝试使用带引号的字符串而不是浮点常量作为构造函数参数。。。那真烦人。在我的实际应用程序中,它们不是文本,而是双变量,但我想这同样适用。所以这可能只是一个巧合,它做的与我期望的相反,对于其他值,它可能会意外地正常工作。奇怪的是,这么简单的事情变得这么难。我真的不想把东西转换成字符串再转换回来,但这似乎是唯一可行的解决方案。表示货币价值总是一件痛苦的事情。你从哪里得到这些价值?它们真的只有3位数吗?它们可能来自很多地方。在本例中,它们实际上只有3位数字,因为这是我自己制作的测试用例。它是一个具有该精确值的java.lang.Double。但是我们正在开发一个通用的应用程序开发平台,所以它可能意味着任何东西。我将用我的实际解决方案更新我的答案。谢谢,这比我的方法更有效,不必使用字符串值。然而,实际实现似乎也使用双精度值的字符串表示。在Javadoc中:
valueOf(double-val)使用double.toString(double)方法提供的double的规范字符串表示法将double转换为BigDecimal。
。所以基本上这也不能解决浮点数的问题。显示的输出不是上面代码的输出。例如,没有“BigDecimal bd2=新的BigDecimal(265.335d);”。