java 基本数据类型转换(精度丢失问题)

JAVA中基本数据类型:

类型:字节:范围:默认值:
byte1-128~1270
short2-32768~327670
char20~65535'\u0000'
int4-2147483648~21474836470
long8-2^63~2^63-10L或0l
float43.402823e38~1.401298e-450.0F或0.0f
double81.797693e308~4.9000000e-3240.0D或0.0d
boolean1false 或 truefalse

在Java编程过程中,经常会涉及到不同数值类型之间的计算问题,例如:

int m=6;  
float n=3.5f;  
double p=2.75d;
System.out.println(m + n); 
System.out.println(n + p);

运行程序,输出结果分别为:9.5和6.25。计算机在执行m+n的时候,首先会将m先转换成float类型,然后再将其与n进行加法运算。同理,执行n+p时,首先将n转换成double类型,然后再将其与p进行加法运算。下面我们来看一下实际编码过程中出现的问题:

我们可以看出,当两个不同类型的数进行基本运算符操作时,精度小的数值类型首先会向精度大的数值类型进行转换,最后进行计算。下面来看下数值类型之间的合法转换图。

图中的实线箭头表示无信息丢失的转换,虚线箭头表示有信息丢失的转换。其转换规则如下:

如果有两个不同的操作数在做运算,其中有一个是double类型,另一个就会转换为double类型;
否则(这两个操作数中没有double类型),如果其中有一个操作数是float,另一个就会转化为float;
否则(这两个操作数中没有double、float类型),如果其中有一个操作数是long,另一个就会转换为long;
否则(这两个操作数中没有double、float、long类型),两个操作数都将转换为int类型。

为了理解这些规则,这里再举几个例子:

private static void m3(){
	int a=6;
	float b=3.5f;
	double c =5.26d;
	long d=82L;
	short e=2;
	byte f=3;
	System.out.println(a + b);  // 9.5  a会转换为float类型,结果为float类型
	System.out.println(a + c);  // 11.26  a会转换为double类型,结果为double类型
	System.out.println(a + d);  // 88   a会转换为long类型
	System.out.println(a + e);  // 8  e会转换为int类型
	System.out.println(a + f);  // 9    f会转换为int类型
	System.out.println(b + c);  // 8.76
	System.out.println(b + d);  // 85.5
	System.out.println(b + e);  // 5.5
	System.out.println(b + f);  // 6.5
	System.out.println(c + d);  // 87.26
	System.out.println(c + e);  // 7.26
	System.out.println(c + f);  // 8.26
	System.out.println(d + e);  // 84
	System.out.println(d + f);  // 85
	System.out.println(e + f);  // 5
}

接下来我们再看下数值之间计算时候存在的计算精度丢失问题。例子如下所示:

private static void m1(){
	int a = 3;
	double b = 0.03;
	double c = 0.03;
	double d = a+b+c;
	System.out.println("d:" + d);    // d:3.0599999999999996
}

这里我们可以看到最后的结果并不是我们预期的那样为3.06,其实double类型数值的计算经常会出现这种精度丢失的问题,尤其是有小数点的情况下,常常会应为精度丢失而导致程序出错。那么该如何解决这个问题呢?这时候我们需要使用位于java.math包中的BigDecima类并用String来构造。具体使用方法如下:

public class DoubleUtil {

    // 加法
	public static double add(double m1, double m2) {
		BigDecimal p1 = new BigDecimal(Double.toString(m1));
		BigDecimal p2 = new BigDecimal(Double.toString(m2));
		return p1.add(p2).doubleValue();
	}
	
	// 减法
	public static double sub(double m1, double m2) {
		BigDecimal p1 = new BigDecimal(Double.toString(m1));
		BigDecimal p2 = new BigDecimal(Double.toString(m2));
		return p1.subtract(p2).doubleValue();
	}
	
	// 乘法
	public static double mul(double m1, double m2) {
		BigDecimal p1 = new BigDecimal(Double.toString(m1));
		BigDecimal p2 = new BigDecimal(Double.toString(m2));
		return p1.multiply(p2).doubleValue();
	}
	
	
	/**
	 * 除法
	 * @param scale  保留小数位的精度个数
	 */
	public static double div(double m1, double m2, int scale) {
		if (scale < 0) {
			throw new IllegalArgumentException("Parameter error");
		}
		BigDecimal p1 = new BigDecimal(Double.toString(m1));
		BigDecimal p2 = new BigDecimal(Double.toString(m2));
		return p1.divide(p2, scale, BigDecimal.ROUND_HALF_UP).doubleValue();
	}
}

参考博文:

https://blog.csdn.net/gulingfengze/article/details/54094193

https://www.cnblogs.com/ryzz/p/10541398.html

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值