9
回答
Java中的Double类型加减乘除如何保证精度不丢失
【腾讯云】学生服务器套餐10元/月 >>>   

最近在进行开发的时候发现,金额计算上面由于采用了double类型导致了一个问题就是,精度丢失的情况,请问各位是如何处理Java中double变量在计算时候精度丢失的问题的。

举报
easymbol
发帖于9个月前 9回/577阅

请点评这个例子,包括 输出和摘要。可能对解决精度丢失的问题有参考价值。

import java.math.BigDecimal;
public class A {
	public static void main(String args[]){
/* 已知两个双精度变量 f1, f2 */
		double f1= 1.453646757665879802;
		double f2= 2.546576546565797861;
/* 用BigDecimal类处理, 初始化必须使用字符串.
 * 因为用数值初始化会得到近似值,不准确 */	
		String df1 = Double.toString(f1); 
		String df2 = Double.toString(f2);
		
/* 使用字符串作参数生成匿名对象,据此创建标度为 20 的 BigDecimal 对象 b1,b2 */
  BigDecimal b1 = new BigDecimal(df1).setScale(20,BigDecimal.ROUND_HALF_UP); 
  BigDecimal b2 = new BigDecimal(df2).setScale(20,BigDecimal.ROUND_HALF_UP);
  
  /* 分别调用 BigDecimal 方法,进行四则运算,结果仍为 BigDeciamal 实体  */
  BigDecimal ad  = b1.add(b2); 
  BigDecimal sub = b1.subtract(b2);
  BigDecimal div = b1.divide(b2,6); // 根据测试,这里 舍入模式 最多设作 6.
  BigDecimal mul = b1.multiply(b2);
  
  /* 输出两种结果:1. 通过 BigDecimal 保留精度的操作, 2. 直接用双精度变量做算子 */
  System.out.println("保留 20 位小数,加法结果: " + ad);
  System.out.printf(" 直接相加 %39.20f\n", (f1 + f2));
  System.out.println("保留 20 位小数,减法结果: " + sub);
  System.out.printf(" 直接相减 %39.20f\n" , (f1 - f2));
  System.out.println("保留 16+16 位小数,乘法结果: " +  mul);
  System.out.printf(" 直接相乘 %54.32f\n", f1*f2);
  System.out.println("保留 6 位小数,除法结果: " + div);
  System.out.printf(" 直接相除 %38.20f\n", f1/f2);
  }
}

输出:

保留 20 位小数,加法结果: 4.00022330423150000000
 直接相加                              4.00022330423150050000
保留 20 位小数,减法结果: -1.09292978889990000000
 直接相减                             -1.09292978889990010000
保留 16+16 位小数,乘法结果: 3.7018227400629999571383430600000000000000
 直接相乘                                    3.70182274006300060000000000000000
保留 6 位小数,除法结果: 0.57082390067016855318
 直接相除                            0.57082390067016850000

摘要:
1. 用BigDecimal类处理精度问题, 初始化必须使用字符串.
2. 根据 小数点后均为13位的 双精度变量 f1, f2  生成 BigDecemal 对象,此处标度 均设置为 20. 
3. 分别调用 BigDecimal 方法,以达到四则运算的目的,结果仍为 BigDeciamal 实体.
4. 直接用 f1, f2 做算子,用操作符 + - * / 计算得出 双精度数据结果.
5. 比较表明: 
   a. 加法结果, 直至小数点后 20 位 数字都相同.
   b. 减法结果, 只保证 至小数点后 13 位(即原始 f1,f2的位数)数字相同。
   c. 乘法结果,用 BigDecimal 可以得到 32 位的结果。
   d. 除法结果,调用divide()方法,必须设置 舍入模式 roundingMode,本情况最大设为 6.
   e. 除法结果,最后4位数字不同。

金额一般都用BigDecimal。 用来对超过16位有效位的数进行精确的运算。双精度浮点型变量double可以处理16位有效数。在实际应用中,需要对更大或者更小的数进行运算和处理。float和double只能用来做科学计算或者是工程计算,在商业计算中要用java.math.BigDecimal

采用字符串形式构建 BigDecimal ;

如:1.0+2.4556+2.34

BigDecimal temp1 = new BigDecimal("1.0").add(new BigDecimal("2.4556"));

BigDecimal temp2 = temp1.add(new BigDecimal("2.34"));

熟练掌握Java基础协议。

 

 

顶部