网站开发常问的技术性问题,广州网站建设如何做,微信订单网站模版,三点水网站建设合同书文章目录为什么要使用BigDecimal构造方法加减乘除舍入模式#xff08;对BigDecimal进行截取#xff09;取余数比较大小BigDecimal 转 StringBigDecimal与double和int转换格式化显示 BigDecimal使用DecimalFormat使用String.format()总结为什么要使用BigDecimal
double类型的…
文章目录为什么要使用BigDecimal构造方法加减乘除舍入模式对BigDecimal进行截取取余数比较大小BigDecimal 转 StringBigDecimal与double和int转换格式化显示 BigDecimal使用DecimalFormat使用String.format()总结为什么要使用BigDecimal
double类型的数据进行加减乘除不会得到精确的结果。
public static void main(String[] args) {System.out.println(0.2 0.1);System.out.println(0.3 - 0.1);System.out.println(0.2 * 0.1);System.out.println(0.3 / 0.1);}运行上述的计算代码会得到如下的结果
0.30000000000000004
0.19999999999999998
0.020000000000000004
2.9999999999999996那为什么会出现这种情况呢
原因在于我们的计算机是二进制的。所以 CPU 表示浮点数由两个部分组成指数和尾数这样的表示方法一般都会失去一定的精确度有些浮点数运算也会产生一定的误差。所以二进制根本无法精确表示浮点数。只能无限接近于精确值而已。
float和double类型的主要设计目标是为了科学计算和工程计算这些数据类型是为了在广域数值范围上提供快速近似计算而精心设计的。它们没有提供完全精确的结果所以不应该被用于要求精确结果的场合。但是商业计算往往要求结果精确这时候 BigDecimal 就派上大用场啦。
构造方法
1.public BigDecimal(double val) 将 double 表示形式转换为 BigDecimal不建议使用
2.public BigDecimal(int val) 将 int 表示形式转换成 BigDecimal
3.public BigDecimal(String val) 将 String 表示形式转换成 BigDecimal
为什么不建议使用第一种构造器看下面的例子 public static void main(String[] args) {BigDecimal bigDecimal new BigDecimal(2);BigDecimal bDouble new BigDecimal(2.3);BigDecimal bString new BigDecimal(2.3);System.out.println(bigDecimal bigDecimal);System.out.println(bDouble bDouble);System.out.println(bString bString);}最终输出的结果为
bigDecimal2
bDouble2.29999999999999982236431605997495353221893310546875
bString2.3从上面的输出结果可以得知double 数据转换成 BigDecimal 后并不能得到精确的数据。为什么这样呢
官方解释说BigDecimal 的参数类型为 double 的构造方法的结果有一定的不可预知性。在代码中你看到的2.3其实只是显示成 2.3 而已2.3 其实并没有对应的精确二进制数其对应的二进制数转换成十进制小数实际是 2.29999999999999982236431605997495353221893310546875只是显示成 2.3 而已。
所以使用 new BigDecimal(2.3); 构造 BigDecimal 对象时底层参与计算的是对应的二进制数而这个二进制数转换成十进制数 2.29999999999999982236431605997495353221893310546875而 BigDecimal 可以精确表示这串数值所以最终输出的结果就是 2.29999999999999982236431605997495353221893310546875。
另一方面BigDecimal(String val) 构造方法是完全可预知的写入 newBigDecimal(“0.1”) 将创建一个 BigDecimal它正好等于预期的 0.1。因此比较而言通常建议优先使用 String 构造方法。
当 double 必须用作 BigDecimal 的源时请使用 Double.toString(double) 转成 String然后使用参数类型为 String 的 BigDecimal 构造方法或使用 BigDecimal 的静态方法 valueOf如下 public static void main(String[] args) {BigDecimal bd1 new BigDecimal(Double.toString(2.3));BigDecimal bd2 BigDecimal.valueOf(2.3);System.out.println(bd1);System.out.println(bd2);}加减乘除
对于常用的加减乘除BigDecimal 类提供了相应的成员方法
public BigDecimal add(BigDecimal value); //加法public BigDecimal subtract(BigDecimal value); //减法 public BigDecimal multiply(BigDecimal value); //乘法public BigDecimal divide(BigDecimal value); //除法具体用法如下 public static void main(String[] args) {BigDecimal a new BigDecimal(4.5);BigDecimal b new BigDecimal(1.5);System.out.println(a b a.add(b));System.out.println(a - b a.subtract(b));System.out.println(a * b a.multiply(b));System.out.println(a / b a.divide(b));}注意因为BigInteger与BigDecimal都是不可变的immutable的在进行每一步运算时都会产生一个新的对象。
舍入模式对BigDecimal进行截取
BigDecimal 除法可能出现不能整除的情况比如 4.5/1.3这时会报错java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.
其实divide方法有可以传三个参数
public BigDecimal divide(BigDecimal divisor, int scale, int roundingMode) 第一个参数表示除数第二个参数表示小数点后保留的位数第三个参数表示舍入模式只有在作除法运算或四舍五入时才用到舍入模式。
有下面这几种
ROUND_CEILING //向正无穷方向舍入。如果为正数舍入结果同ROUND_UP一致如果为负数舍入结果同ROUND_DOWN一致。注意此模式不会减少数值大小。
ROUND_DOWN //向零方向舍入。舍弃非零部分不会对非零舍弃部分相邻的数字加一采取截取行为。
ROUND_FLOOR //向负无穷方向舍入。如果为正数舍入结果同ROUND_DOWN一致如果为负数舍入结果同ROUND_UP一致。注意此模式不会增加数值大小。
ROUND_HALF_DOWN //向“最接近”的数字舍入如果与两个相邻数字的距离相等则为向下舍入的舍入模式。向距离最近的一边舍入除非两边的距离是相等,如果是这样向下舍入。这种模式也就是我们常说的我们的“五舍六入”。例如1.55 保留一位小数结果为1.5。
ROUND_HALF_EVEN //向“最接近”的数字舍入如果与两个相邻数字的距离相等则向相邻的偶数舍入。即如果舍弃部分左边的数字奇数则舍入行为与 ROUND_HALF_UP 相同如果为偶数则舍入行为与 ROUND_HALF_DOWN 相同。注意在重复进行一系列计算时此舍入模式可以将累加错误减到最小。此舍入模式也称为“银行家舍入法”主要在美国使用。总结一句话四舍六入五分两种情况如果前一位为奇数则入位否则舍去。
ROUND_HALF_UP //向“最接近”的数字舍入如果与两个相邻数字的距离相等则为向上舍入的舍入模式。即向距离最近的一边舍入除非两边的距离是相等,如果是这样向上舍入。1.55保留一位小数结果为1.6。这个其实就是四舍五入
ROUND_UNNECESSARY //断言请求的操作具有精确的结果因此不需要舍入。如果对获得非精确结果的操作指定此舍入模式则抛出ArithmeticException。
ROUND_UP //向远离0的方向舍入。舍弃非零部分并将非零舍弃部分相邻的数字加一。例如4.5633若保留3位小数则结果是4.564按照各自的需要可传入合适的第三个参数。
从 Java 9.0 开始不再推荐使用 BigDecimal 的常量而改成使用枚举类 RoundingMode 的枚举值
CEILING
DOWN
FLOOR
HALF_DOWN
HALF_EVEN
HALF_UP // 就是四舍五入
UNNECESSARY
UP // 向远离0的方向舍入需要对 BigDecimal 进行截断并且四舍五入可用 setScale 方法例
public static void main(String[] args) {BigDecimal a new BigDecimal(4.5635);a a.setScale(3, BigDecimal.ROUND_HALF_UP); //保留3位小数且四舍五入// BigDecimal的常量ROUND_HALF_UP被封装成了RoundingMode的枚举值HALF_UPa a.setScale(3, RoundingMode.HALF_UP);System.out.println(a);}取余数
public BigDecimal[] divideAndRemainder(BigDecimal divisor);该方法接收另一个BigDecimal 对象作为参数该参数即为除数返回一个BigDecimal数组返回数组中包含两个元素第一个元素为两数相除的商第二个元素为余数。
使用案例如下
public static void main(String[] args) {BigDecimal amt new BigDecimal(14);BigDecimal[] results amt.divideAndRemainder(BigDecimal.valueOf(5));System.out.println(商 results[0]);System.out.println(余 results[1]);}比较大小
BigDecimal a new BigDecimal (101);
BigDecimal b new BigDecimal (111);//使用compareTo方法比较
//注意a、b均不能为null否则会报空指针
if(a.compareTo(b) -1){System.out.println(a小于b);
}if(a.compareTo(b) 0){System.out.println(a等于b);
}if(a.compareTo(b) 1){System.out.println(a大于b);
}if(a.compareTo(b) -1){System.out.println(a大于等于b);
}if(a.compareTo(b) 1){System.out.println(a小于等于b);
}BigDecimal 转 String
public static void main(String[] args) {// 浮点数的打印System.out.println(new BigDecimal(10000000000).toString());// 普通的数字字符串System.out.println(new BigDecimal(100.000).toString());// 去除末尾多余的0System.out.println(new BigDecimal(100.000).stripTrailingZeros().toString());// 避免输出科学计数法System.out.println(new BigDecimal(100.000).stripTrailingZeros().toPlainString());}1.用toString()方法输出的就是普通的数字字符串。 2.stripTrailingZeros()函数就是用于去除末尾多余的0的 3.用toPlainString()函数代替toString(),避免输出科学计数法的字符串。
输出结果为
10000000000
100.000
1E2
100BigDecimal与double和int转换
double 转成 BigDecimal
double d 33.45;
BigDecimal b BigDecimal.valueOf(d);
System.out.println(b);BigDecimal 转成 double
BigDecimal b new BigDecimal(33.67);
double d b.doubleValue();
System.out.println(d);格式化显示 BigDecimal
使用DecimalFormat
public static void main(String[] args) {BigDecimal num new BigDecimal(13.155215);DecimalFormat df1 new DecimalFormat(0.00); // 格式也可以写成 #.00String str df1.format(num);System.out.println(str);// 13.16}使用String.format() public static void main(String[] args) {BigDecimal num new BigDecimal(13.155215);String result String.format(%.2f, num);// %.2f - %. 表示小数点前允许任意位数2表示保留两位小数f表示格式的结果为浮点型System.out.println(result);}总结
1.商业计算使用BigDecimal。 2.尽量使用参数类型为String的构造函数。 3.BigDecimal都是不可变的immutable的在进行每一步运算时都会产生一个新的对象所以在做加减乘除运算时千万要保存操作后的值。