JAVA中基本数据类型:
类型: | 字节: | 范围: | 默认值: |
byte | 1 | -128~127 | 0 |
short | 2 | -32768~32767 | 0 |
char | 2 | 0~65535 | '\u0000' |
int | 4 | -2147483648~2147483647 | 0 |
long | 8 | -2^63~2^63-1 | 0L或0l |
float | 4 | 3.402823e38~1.401298e-45 | 0.0F或0.0f |
double | 8 | 1.797693e308~4.9000000e-324 | 0.0D或0.0d |
boolean | 1 | false 或 true | false |
在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();
}
}
参考博文: