将 double 转换为 BigDecimal 并设置 BigDecimal 精度
Posted
技术标签:
【中文标题】将 double 转换为 BigDecimal 并设置 BigDecimal 精度【英文标题】:Convert double to BigDecimal and set BigDecimal Precision 【发布时间】:2012-09-05 21:25:41 【问题描述】:在 Java 中,我想获取一个双精度值并将其转换为 BigDecimal
并将其字符串值打印到一定精度。
import java.math.BigDecimal;
public class Main
public static void main(String[] args)
double d=-.00012;
System.out.println(d+""); //This prints -1.2E-4
double c=47.48000;
BigDecimal b = new BigDecimal(c);
System.out.println(b.toString());
//This prints 47.47999999999999687361196265555918216705322265625
它打印出这个巨大的东西:
47.47999999999999687361196265555918216705322265625
而不是
47.48
我进行BigDecimal
转换的原因是有时双精度值会包含很多小数位(即-.000012
),而将双精度值转换为字符串时会产生科学记数法-1.2E-4
。我想以非科学记数法存储字符串值。
我希望 BigDecimal 始终具有两个精度单位,例如:“47.48”。 BigDecimal 可以限制转换为字符串的精度吗?
【问题讨论】:
注意:BigDecimal 有时也会使用科学记数法(我相信数字 【参考方案1】:这种行为的原因是打印的字符串是准确的值 - 可能不是你所期望的,但这是存储在内存中的真实值 - 这只是浮点表示的限制。
根据 javadoc,如果不考虑此限制,BigDecimal(double val) 构造函数的行为可能会出乎意料:
此构造函数的结果可能有些不可预测。一 可能会假设用 Java 编写 new BigDecimal(0.1) 会创建一个 BigDecimal 正好等于 0.1(未缩放的值 1,与 比例为 1),但实际上等于 0.10000000000000000055511151231257827021181583404541015625。这是因为 0.1 不能完全表示为双精度数(或者,对于 物质,作为任何有限长度的二进制分数)。因此,价值 传递给构造函数的不完全等于 0.1,尽管出现了。
所以在你的情况下,而不是使用
double val = 77.48;
new BigDecimal(val);
使用
BigDecimal.valueOf(val);
BigDecimal.valueOf 返回的值等于调用Double.toString(double)
产生的值。
【讨论】:
今天遇到了完全相同的问题,恕我直言,这是最合适的答案!谢谢! 我建议在BigDecimal.valueOf(val)
之后添加.stripTrailingZeros()
以省略尾随零。示例:BigDecimal.valueOf(15.0).stripTrailingZeros();
-> 15(如果您不调用 .stripTrailingZeros()
,则不是 15.0@【参考方案2】:
如果您使用另一个 MathContext,它会打印 47.48000:
BigDecimal b = new BigDecimal(d, MathContext.DECIMAL64);
只需选择您需要的上下文。
【讨论】:
不推荐使用双重构造函数。 ***.com/questions/1056722/… BigDecimal b = BigDecimal.valueOf(d); @rvazquezglez 喜欢你的解决方案 其他值仍然存在缺陷。例如new BigDecimal( 1E-11, MathContext.DECIMAL64).toPlainString()
打印0.000000000009999999999999999
,但BigDecimal.valueOf
按预期工作。【参考方案3】:
您想尝试String.format("%f", d)
,它将以十进制表示法打印您的双精度数。根本不要使用BigDecimal
。
关于精度问题:您首先将47.48
存储在double c
中,然后从该double
中创建一个新的BigDecimal
。精确度的损失在于分配给c
。你可以这样做
BigDecimal b = new BigDecimal("47.48")
避免丢失任何精度。
【讨论】:
【参考方案4】:为什么不:
b = b.setScale(2, RoundingMode.HALF_UP);
【讨论】:
为什么不 BigDecimal b = new BigDecimal(c).setScale(2,BigDecimal.ROUND_HALF_UP);【参考方案5】:它正在打印出double
的实际准确值。
Double.toString()
,将double
s 转换为String
s,不 打印输入的确切十进制值——如果x
是您的双精度值,它会打印出足够的数字,x
是最接近它打印的值的double
。
关键是 没有像 47.48 这样的double
。 Doubles 将值存储为 binary 分数,而不是小数,因此它不能存储精确的十进制值。 (这就是BigDecimal
的用途!)
【讨论】:
【参考方案6】:String.format 语法帮助我们将双精度数和 BigDecimals 转换为任何精度的字符串。
这个java代码:
double dennis = 0.00000008880000d;
System.out.println(dennis);
System.out.println(String.format("%.7f", dennis));
System.out.println(String.format("%.9f", new BigDecimal(dennis)));
System.out.println(String.format("%.19f", new BigDecimal(dennis)));
打印:
8.88E-8
0.0000001
0.000000089
0.0000000888000000000
【讨论】:
【参考方案7】:BigDecimal b = new BigDecimal(c).setScale(2,BigDecimal.ROUND_HALF_UP);
【讨论】:
【参考方案8】:在 Java 9 中,以下内容已被弃用:
BigDecimal.valueOf(d).
setScale(2, BigDecimal.
ROUND_HALF_UP);
改为使用:
BigDecimal.valueOf(d).setScale(2, RoundingMode.HALF_UP);
例子:
double d = 47.48111;
System.out.println(BigDecimal.valueOf(d)); //Prints: 47.48111
BigDecimal bigDecimal = BigDecimal.valueOf(d).setScale(2, RoundingMode.HALF_UP);
System.out.println(bigDecimal); //Prints: 47.48
【讨论】:
以上是关于将 double 转换为 BigDecimal 并设置 BigDecimal 精度的主要内容,如果未能解决你的问题,请参考以下文章
java - 如何将浮点数转换为 BigDecimal? [复制]
如何修复java.lang.ClassCastException:java.lang.Double无法转换为变量表达式的java.math.BigDecimal错误?