标题

  • JAVA中的float和double的区别
  • 特别需要注意的是两个浮点数的算术运算
  • BigDecimal类
  • 常用方法
  • Java 浮点数大小比较


阅读建议:这块内容前后多少有点联系,建议通篇阅读一下。

JAVA中的float和double的区别

深入层次理解单精度浮点数(float)、多精度浮点数(double)的区别,精度和范围和什么有关系

浮点数的表示:

在计算机系统中,浮点数采用 符号+阶码+尾数 进行表示。

Java里double与float的区别 java float和double的区别_浮点数计算精度丢失问题


Java里double与float的区别 java float和double的区别_浮点数_02

Java里double与float的区别 java float和double的区别_有效数字_03


Java里double与float的区别 java float和double的区别_浮点数_04

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处理单精度浮点数的速度比处理双精度浮点数快.

Java里double与float的区别 java float和double的区别_Java 浮点数大小比较_05

特别需要注意的是两个浮点数的算术运算

首先提纲挈领下:

1、浮点数进行算术运算不一定都会出现问题

2、浮点数进行算术运算一般采用BigDecimal类

3、超过对应类型的范围后也有误差,所以一开始就要选对数据类型

Java里double与float的区别 java float和double的区别_Java 浮点数大小比较_06

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
    }

分析上述产生原因:务必用心阅读

Java里double与float的区别 java float和double的区别_浮点数计算精度丢失问题_07


这个图介绍的很详细了,我这里大致总结一下就是:

因为计算机只识别二进制(源程序翻译成二进制的机器码后才能被计算机识别)

所以在这转换过程中,发生了精度的丢失。(在这个转换的过程中,浮点数参与了计算,那么转换的过程就会变得不可预 知,并且变得不可逆。)

在转换过程中不排除能够准确转换的(而至于为什么有些浮点计算会得到准确的结果,应该也是碰巧那个计算的二进制与 十进制之间能够准确转换。)

可以正确输出单个浮点型数据(而当输出单个浮点型数据的时候,可以正确输出,如: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里double与float的区别 java float和double的区别_System_08

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

Java里double与float的区别 java float和double的区别_Java 浮点数大小比较_09

Java里double与float的区别 java float和double的区别_有效数字_10


Java里double与float的区别 java float和double的区别_Java 浮点数大小比较_11


如果说你的浮点数进行计算后,理论上应该相等,但由于精度问题你比较百分之99%可能都不会相等。

Java里double与float的区别 java float和double的区别_Java 浮点数大小比较_12


所以可以通过定义误差范围解决,具体如下

Java里double与float的区别 java float和double的区别_浮点数计算精度丢失问题_13


我们知道浮点数运算会造成精度丢失,所以最好用BigDecimal类进行数据计算

Java里double与float的区别 java float和double的区别_有效数字_14

Java里double与float的区别 java float和double的区别_Java 浮点数大小比较_15

下面内容随便看看,正儿八经业务中不会那么比较,基本采用的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范围有效数字

Java里double与float的区别 java float和double的区别_有效数字_16