https://www.cnblogs.com/xujishou/p/7491932.h
为什么会出现这个问题呢,就这是java和其它计算机语言都会出现的问题,下面我们分析一下为什么会出现这个问题:
float和double类型主要是为了科学计算和工程计算而设计的。他们执行二进制浮点运算,这是为了在广泛的数字范围上提供较为精确的快速近似计算而精心设计的。然而,它们并没有提供完全精确的结果,所以我们不应该用于精确计算的场合。float和double类型尤其不适合用于货币运算,因为要让一个float或double精确的表示0.1或者10的任何其他负数次方值是不可能的(其实道理很简单,十进制系统中能不能准确表示出1/3呢?同样二进制系统也无法准确表示1/10)。
浮点运算很少是精确的,只要是超过精度能表示的范围就会产生误差。往往产生误差不是因为数的大小,而是因为数的精度。因此,产生的结果接近但不等于想要的结果。尤其在使用 float 和 double 作精确运算的时候要特别小心。
现在我们就详细剖析一下浮点型运算为什么会造成精度丢失?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
|
解决方法
使用BigDecmal,而且需要在构造参数使用String类型。
在《Effective Java》这本书中就给出了一个解决方法。该书中也指出,float和double只能用来做科学计算或者是工程计算,在商业计算等精确计算中,我们要用java.math.BigDecimal。
BigDecimal类有4个构造方法,我们只关心对我们解决浮点型数据进行精确计算有用的方法,即
BigDecimal(double value) // 将double型数据转换成BigDecimal型数据
思路很简单,我们先通过BigDecimal(double value)方法,将double型数据转换成BigDecimal数据,然后就可以正常进行精确计算了。等计算完毕后,我们可以对结果做一些处理,比如 对除不尽的结果可以进行四舍五入。最后,再把结果由BigDecimal型数据转换回double型数据。
这个思路很正确,但是如果你仔细看看API里关于BigDecimal的详细说明,你就会知道,如果需要精确计算,我们不能直接用double,而非要用 String来构造BigDecimal不可!所以,我们又开始关心BigDecimal类的另一个方法,即能够帮助我们正确完成精确计算的 BigDecimal(String value)方法。
// BigDecimal(String value)能够将String型数据转换成BigDecimal型数据
那么问题来了,想像一下吧,如果我们要做一个浮点型数据的加法运算,需要先将两个浮点数转为String型数据,然后用 BigDecimal(String value)构造成BigDecimal,之后要在其中一个上调用add方法,传入另一个作为参数,然后把运算的结果(BigDecimal)再转换为浮 点数。如果每次做浮点型数据的计算都要如此,你能够忍受这么烦琐的过程吗?至少我不能。所以最好的办法,就是写一个类,在类中完成这些繁琐的转换过程。这 样,在我们需要进行浮点型数据计算的时候,只要调用这个类就可以了。网上已经有高手为我们提供了一个工具类Arith来完成这些转换操作。它提供以下静态 方法,可以完成浮点型数据的加减乘除运算和对其结果进行四舍五入的操作:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 |
|
附上Arith的源代码,大家只要把它编译保存好,要进行浮点数计算的时候,在你的源程序中导入Arith类就可以使用以上静态方法来进行浮点数的精确计算了