Bigdecimal 数据转换精度缺失
使用 new BigDecimal()、.valueof() 和 new BigDecimal("[字符串]")的区别
构造 BigDecimal 对象常用以下方法:
BigDecimal BigDecimal(double d); //不允许使用
BigDecimal BigDecimal(String s); //常用,推荐使用
static BigDecimal valueOf(double d); //常用,推荐使用
其原因有
- double 参数的构造方法,不允许使用!!!!因为它不能精确的得到相应的值;
- String 构造方法是完全可预知的: 写入 new BigDecimal("0.1") 将创建一个 BigDecimal,它正好等于预期的0.1; 因此,通常建议优先使用 String 构造方法;
- 静态方法 valueOf(double val) 内部实现,仍是将 double 类型转为 String 类型; 这通常是将 double(或float)转化为 BigDecimal 的首选方法;
如下代码测试操作:
public class BigDecimalDemo {
public static void main(String[] args) {
Double v1 = 2.43;
Double v2 = 4.0;
System.out.println(new BigDecimal(v1));
System.out.println(new BigDecimal(v2));
System.out.println(new BigDecimal(v1.toString()));
System.out.println(new BigDecimal(v2.toString()));
System.out.println(BigDecimal.valueOf(v1));
System.out.println(BigDecimal.valueOf(v2));
}
}
以上输出的结果是:
2.430000000000000159872115546022541821002960205078125
4
2.43
4.0
2.43
4.0
从结果可以看的出来直接 new BigDecimal()的情况会出现数据精准度丢失的情况
而. valueof 和 new 字符串的形式却不会使精度丢失
我们可以看一下他的源码:
/**
* Translates a {@code double} into a {@code BigDecimal}, using
* the {@code double}'s canonical string representation provided
* by the {@link Double#toString(double)} method.
*
* <p><b>Note:</b> This is generally the preferred way to convert
* a {@code double} (or {@code float}) into a
* {@code BigDecimal}, as the value returned is equal to that
* resulting from constructing a {@code BigDecimal} from the
* result of using {@link Double#toString(double)}.
*
* @param val {@code double} to convert to a {@code BigDecimal}.
* @return a {@code BigDecimal} whose value is equal to or approximately
* equal to the value of {@code val}.
* @throws NumberFormatException if {@code val} is infinite or NaN.
* @since 1.5
*/
public static BigDecimal valueOf(double val) {
// Reminder: a zero double returns '0.0', so we cannot fastpath
// to use the constant ZERO. This might be important enough to
// justify a factory approach, a cache, or a few private
// constants, later.
return new BigDecimal(Double.toString(val));
}
valueof 的形式是将 double 直接 tostring 为一个字符串的形式进行转换的
BigDecimal 的大小比较
BigDecimal是Java里精确计算的类,下面说一下两个BigDecimal对象大小,相等的判断。
一般的对象用equals,但是BigDecimal比较特殊,举个例子:
public static void main(String[] args) {
BigDecimal a = new BigDecimal("10.00");
BigDecimal b = new BigDecimal("10");
//equals方式
System.out.println(a.equals(b)); //结果为: false
//toPlainString再equals
System.out.println(a.toPlainString().equals(b.toPlainString())); //结果为: false
//longValue方式
System.out.println(a.longValue() == b.longValue()); //结果为: true
//compareTo
System.out.println(a.compareTo(b) == 0); //结果为: true
}
看似使用 Long 数据类型进行比较也可以但是我们看下一个例子:
public static void main(String[] args) {
BigDecimal a = new BigDecimal("10.300003");
BigDecimal b= new BigDecimal(10.300003);
System.out.println(b.equals(a)); //false
System.out.println(b.toPlainString().equals(a.toPlainString())); //false
System.out.println(b.longValue() == a.longValue()); //true
System.out.println(b.compareTo(a) == 0); //false
}
为什么compareTo方法不可以了,而longValue方式却还是OK的。让我们打印一下。
public static void main(String[] args) {
BigDecimal a = new BigDecimal("10.300003");
BigDecimal b= new BigDecimal(10.300003);
System.out.println(b.equals(a)); //false
System.out.println(b.toPlainString().equals(a.toPlainString())); //false
System.out.println(b.longValue() == a.longValue()); //true
System.out.println("b.longValue():"+b.longValue());
System.out.println("a.longValue():"+a.longValue());
System.out.println(b.compareTo(a) == 0); //false
}
而输出的结果令我懵逼
false
false
true
b.longValue():10
a.longValue():10
false
我们可以看出longvalue 的结果是没有小数点的所以对 BigDecimal 数据类型进行比较的时候还是使用"compareTo"方法
总结: 当我们需要使用BigDecimal 进行数据转换时一定要注意转换的数据类型以及大小比较的唯一方法我们可以对它的值进行<或者>的判断如:
public static void main(String[] args) {
BigDecimal a = new BigDecimal("10.300003");
BigDecimal b= BigDecimal.valueOf(10.3);
System.out.println(b.compareTo(a) < 0); //true
System.out.println(b.compareTo(a) > 0); //false
}
最后:感谢大家的阅读
网友评论