float与double精度丢失问题

简介: float与double精度丢失问题


  1. java中int,float,long,double取值范围
public class TestOutOfBound {
        public static void main(String[] args) {
            System.out.println(Integer.MAX_VALUE-(-Integer.MAX_VALUE)); //内存溢出
            System.out.println(Integer.MAX_VALUE); //2的31次方-1,10个数位,正的20亿左右,用在钱上面不一定够
            System.out.println(Integer.MIN_VALUE); //负的2的31次方
            System.out.println(Long.MAX_VALUE); //2的64次方-1,19个数位,很大了,可放心用在钱上面
            System.out.println(Long.MIN_VALUE); //负的2的64次方
            System.out.println(Float.MAX_VALUE); //2的128次方-1,38个数位,比long多了一倍,这个主要用来做简单数学精确运算使用
            System.out.println(Float.MIN_VALUE); //2的-149次方
            System.out.println(Double.MAX_VALUE); //2的1024次方-1,308个数位,是float数位的10倍,主要用来做复杂运算和天文运算
            System.out.println(Double.MIN_VALUE); //2的-1074次方
        }
}
  1. float与double精度丢失问题
    举例:double result = 1.0 - 0.9
    结果:0.09999999999999998
    原因
    float和double类型主要是为了科学计算和工程计算而设计的。他们执行二进制浮点运算,这是为了在广泛的数字范围上提供较为精确的快速近似计算而精心设计的。然而,它们并没有提供完全精确的结果,所以我们不应该用于精确计算的场合。float和double类型尤其不适合用于货币运算因为要让一个float或double精确的表示0.1或者10的任何其他负数次方值是不可能的(其实道理很简单,十进制系统中能不能准确表示出1/3呢?同样二进制系统也无法准确表示1/10
    浮点运算很少是精确的,只要是超过精度能表示的范围就会产生误差。往往产生误差不是因为数的大小,而是因为数的精度。因此,产生的结果接近但不等于想要的结果。尤其在使用 float 和 double 作精确运算的时候要特别小心。

解决方法一:

int resultInt = 10 - 9;
double result = (double) resultInt / 100;//最终时候自己控制小数点

解决方法二:

使用BigDecmal,而且构造参数使用String类型

《Effective Java》书中指出,float和double只能用来做科学计算或者是工程计算,在商业计算等精确计算中,我们要用java.math.BigDecimal

而且不能直接用double,而非要用 String来构造BigDecimal不可!BigDecimal(String value)

public static double add(double v1,double v2)
public static double sub(double v1,double v2)
public static double mul(double v1,double v2)
public static double div(double v1,double v2)
public static double div(double v1,double v2,int scale)
public static double round(double v,int scale)

为什么非要用 String来构造BigDecimal

如果不用BigDecimal做除法时如果出现除不尽(循环小数)的情况,会抛异常

Exception in thread "main" java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.
at java.math.BigDecimal.divide(BigDecimal.java:1693) 

这是BigDecimal进行除法运算时的坑

参考:为什么浮点型运算会造成精度丢失?

首先我们要搞清楚下面两个问题

  1. 十进制整数如何转化为二进制数
//11表示成二进制数
11/2=5 余 1
5/2=2 余 1
2/2=1 余 0
1/2=0 余 1
0结束 11二进制表示为(从下往上):1011
  1. 十进制小数如何转化为二进制数
//整数转二进制,除以后的结果为0了就结束了,所有的整数除以2一定能够最终得到0。所以整数永远可以用二进制精确表示(不会无限循环下去)但小数就不一定了
//0.9表示成二进制数
//算法是乘以2直到没有了小数为止 
0.9*2=1.8 取整数部分 1
0.8(1.8的小数部分)*2=1.6 取整数部分 1
0.6*2=1.2 取整数部分 1
0.2*2=0.4 取整数部分 0
0.4*2=0.8 取整数部分 0
0.8*2=1.6 取整数部分 1
0.6*2=1.2 取整数部分 0
......... 0.9二进制表示为(从上往下): 1100100100100......
//注意:上面的计算过程循环了,也就是说*2永远不可能消灭小数部分,这样算法将无限下去。很显然,小数的二进制表示有时是不可能精确的 。其实道理很简单,十进制系统中能不能准确表示出1/3呢?同样二进制系统也无法准确表示1/10。这也就解释了为什么浮点型减法出现了"减不尽"的精度丢失问题。


相关文章
|
6月前
|
存储 Java
百度搜索:蓝易云【Java语言之float、double内存存储方式】
由于使用IEEE 754标准进行存储,float和double类型可以表示非常大或非常小的浮点数,并且具有一定的精度。然而,由于浮点数的特性,它们在进行精确计算时可能会存在舍入误差。在编写Java程序时,需要注意使
97 0
|
1月前
|
存储 C语言
使用 sizeof 操作符计算int, float, double 和 char四种变量字节大小
【10月更文挑战第13天】使用 sizeof 操作符计算int, float, double 和 char四种变量字节大小。
77 1
|
4月前
|
存储 编译器 C++
C++从遗忘到入门问题之float、double 和 long double 之间的主要区别是什么
C++从遗忘到入门问题之float、double 和 long double 之间的主要区别是什么
|
4月前
|
存储 SQL 数据库
MySQL设计规约问题之为何推荐用DECIMAL代替FLOAT和DOUBLE来存储精确浮点数
MySQL设计规约问题之为何推荐用DECIMAL代替FLOAT和DOUBLE来存储精确浮点数
|
6月前
|
存储 C语言
计算 int, float, double 和 char 字节大小
计算 int, float, double 和 char 字节大小。
79 3
|
存储 C语言
C 语言实例 - 计算 int, float, double 和 char 字节大小
C 语言实例 - 计算 int, float, double 和 char 字节大小。
93 1
|
6月前
|
C#
C# 字节数组与INT16,float,double之间相互转换,字符数组与字符串相互转换,
C# 字节数组与INT16,float,double之间相互转换,字符数组与字符串相互转换,
183 2
|
存储 C语言
计算 int, float, double 和 char 字节大小
C 语言实例 - 计算 int, float, double 和 char 字节大小。
94 1
float和double的区别
float和double的区别
100 0
C/C++ 关于double和float两种类型的区别
C/C++ 关于double和float两种类型的区别
C/C++ 关于double和float两种类型的区别