关于double与float精度丢失问题~看完我明白了☆

今天刷面试题时,看到了(精度丢失)这个问题,今天来通过参考资料,把它总结一下



①<精度丢失>长什么样?

运行代码:

public static void main(String[] args) {
	System.out.println(2.0-1.1);
}

运行结果:
在这里插入图片描述

是的运行结果是0.8999999999999999,而不是你想的0.9;这种舍入误差的主要原因是浮点数值采用二进制系统表示,而在二进制系统中,无法精确的表示分数1/10,就像是十进制无法精确的标识1/3(0.333333…)一样


②为什么会精度丢失?

使用代码:System.out.println(4.0 - 3.6);
运行结果:0.3999999999999999

计算过程解析:
注意:浮点数值采用二进制系统表示,而在二进制系统中,无法精确的表示分数1/10

  • 将十进制的 4.0 转换成 二进制,将十进制的 3.6 转换成二进制;
    4.0转为二进制:100
    3.6转二进制:11.100110011001…(一直循环除不尽)
  • 使用转换后的二进制,进行减法运算

3.6 转换成二进制,就类似于 1除以3一样,是除不尽。所以 System.out.println(4.0 - 3.6); 就会输出 0.3999999999999999


③用BigDecimal类解决精度丢失的问题

BigDecimal工具包:

/**
 * 用于高精确处理常用的数学运算
 */
public class ArithmeticUtils {
 //默认除法运算精度
 private static final int DEF_DIV_SCALE = 10;

 /**
  * 提供精确的加法运算
  *
  * @param v1 被加数
  * @param v2 加数
  * @return 两个参数的和
  */

 public static double add(double v1, double v2) {
  BigDecimal b1 = new BigDecimal(Double.toString(v1));
  BigDecimal b2 = new BigDecimal(Double.toString(v2));
  return b1.add(b2).doubleValue();
 }

 /**
  * 提供精确的加法运算
  *
  * @param v1 被加数
  * @param v2 加数
  * @return 两个参数的和
  */
 public static BigDecimal add(String v1, String v2) {
  BigDecimal b1 = new BigDecimal(v1);
  BigDecimal b2 = new BigDecimal(v2);
  return b1.add(b2);
 }

 /**
  * 提供精确的加法运算
  *
  * @param v1 被加数
  * @param v2 加数
  * @param scale 保留scale 位小数
  * @return 两个参数的和
  */
 public static String add(String v1, String v2, int scale) {
  if (scale < 0) {
   throw new IllegalArgumentException(
     "The scale must be a positive integer or zero");
  }
  BigDecimal b1 = new BigDecimal(v1);
  BigDecimal b2 = new BigDecimal(v2);
  return b1.add(b2).setScale(scale, BigDecimal.ROUND_HALF_UP).toString();
 }

 /**
  * 提供精确的减法运算
  *
  * @param v1 被减数
  * @param v2 减数
  * @return 两个参数的差
  */
 public static double sub(double v1, double v2) {
  BigDecimal b1 = new BigDecimal(Double.toString(v1));
  BigDecimal b2 = new BigDecimal(Double.toString(v2));
  return b1.subtract(b2).doubleValue();
 }

 /**
  * 提供精确的减法运算。
  *
  * @param v1 被减数
  * @param v2 减数
  * @return 两个参数的差
  */
 public static BigDecimal sub(String v1, String v2) {
  BigDecimal b1 = new BigDecimal(v1);
  BigDecimal b2 = new BigDecimal(v2);
  return b1.subtract(b2);
 }

 /**
  * 提供精确的减法运算
  *
  * @param v1 被减数
  * @param v2 减数
  * @param scale 保留scale 位小数
  * @return 两个参数的差
  */
 public static String sub(String v1, String v2, int scale) {
  if (scale < 0) {
   throw new IllegalArgumentException(
     "The scale must be a positive integer or zero");
  }
  BigDecimal b1 = new BigDecimal(v1);
  BigDecimal b2 = new BigDecimal(v2);
  return b1.subtract(b2).setScale(scale, BigDecimal.ROUND_HALF_UP).toString();
 }

 /**
  * 提供精确的乘法运算
  *
  * @param v1 被乘数
  * @param v2 乘数
  * @return 两个参数的积
  */
 public static double mul(double v1, double v2) {
  BigDecimal b1 = new BigDecimal(Double.toString(v1));
  BigDecimal b2 = new BigDecimal(Double.toString(v2));
  return b1.multiply(b2).doubleValue();
 }

 /**
  * 提供精确的乘法运算
  *
  * @param v1 被乘数
  * @param v2 乘数
  * @return 两个参数的积
  */
 public static BigDecimal mul(String v1, String v2) {
  BigDecimal b1 = new BigDecimal(v1);
  BigDecimal b2 = new BigDecimal(v2);
  return b1.multiply(b2);
 }

 /**
  * 提供精确的乘法运算
  *
  * @param v1 被乘数
  * @param v2 乘数
  * @param scale 保留scale 位小数
  * @return 两个参数的积
  */
 public static double mul(double v1, double v2, int scale) {
  BigDecimal b1 = new BigDecimal(Double.toString(v1));
  BigDecimal b2 = new BigDecimal(Double.toString(v2));
  return round(b1.multiply(b2).doubleValue(), scale);
 }

