BigDecimal 在转换 to/from 浮点数时不保留舍入值
BigDecimal not retaining rounded value when converting to/from float
我有一个函数可以使用 BigDecimal.setScale
将浮点数舍入到 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));
正好相反。 BigDecimal
说的是实话。 0.26579999923706055 更接近您的 float
在四舍五入前后一直获得的值。 float
是二进制而不是十进制数不能精确地包含 0.2658。实际上 0.265799999237060546875 已经很接近了。
当你打印浮点数时,你没有得到完整的值。发生了一些舍入,因此尽管 float
具有上述值,但您只能看到 0.2658
.
当您从 float
创建 BigDecimal
时,您实际上首先转换为 double
(因为这是 BigDecimal.valueOf()
接受的)。 double
与 float
具有相同的值,但将打印为 0.26579999923706055,这也是您的 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
.
那么到底发生了什么:
- 您的
float
在四舍五入前后的内部值为 0.265799999237060546875。
- 当您将
float
传递给 BigDecimal.valueOf(double)
时,您实际上是在转换 float
-> double
-> String
-> BigDecimal
.
-
double
与 float
具有相同的值,0.265799999237060546875.
- 到
String
的转换稍微舍入到 "0.26579999923706055"
。
- 因此您的
BigDecimal
得到的值为 0.26579999923706055,即您看到并询问的值。
来自 BigDecimal.valueOf(double)
的文档:
Translates a double
into a BigDecimal
, using the double
's
canonical string representation provided by the
Double.toString(double)
method.
链接
- 堆栈溢出问题:Is floating point math broken?
- 文档:
BigDecimal.valueOf(double)
- 堆栈溢出问题:BigDecimal - to use new or valueOf
我决定修改我的程序,使用 BigDecimal 作为对象中 属性 价格的基本类型,而不是 float 类型。虽然一开始很棘手,但在 运行.
中绝对是更清洁的解决方案
public class Order {
// float price; // old type
BigDecimal price; // new type
}
我有一个函数可以使用 BigDecimal.setScale
将浮点数舍入到 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));
正好相反。 BigDecimal
说的是实话。 0.26579999923706055 更接近您的 float
在四舍五入前后一直获得的值。 float
是二进制而不是十进制数不能精确地包含 0.2658。实际上 0.265799999237060546875 已经很接近了。
当你打印浮点数时,你没有得到完整的值。发生了一些舍入,因此尽管 float
具有上述值,但您只能看到 0.2658
.
当您从 float
创建 BigDecimal
时,您实际上首先转换为 double
(因为这是 BigDecimal.valueOf()
接受的)。 double
与 float
具有相同的值,但将打印为 0.26579999923706055,这也是您的 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 callingtoString
on thedouble
value. That's not the same as the number actually represented by thatdouble
. That's whyBigDecimal.valueOf(double)
doesn't in general return the same value asnew BigDecimal(double)
. It's really important to understand the difference if you're going to be working with floating point values and withBigDecimal
.
那么到底发生了什么:
- 您的
float
在四舍五入前后的内部值为 0.265799999237060546875。 - 当您将
float
传递给BigDecimal.valueOf(double)
时,您实际上是在转换float
->double
->String
->BigDecimal
.-
double
与float
具有相同的值,0.265799999237060546875. - 到
String
的转换稍微舍入到"0.26579999923706055"
。 - 因此您的
BigDecimal
得到的值为 0.26579999923706055,即您看到并询问的值。
-
来自 BigDecimal.valueOf(double)
的文档:
Translates a
double
into aBigDecimal
, using thedouble
's canonical string representation provided by theDouble.toString(double)
method.
链接
- 堆栈溢出问题:Is floating point math broken?
- 文档:
BigDecimal.valueOf(double)
- 堆栈溢出问题:BigDecimal - to use new or valueOf
我决定修改我的程序,使用 BigDecimal 作为对象中 属性 价格的基本类型,而不是 float 类型。虽然一开始很棘手,但在 运行.
中绝对是更清洁的解决方案public class Order {
// float price; // old type
BigDecimal price; // new type
}