大家好,又见面了,我是你们的朋友全栈君。
原文地址:https://blog.csdn.net/qwfylwc/article/details/53939906
下面列举让你惊讶的现象,或许你还一直这么用:
1、使用Math.round()
double d = 1041.735;
d = Math.round(d*100)/100.0; //除以100.0 而不是100
System.out.println(d); //输出结果是1041.73
2、使用 BigDecima
double d = 9.655;
BigDecimal b = new BigDecimal(d);
d = b.setScale(2,RoundingMode.HALF_UP).doubleValue();
System.out.println(d); //输出结果是9.65
3、使用DecimalFormat
double d = 11.225;
DecimalFormat df = new DecimalFormat("0.00");
String s = df.format(d);
System.out.println(s);//输出结果是11.22
所有的根源都是double的浮点运算机制
例1
1041.735*100=104173.49999999999
Math.round(1041.735*100)=104173
例2
在进行使用double的构造函数之后,发生了变化,导致后续的四舍五入错误
例3
和例1、例2有点区别,在内部实现时,也是进行了相关的浮点预算
综上所述:只要进行浮点运算,就可能产生精度问题
上述例2和例3几乎接近真实,只需要进行一点调整即可
例2
double d = 9.655;
//通过改变构造方法,就可以解决精度丢失问题
BigDecimal b = new BigDecimal(Double.toString(d));
d = b.setScale(2,RoundingMode.HALF_UP).doubleValue();
System.out.println(d); //输出结果是9.66
例3
double d = 11.225;
DecimalFormat df = new DecimalFormat("0.00");
//指定RoundingMode
df.setRoundingMode(RoundingMode.HALF_UP);
String s = df.format(d);
System.out.println(s);//输出结果是11.23
下面我们再来看一个经典的例子
计算199999.00*0.015,结果保留2位有效数字
理论上 199999.00*0.015=2999.985
实际上java的bouble运算是 199999.00*0.015=2999.984999….
下面提供了一个double运算的工具类,最后的format解决了科学计数法显示问题(1.53E10)
public class DoubleUtil {
private static final int DIV_SCALE=10;//默认除法运算精度
private DoubleUtil(){
}
/**
* 提供精确的加法运算
* @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 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 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();
}
/**
* 提供(相对)精确的除法运算
* 当除不尽时,使用默认精度:DIV_SCALE
* @param v1 被除数
* @param v2 除数
* @return 两个参数的商
*/
public static double div(double v1,double v2){
return div(v1,v2,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("scale不能小于0");
}
BigDecimal b1 = new BigDecimal(Double.toString(v1));
BigDecimal b2 = new BigDecimal(Double.toString(v2));
return b1.divide(b2,scale,BigDecimal.ROUND_HALF_UP).doubleValue();
}
/**
* 提供精确的小数位四舍五入处理
* @param v 需要四舍五入的数字
* @param scale 小数点后保留几位
* @return 四舍五入后的结果
*/
public static double round(double v1,int scale){
if(scale<0){
throw new IllegalArgumentException("scale不能小于0");
}
BigDecimal b = new BigDecimal(Double.toString(v1));
BigDecimal one = new BigDecimal("1");
return b.divide(one,scale,BigDecimal.ROUND_HALF_UP).doubleValue();
}
public static String format(double v1,int scale){
String s = String.valueOf(round(v1,scale));
s = new BigDecimal(s).toPlainString();//解决科学计算法转换问题
int k = s.indexOf(".");
if(k<0 && scale>0){
s = s+".0";
k=s.indexOf(".");
}
if(k>0){
int d_scale = (s.length()-(k+1));
if(scale>d_scale){
for(int i=0;i<scale-d_scale;i++){
s+="0";
}
}else if(scale<d_scale){//当scale=0时才会出现这种情况
s = s.substring(0,k);
}
}
return s;
}
}
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/156866.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...