 /**
  * 提供精确的乘法运算
  *
  * @param v1 被乘数
  * @param v2 乘数
  * @param scale 保留scale 位小数
  * @return 两个参数的积
  */
 public static String mul(String v1, String v2, int scale) {
  if (scale < 0) {
   throw new IllegalArgumentException(
     "The scale must be a positive integer or zero");
  }
  BigDecimal b1 = new BigDecimal(v1);
  BigDecimal b2 = new BigDecimal(v2);
  return b1.multiply(b2).setScale(scale, BigDecimal.ROUND_HALF_UP).toString();
 }

 /**
  * 提供(相对)精确的除法运算,当发生除不尽的情况时,精确到
  * 小数点以后10位,以后的数字四舍五入
  *
  * @param v1 被除数
  * @param v2 除数
  * @return 两个参数的商
  */

 public static double div(double v1, double v2) {
  return div(v1, v2, DEF_DIV_SCALE);
 }

 /**
  * 提供(相对)精确的除法运算。当发生除不尽的情况时,由scale参数指
  * 定精度,以后的数字四舍五入
  *
  * @param v1 被除数
  * @param v2 除数
  * @param scale 表示表示需要精确到小数点以后几位。
  * @return 两个参数的商
  */
 public static double div(double v1, double v2, int scale) {
  if (scale < 0) {
   throw new IllegalArgumentException("The scale must be a positive integer or zero");
  }
  BigDecimal b1 = new BigDecimal(Double.toString(v1));
  BigDecimal b2 = new BigDecimal(Double.toString(v2));
  return b1.divide(b2, scale, BigDecimal.ROUND_HALF_UP).doubleValue();
 }

 /**
  * 提供(相对)精确的除法运算。当发生除不尽的情况时,由scale参数指
  * 定精度,以后的数字四舍五入
  *
  * @param v1 被除数
  * @param v2 除数
  * @param scale 表示需要精确到小数点以后几位
  * @return 两个参数的商
  */
 public static String div(String v1, String v2, int scale) {
  if (scale < 0) {
   throw new IllegalArgumentException("The scale must be a positive integer or zero");
  }
  BigDecimal b1 = new BigDecimal(v1);
  BigDecimal b2 = new BigDecimal(v1);
  return b1.divide(b2, scale, BigDecimal.ROUND_HALF_UP).toString();
 }

 /**
  * 提供精确的小数位四舍五入处理
  *
  * @param v  需要四舍五入的数字
  * @param scale 小数点后保留几位
  * @return 四舍五入后的结果
  */
 public static double round(double v, int scale) {
  if (scale < 0) {
   throw new IllegalArgumentException("The scale must be a positive integer or zero");
  }
  BigDecimal b = new BigDecimal(Double.toString(v));
  return b.setScale(scale, BigDecimal.ROUND_HALF_UP).doubleValue();
 }

 /**
  * 提供精确的小数位四舍五入处理
  *
  * @param v  需要四舍五入的数字
  * @param scale 小数点后保留几位
  * @return 四舍五入后的结果
  */
 public static String round(String v, int scale) {
  if (scale < 0) {
   throw new IllegalArgumentException(
     "The scale must be a positive integer or zero");
  }
  BigDecimal b = new BigDecimal(v);
  return b.setScale(scale, BigDecimal.ROUND_HALF_UP).toString();
 }

 /**
  * 取余数
  *
  * @param v1 被除数
  * @param v2 除数
  * @param scale 小数点后保留几位
  * @return 余数
  */
 public static String remainder(String v1, String v2, int scale) {
  if (scale < 0) {
   throw new IllegalArgumentException(
     "The scale must be a positive integer or zero");
  }
  BigDecimal b1 = new BigDecimal(v1);
  BigDecimal b2 = new BigDecimal(v2);
  return b1.remainder(b2).setScale(scale, BigDecimal.ROUND_HALF_UP).toString();
 }

 /**
  * 取余数 BigDecimal
  *
  * @param v1 被除数
  * @param v2 除数
  * @param scale 小数点后保留几位
  * @return 余数
  */
 public static BigDecimal remainder(BigDecimal v1, BigDecimal v2, int scale) {
  if (scale < 0) {
   throw new IllegalArgumentException(
     "The scale must be a positive integer or zero");
  }
  return v1.remainder(v2).setScale(scale, BigDecimal.ROUND_HALF_UP);
 }

 /**
  * 比较大小
  * 阿里巴巴开发规范明确:比较BigDecimal的等值需要使用compareTo,不可用equals
  * equals会比较值和精度,compareTo会忽略精度
  * @param v1 被比较数
  * @param v2 比较数
  * @return 如果v1 大于v2 则 返回true 否则false
  */
 public static boolean compare(String v1, String v2) {
  BigDecimal b1 = new BigDecimal(v1);
  BigDecimal b2 = new BigDecimal(v2);
  int bj = b1.compareTo(b2);
  boolean res;
  if (bj > 0)
   res = true;
  else
   res = false;
  return res;
 }
}

使用工具包运算:
在这里插入图片描述
在这里插入图片描述
解决精度丢失问题~


参考:
Java用BigDecimal类解决Double类型精度丢失的问题
Java为什么会出现精度丢失这种现象你知道吗

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值