Java(其实是计算机系统的通病,而不单单是Java的问题,C、C++等任何语言都有这个问题)关于小数的运算结果,不正确不精确,原因剖析,及解决办法
2017-11-03 11:39
1471 查看
Java(其实是计算机系统的通病,而不单单是Java的问题)关于小数的运算结果,不正确不精确,原因剖析,及解决办法
这么神奇?
试一把。还真是:
从输出结果上看,出在运算上,而不是出在存储上。如果问题出在存储上,0.07这个应该也不能正常显示。那么怎么解决呢?
那既然是计算导致的问题,存储是没有问题,为什么这篇文章却说,2.4这个数字,计算机没办法用二进制精确表示呢??
有些人跟我有相同的疑问:
这么看来,计算机的确不能精确的表示小数:
那为什么double a=0.1这个变量,输出出来的时候,显示的不是0.0999908447265625的,而是精确的0.1?
答案是:这是Java给你制造的假象。。
怎么处理,就可以精确了呢?答案是:BigDecimal。
步骤如下:
1)将double类型转换成string类型
2)将string类型转换成BigDecimal对象
3)使用BigDecimal对象的方法如add等进行加减乘除运算。
疑问:既然0.06存入计算机中就不是精确的0.06如0.0599999,那么转成string不就是也不是精确的0.05999999了吗,为什么转出来却没有问题?
如下我做了测试,原因还是假象,是因为Double.toString并不是给你显示的精确的0.599999,而是给你一个比较规整的0.06,就是这么坑爹,处处是假象。
但是是不是用了bigDecimal就一定没问题了呢?
不是的,比如,如下例子:
我现实中,要将下图中的两个很长的小数相加,但是只有方法2做到了精确的相加,其他的Java都背地里做了手脚给外界现实一个假象。
方法1和最后的方法问题出在哪儿?
可以下debug就很清楚了,在定义Double类型的变量时,就已经是假象了。
并且BigDecimal.valueOf()只能处理double和long型的数据。
总结:只要记住如下3点就行。
1无法精确存储小数。计算机无法100%精确地存储小数,无法,never,肯定会有误差。
2假象。如果你存0.0.6到计算机输出的的结果还是0.06,那么,你看到的就是Java(其实是Java的jdk封装的类,如system.out.println、Double.toString等)给你展现的假象,他偷偷的将存储在计算机里的真实结果给你偷偷地处理了。
3只要BigDecimal和String,绝不要Double等任何其他数据类型的参与。如果想要精确计算,只需要BigDecimal和String两个类就行了,不要Double等其他任何数据类型的参与,否则必不精确。
这么神奇?
试一把。还真是:
从输出结果上看,出在运算上,而不是出在存储上。如果问题出在存储上,0.07这个应该也不能正常显示。那么怎么解决呢?
那既然是计算导致的问题,存储是没有问题,为什么这篇文章却说,2.4这个数字,计算机没办法用二进制精确表示呢??
有些人跟我有相同的疑问:
这么看来,计算机的确不能精确的表示小数:
当我们 double a = 0.1的时候, 0.1(十进制) = 0.0001100110011001(二进制),实际是表示为浮点数的,这里就略过了。计算机里也只能保存到0.0001100110011001(二进制)的浮点形式。 而 0.0001100110011001(二进制) = 0.0999908447265625(十进制)。也就是说内存中存放的数只能表示到0.0999908447265625。 |
答案是:这是Java给你制造的假象。。
怎么处理,就可以精确了呢?答案是:BigDecimal。
步骤如下:
1)将double类型转换成string类型
2)将string类型转换成BigDecimal对象
3)使用BigDecimal对象的方法如add等进行加减乘除运算。
疑问:既然0.06存入计算机中就不是精确的0.06如0.0599999,那么转成string不就是也不是精确的0.05999999了吗,为什么转出来却没有问题?
如下我做了测试,原因还是假象,是因为Double.toString并不是给你显示的精确的0.599999,而是给你一个比较规整的0.06,就是这么坑爹,处处是假象。
但是是不是用了bigDecimal就一定没问题了呢?
不是的,比如,如下例子:
我现实中,要将下图中的两个很长的小数相加,但是只有方法2做到了精确的相加,其他的Java都背地里做了手脚给外界现实一个假象。
方法1和最后的方法问题出在哪儿?
可以下debug就很清楚了,在定义Double类型的变量时,就已经是假象了。
并且BigDecimal.valueOf()只能处理double和long型的数据。
总结:只要记住如下3点就行。
1无法精确存储小数。计算机无法100%精确地存储小数,无法,never,肯定会有误差。
2假象。如果你存0.0.6到计算机输出的的结果还是0.06,那么,你看到的就是Java(其实是Java的jdk封装的类,如system.out.println、Double.toString等)给你展现的假象,他偷偷的将存储在计算机里的真实结果给你偷偷地处理了。
3只要BigDecimal和String,绝不要Double等任何其他数据类型的参与。如果想要精确计算,只需要BigDecimal和String两个类就行了,不要Double等其他任何数据类型的参与,否则必不精确。
相关文章推荐
- JavaScript对浮点小数运算结果不精确bug的解决办法
- android编程中遇到的关于调试百度地图时出现的 java.lang.UnsatisfiedLinkError: initClass 问题的原因及解决办法
- 关于A+B+C问题4种语言的解决办法,Java、C语言、C++、Python
- 区别对待 【找到问题发生的原因】 以及 【关于这个问题的 「正确可行」 的解决方法】
- 关于android编程遇到java.lang.OutOfMemoryError: bitmap size exceeds VM budget此类问题的原因及解决办法
- 举例说明关于android编程中遇到的java.lang.ClassCastException: android.app.Application问题的原因及解决办法
- 举例说明Android开发中遇到的 java.lang.ClassCastException: java.lang.String这个问题的原因及其解决办法
- “由于应用程序的配置不正确,应用程序未能启动,重新安装应用程序可能会纠正这个问题”的解决办法
- 关于Linux系统增加SCSI硬盘不识别的问题及解决办法
- 关于Window 7 系统磁盘无法显示的问题的解决办法
- 关于系统时间被改问题的解决办法
- android编程中遇到的关于java.io.FileNotFoundException: /mnt/sdcard/update.zip (Permission denied)错误的原因及解决办法
- android编程过程中遇到的关于Canvas: trying to use a recycled bitmap android.graphics.Bitmap问题的原因及解决办法
- VS2008调试程序时出现“由于应用程序的配置不正确,应用程序未能启动,重新安装应用程序可能会纠正这个问题”的解决办法
- 关于在java中连接MS SQL Server 2005 JDBC的问题及解决办法
- 关于本站提供的Windows 7下硬盘安装xp提示找不到路径问题的原因及解决办法
- 关于ubuntu系统启动时显示.dmrc权限不正确的问题的解决
- Discuz!NT 3.5.2 关于不能在64位系统部署问题彻底解决办法
- 在很多论坛上看到了有人抱怨Flash CS5中,代码提示(Code hint)有时不显示的问题,这个问题可能有很多原因,我整理了几个解决办法,有可能可以帮助到你~
- devenv.exe - 系统错误无法启动此程序,因为计算机中丢失 MSVCR100.dll。尝试重新安装该程序以解决此问题。【解决办法】