JAVA基础-绝对慎用的变量-double,float
对于刚接触java的童鞋俩说,变量应该是最先了解的,因为要写好代码,最基础的加减乘除是必须要使用的,这些元素就像学英语的is am are一样,即使英语考试就得了20分,日久生情,也能深刻了解其中的含义,然而这些……你真的会用了吗?
数据类型介绍
java中常用的用于表示数据的类型,int,long,float,double换成人话就是,小一点的整数用int,大一点的用long,小(短)一点的小数用float,大(长)一点的小数用double,这是大部分初学者对这4个类型的理解,当然只要有表示数据的方法,接下来的加减乘除就可以链接运算符号直接计算了。这里对4个类型进行一个详细说明
- int ,4个字节,32位,存储范围-2147483648 (-2的31次方) ~ 2147483647 (2的31次方-1);
- long ,8个字节,64位,存储范围-9223372036854775808 (-2的63次方) ~ 9223372036854775807 (2的63次方-1);
- float ,4个字节,32位,存储范围1.4E-45 (2的-149次方) ~ 3.4028235E38 (2的128次方-1);
- double ,8个字节,64位,存储范围4.9E-324 (2的-1074次方) 1.7976931348623157E308 (2的1024次方-1);
应用场景
根据上面的说明,int适用于比较小一些的整数,比如我们常见的for循环,int i=0;i<=10;i++,long用于比较大的整数,比如对应数据库Bigint这种比较大比较长的ID,float和double意思差不多,就是对应长短的小数位,那么按照大多数人的想法,正常的加减乘除运算,我们有这4个变量,足够了。
表示原理
这么简单的问题,为啥还要讲原理呢,因为讲完原理以后,你就会深刻的理解到,原来只用这几个变量,对有多大的坑。在讲原理之前,先抛出一个问题。如何用10进制表示三分之一这个数………………
下面为了简单说明一下,我们用正数做一个说明,其实负数也简单,就是有专门表示符号的位数。
1、计算机存储—整数
我们知道,计算机他只认识0,1,那么假设我们要表示10进制的8,转换为2进制为1000,10进制的10,转为2进制为1010,其实很简单。总结下算法就是对2取模。
2、计算机存储—小数
小数对2取馍基本上就取不出来了,那么计算机采用的方法就是, 乘2,然后取整数部分,我们拿0.125举例,0.1252=0.25,取整数部分0,0.252=0.5,取整数部分0,0.5*2=1,取整数部分1,那么结果就是001。当然0.125这个数据比较规矩,我们再来一个不规矩的
0.9
0.9X2=1.8,取整1;
0.8X2=1.6,取整1;
0.6X2=1.2,取整1;
0.2X2=0.4,取整0;
0.4X2=0.8,取整0;
0.8X2=1.6,取整1;
0.6X2=1.2,取整1;从这里开始,应该产生规律了,下面将无限循环,这和10进制表示三分之一,是一个道理
总结
根据原理的部分演练,也就是说,即使你只是定义了一个double 0.9,那么这个0.9也只是无限接近于0.9,他并不是真正的0.9,那么话不多说,上代码:
double a = 0.9d;
double b = 0.9d;
System.out.println(a);
System.out.println(a==b);
double c = 0.6d;
double d = 0.3d;
System.out.println(c+d);
System.out.println(a==(c+d));
代码运行结果
0.9
true
0.8999999999999999
false
第一个结果为为0.9,我们感觉并不意外,a等于b 因为都是0.9我们感觉也并不意外,而c+d并没有产生我们预期的结果,而是0.899999999999999999,当然在输出这个结果后,a也就不可能等于c+d了,这根本原因就是在于,因为我们定义的数字,在计算机内部,是无法精确存储的,而我们仅仅是做了一个加单的0.3+0.6就已经出现了位数的变化,那么当我们小数位数更多的时候,这个偏差是不可原谅的。
正确做法,使用bigdecimal
BigDecimal c1 = new BigDecimal("0.6");
BigDecimal d1 = new BigDecimal("0.3");
System.out.println(c1.add(d1).doubleValue() == a);
这个结果输出是true,是因为decimal尽可能的保留运算的精度,当然他付出的代价其实也是更大的。
最后给刚刚学习java的新童鞋一个建议,直接忘掉float,double吧,这俩参数在高精度计算的时候,精度丢失会极为严重,当然其实他存在的场景不光是java,例如Mysql,因为计算机存储原理都是一样的,所以也仍然是不推荐的。
不要觉得BigDecimal比较长,不好写。。。精度计算是离不开他的。。对于参加工作的有条件的项目组,甚至可以建议,禁用float,double