阅读建议:这块内容前后多少有点联系,建议通篇阅读一下。
JAVA中的float和double的区别
深入层次理解单精度浮点数(float)、多精度浮点数(double)的区别,精度和范围和什么有关系
浮点数的表示:
在计算机系统中,浮点数采用 符号+阶码+尾数 进行表示。
float: 单精度浮点数 占4bytes 有效数字8位 最后一位会四舍五入 声明必须显示 如:0.3f |
double: 双精度浮点数 占8bytes 有效数字17位 java中小数都默认是double类型 |
注意:不包括小数点 (float 有效数字8位 )、(double 有效数字17位 )
//不包括小数点 float 8位 double 17位
//第7位将产生四舍五入(5及5以下的都将舍去)
float myFloat = 3.1415926566f;//3.1415927(有效数字8位 )
//多余的直接舍去,好像也是4舍五入,好像也不对,反正就是精度不对了
double myDouble = 0.69696969699696969;//0.6969696969969696(有效数字17位 )
System.out.println(myFloat + "\n" + myDouble);
//注意一下这个输出,是在你原有float结果上(8位有效数字)在填到17位数,填充的数字我不知道
System.out.println((double)myFloat);//3.1415927410125732
//根据下面上面的结论貌似不太说的过去
double v211 = 0.12345678901234567;
double v212 = 0.123456789012345678;
double v213 = 0.123456789012345679;
System.out.println(v211);//0.12345678901234566
System.out.println(v212);//0.12345678901234568
System.out.println(v213);//0.12345678901234568
//最终发现如下,有效17位如果后面还有1位,此时一般会输出第18位
double a = 0.12345678901234560;
double b = 0.12345678901234561;
double c = 0.12345678901234566;
double d = 0.12345678901234567;
double e = 0.12345678901234568;
double f = 0.12345678901234569;
System.out.println(a);//0.1234567890123456//特殊 但有规律,0默认不展示
double d2 = 0.1234567890;
System.out.println(d2);//0.123456789
System.out.println(b);//0.12345678901234561
System.out.println(c);//0.12345678901234566
System.out.println(d);//0.12345678901234566//特殊
System.out.println(e);//0.12345678901234568
System.out.println(f);//0.12345678901234569
//有效17位如果后面还有2位 结果如下:
double a1 = 0.123456789012345670;
double b1 = 0.123456789012345619;
double c1 = 0.123456789012345668;
double d1 = 0.123456789012345677;
double e1 = 0.123456789012345686;
double f1 = 0.123456789012345695;
System.out.println(a1);//0.12345678901234566//特殊
System.out.println(b1);//0.12345678901234562
System.out.println(c1);//0.12345678901234566
System.out.println(d1);//0.12345678901234568
System.out.println(e1);//0.12345678901234569
System.out.println(f1);//0.12345678901234569
1)float型 内存分配4个字节,占32位,范围从10^-38到10^38 和 -10^38到-10^-38
例float x=123.456f,y=2e20f;
注意float型定义的数据末尾必须有"f"或"F",为了和double区别 |
2)double型 内存分配8个字节,占64位,范围从10^-308到10^308 和 -10^-308到-10^-308
例double x=1234567.98,y=8980.09d; 末尾可以有"d"也可以不写
3)在程序中处理速度不同
一般来说,CPU处理单精度浮点数的速度比处理双精度浮点数快.
特别需要注意的是两个浮点数的算术运算
首先提纲挈领下:
1、浮点数进行算术运算不一定都会出现问题
2、浮点数进行算术运算一般采用BigDecimal类
3、超过对应类型的范围后也有误差,所以一开始就要选对数据类型
public static void main(String args[]) {
System.out.println(0.05 + 0.01);//0.060000000000000005
System.out.println(1.0 - 0.42);//0.5800000000000001
System.out.println(4.015 * 100);//401.49999999999994
System.out.println(123.3 / 100);//1.2329999999999999
}
分析上述产生原因:务必用心阅读
这个图介绍的很详细了,我这里大致总结一下就是:
因为计算机只识别二进制(源程序翻译成二进制的机器码后才能被计算机识别)
所以在这转换过程中,发生了精度的丢失。(在这个转换的过程中,浮点数参与了计算,那么转换的过程就会变得不可预 知,并且变得不可逆。)
在转换过程中不排除能够准确转换的(而至于为什么有些浮点计算会得到准确的结果,应该也是碰巧那个计算的二进制与 十进制之间能够准确转换。)
可以正确输出单个浮点型数据(而当输出单个浮点型数据的时候,可以正确输出,如:double d = 2.4; System.out.println(d);//2.4)
浮点数适合进行科学计算不适合精确计算(浮点数并不适合用于精确计算,而适合进行科学计算。)
float和double只能用来做科学计算或者是工程计算,在商业计算中我们要用java.math.BigDecimal。使用BigDecimal并且一定要用String来够造。
Java浮点数float和double精确计算的精度误差问题总结
网址
float和double只能用来做科学计算或者是工程计算,在商业计算中我们要用java.math.BigDecimal。使用BigDecimal并且一定要用String来够造。
BigDecimal类
常用方法
待填充
保留2位或自定义位数并返回BigDecimal
保留2位或自定义位数并返回String
Java 浮点数大小比较
先放方法,在介绍分析:
切记使用使用BigDecimal 参数为 String 的构造方法才能保证compareTo()的结果是精确的。(这个是最保险的,除非你能确认你的小数位数在对应类型范围内)
为了使用方便我这里直接提取个方法:
/**
* 如果可以确保数值不会超过double的精度范围,比较两个浮点型大小
* @param a
* @param b
* @return a>b=1 a<b=-1 a=b=0
*/
public static int doubleCompare(double a, double b) {
BigDecimal bd1 = BigDecimal.valueOf(a);
BigDecimal bd2 = BigDecimal.valueOf(b);
return bd1.compareTo(bd2);
}
//todo 我们知道浮点数运算会造成精度丢失,所以最好用BigDecimal类进行数据计算(直接搜这句话)
//下面这个挺有意思,我放文章末尾了,着重看下
float v1 = 0.99f;
System.out.println(BigDecimal.valueOf(0.99f)); // 0.9900000095367432
System.out.println(BigDecimal.valueOf(v1)); // 0.9900000095367432
System.out.println(new BigDecimal(v1)); //0.9900000095367431640625
//正确做法
System.out.println(new BigDecimal(String.valueOf(v1))); //0.99
如果说你的浮点数进行计算后,理论上应该相等,但由于精度问题你比较百分之99%可能都不会相等。
所以可以通过定义误差范围解决,具体如下
我们知道浮点数运算会造成精度丢失,所以最好用BigDecimal类进行数据计算
下面内容随便看看,正儿八经业务中不会那么比较,基本采用的BigDecimal
在范围内下面说法有一定参考价值,但是不建议使用如下:
如果是 double类型,可以直接通过 ==
来比较
如果是 Double类型,不可以直接通过 ==
来比较,需要使用 compareTo
方法
不建议原因案例,比如超过范围后就会造成bug
double v12 = 1.12345678901234567;
double v13 = 1.1234567890123456789d;//只有17位有效,等价于v12的结果
System.out.println((v12 == v13));//true
Double v3 = 1.12345678901234567d;//不写d编译报错可采取下面
Double v31 = Double.valueOf(1.12345678901234567);
Double v4 = 1.1234567890123456789d;
System.out.println((v3.compareTo(v31)));//0
System.out.println((v3.compareTo(v4)));//0
System.out.println((v31.compareTo(v4)));//0
下面是在对应数据类型范围内案例 ,不难得出结论,不做过多概括
public static void main(String args[]) {
double v1 = 1234567;
double v2 = 1234567d;
double v11 = 1234567f;
double v12 = 1234567.1;
double v13 = 1234567.1d;
double v14 = 1234567.1f;
double v15 = 1234567.1f;
Double v3 = 1234567d;//不写d编译报错可采取下面
Double v31 = Double.valueOf(1234567);
Double v4 = 1234567d;
System.out.println((v1 == v2));//true
System.out.println((v11 == v2));//true 整数是ok的
System.out.println((v12 == v13));//true
System.out.println((v12 == v14));//false
System.out.println((v13 == v14));//false
System.out.println((v15 == v14));//true
//上面不能直接实用 compareTo 毕竟 人家是两个对像才可以用
System.out.println((v3 == v4));//false
System.out.println((v3.compareTo(v4)));//0
System.out.println((v31.compareTo(v4)));//0
}
注意下面 double 跟 float 还有点小不同
double v = 0.99d;
System.out.println(BigDecimal.valueOf(0.99)); // 0.99
System.out.println(BigDecimal.valueOf(v)); // 0.99
System.out.println(new BigDecimal(v)); //0.9899999999999999911182158029987476766109466552734375
//正确做法
System.out.println(new BigDecimal(String.valueOf(v))); //0.99
double v2 = 0.123456789012345678d;
System.out.println(v2);//0.12345678901234568
System.out.println(new BigDecimal(String.valueOf(v2))); //0.12345678901234568
System.out.println("----------------------------");
float v1 = 0.99f;
System.out.println(BigDecimal.valueOf(0.99f)); // 0.9900000095367432
System.out.println(BigDecimal.valueOf(v1)); // 0.9900000095367432
System.out.println(new BigDecimal(v1)); //0.9900000095367431640625
//正确做法
System.out.println(new BigDecimal(String.valueOf(v1))); //0.99
System.out.println("+++++++++++++++++++++++++++++++++++++++");
double v25 = 0.123456789012345678d;
double v24 = 0.123456789012345678d;
double v21 = 0.12345678901234567d;
double v22 = 0.1234567890123456d;
double v23 = 0.123456789012345d;
System.out.println(v25);//0.12345678901234568
System.out.println(new BigDecimal(String.valueOf(v25)));//0.12345678901234568
System.out.println(v24);//0.12345678901234568
System.out.println(v21);//0.12345678901234566//todo why
System.out.println(v22);//0.1234567890123456
System.out.println(v23);//0.123456789012345
System.out.println(new BigDecimal(String.valueOf(v23)));//0.123456789012345
System.out.println("-----------------------------------");
float v251f = 0.12345678901f;
float v25f = 0.1234567890f;
float v24f = 0.123456789f;
float v21f = 0.12345678f;
float v22f = 0.1234567f;
float v23f = 0.123456f;
System.out.println(v251f);//0.12345679
System.out.println(v25f);//0.12345679
System.out.println(new BigDecimal(String.valueOf(v25f)));//0.12345679
System.out.println(v24f);//0.12345679
System.out.println(v21f);//0.12345678
System.out.println(v22f);//0.1234567
System.out.println(v23f);//0.123456
System.out.println(new BigDecimal(String.valueOf(v23f)));//0.123456
}
float转成double,它会在float那个精度规则基础上在扩张到double范围有效数字