有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java BigDecimal在转换为浮点/从浮点转换时不保留舍入值

我有一个函数,它使用BigDecimal将一个浮点数舍入到n位数。设置刻度

private float roundPrice(float price, int numDigits) {
    BigDecimal bd = BigDecimal.valueOf(price);
    bd = bd.setScale(numDigits, RoundingMode.HALF_UP);
    float roundedFloat = bd.floatValue();
    return roundedFloat;
}

public void testRoundPrice() {
    float numberToRound = 0.2658f;
    System.out.println(numberToRound);
    float roundedNumber = roundPrice(numberToRound, 5);
    System.out.println(roundedNumber);
    BigDecimal bd = BigDecimal.valueOf(roundedNumber);
    System.out.println(bd);
}

输出:

0.2658
0.2658
0.26579999923706055

如何防止BigDecimal在舍入值末尾添加所有这些额外数字

注意:我无法执行以下操作,因为我无法访问api调用函数中的位数

System.out.println(bd.setScale(5, RoundingMode.CEILING));

共 (2) 个答案

  1. # 1 楼答案

    我决定修改我的程序,在我的对象中使用BigDecimal作为我的财产价格的基本类型,而不是float类型。虽然一开始很棘手,但从长远来看,它肯定是更清洁的解决方案

    public class Order {
        // float price; // old type
        BigDecimal price; // new type
    }
    
  2. # 2 楼答案

    反过来说BigDecimal在告诉你真相。0.2657999923706055更接近float在舍入前后一直获得的值。作为二进制而不是十进制数的float不能精确地容纳0.2658。实际上,0.26579999237060546875是我们能得到的最接近的

    打印浮点时,不会得到完整值。会发生一些舍入,因此尽管float具有上述值,但您只会看到0.2658

    当您从float创建一个BigDecimal时,实际上是首先转换为double(因为这是BigDecimal.valueOf()接受的)。double的值与float的值相同,但打印为0.2657999923706055,这也是BigDecimal获得的值

    如果希望一个BigDecimal具有float打印值,而不是其中的确切值或接近值,则以下操作可能有效:

        BigDecimal bd = new BigDecimal(String.valueOf(roundedNumber));
        System.out.println(bd);
    

    输出:

    0.2658

    但是,您可能会对其他值感到惊讶,因为float没有那么高的精度

    编辑:您正在有效地转换float->double->String->BigDecimal

    达伍德·伊本·卡里姆(Dawood ibn Kareem)的这些富有洞察力的评论让我进行了一些研究:

    Actually 0.265799999237060546875.

    Well, 0.26579999923706055 is the value returned by calling toString on the double value. That's not the same as the number actually represented by that double. That's why BigDecimal.valueOf(double) doesn't in general return the same value as new BigDecimal(double). It's really important to understand the difference if you're going to be working with floating point values and with BigDecimal.

    那么到底发生了什么:

    1. 您的float在四舍五入前后的内部值均为0.26579999237060546875
    2. 当您将float传递给BigDecimal.valueOf(double)时,您实际上是在转换float->double->String->BigDecimal
      • double的值与float的值相同,为0.26579999237060546875
      • String的转换将稍微舍入到"0.26579999923706055"
      • 因此,您的BigDecimal得到的值为0.2657999923706055,这是您看到和询问的值

    BigDecimal.valueOf(double)的文档中:

    Translates a double into a BigDecimal, using the double's canonical string representation provided by the Double.toString(double) method.

    链接