http://edu.eoe.cn/   在线课堂

昨天看到一篇帖子说了几个很明显的简单的浮点的运算,计算机都会算错。
我引过来给大家看看:‘
运行代码:

        System.out.println(0.05 + 0.01);System.out.println(1.0 - 0.42);System.out.println(4.015 * 100);System.out.println(123.3 / 100);

大家可以自己新建一个工程来试试,结果如下:

0.060000000000000005
0.5800000000000001
401.49999999999994
1.2329999999999999

这就很神奇了,0.05+0.01很明显是0.06嘛,但是为什么会变成0.060000000000000005?
是不是计算器太弱智?真是计算机就不靠谱了?

当然不是的。主要是因为java中的简单类型并不适用于对浮点的精确计算。不光是JAVA ,其它语言也存在同样的问题。
虽然现在CPU都支持浮点的运算了,但是CPU在处理的时候,也是先把浮点数(float , double)转成整数再转成二进制,然后进行操作,如果有取余,会有不同的取余方式。
再加上运算完成后,再多二进制转成上层的浮点,又会有一些取舍。就造成了呈现出来时的简单明显的错误 。

所以说,一般float和double用来做科学计算或者是工程计算,在一般对精度要求较高的地方(如商业),我们会用到BCD码或者是java.math.BigDecimal。

BSD码(Binary-Coded Decimal),称BCD码或二-十进制代码,亦称二进码十进数。是一种二进制的数字编码形式,用二进制编码的十进制代码。
大家对这个有兴趣的可以深入研究一下,今天我们主要讲的是BigDecimal类。因为我们在做项目的时候,尤其是对商业项目时,我们不可能还去搞个什么BSD码,可以直接利用BigDecimal类来完成我们的需求。

BigDecimal 是Java提供的不可变的、任意精度的有符号十进制数。如果想看更多关于BigDecimal的介绍,大家可以自行去查看JDK的文档。

BigDecimal提供了一系列的构造函数,主用于将double , string等转化成BigDecimal对象。

BigDecimal(double val) 将 double 转换为 BigDecimal,后者是 double 的二进制浮点值准确的十进制表示形式。
BigDecimal(String val) 将 BigDecimal 的字符串表示形式转换为 BigDecimal。

习惯上我们在使用浮点数的时候都是直接定义的double , float数据类型,在定义上是没有问题,但是如果我们直接调用BigDecimal(double val) 方法来转化,那我们可得先注意一下JDK文档中关于这个构造的详细说明了:

直接上中文了,英文好的,可以自己去看原版:

注:
此构造方法的结果有一定的不可预知性。有人可能认为在 Java 中写入 new BigDecimal(0.1) 所创建的 BigDecimal 正好等于 0.1(非标度值 1,其标度为 1),但是它实际上等于 0.1000000000000000055511151231257827021181583404541015625。这是因为 0.1 无法准确地表示为 double(或者说对于该情况,不能表示为任何有限长度的二进制小数)。这样,传入 到构造方法的值不会正好等于 0.1(虽然表面上等于该值)。

BigDecimal(double val) 这个方法是不可预知的,所以我们推荐使用BigDecimal(String val) 。
String的构造函数就是可预知的,new BigDecimal(“.1”)如同期望的那样精确的等于.1。

接下来我们对 0.05+0.01重新修改一下:

BigDecimal bd1 = new BigDecimal(Double.toString(0.05));BigDecimal bd2 = new BigDecimal(Double.toString(0.01));System.out.println(bd1.add( bd2));

我们再来看看运行的结果:

0.06

这下就是我们想要的结果了,完成了高精度的一个运算了。

注意:
 现在我们已经知道怎么样来解决这个问题了,原则上是推荐使用BigDecimal(String val) 构造方法。
我建议,在商业的应用中,涉及到money的浮点运算全都定义成String ,在数据库中保存也是String ,在需要使用到这个money来作运算的时候,我们再把String转化成BigDecimal来完成高精度的运算。
        
试想一下,如果我们要做一个加法运算,需要先将两个浮点数转为String,然后够造成BigDecimal,在其中一个上调用add方法,传入另一个作为参数,然后把运算的结果(BigDecimal)再转换为浮点数。你能够忍受这么烦琐的过程吗?

SO, 网上找了一个比较好的一个工具类,封闭了简单的操作。可以参考一下:

/*** * 由于Java的简单类型不能够精确的对浮点数进行运算,这个工具类提供精* 确的浮点数运算,包括加减乘除和四舍五入。* **/
public class Arith{//默认除法运算精度private static final int DEF_SCALE = 10;//这个类不能实例化private Arith(){}/*** 提供精确的加法运算。* @param v1 被加数* @param v2 加数* @return 两个参数的和*/public static double add(double v1,double v2){BigDecimal b1 = new BigDecimal(Double.toString(v1));BigDecimal b2 = new BigDecimal(Double.toString(v2));return b1.add(b2).doubleValue();}/*** 提供精确的减法运算。* @param v1 被减数* @param v2 减数* @return 两个参数的差*/public static double sub(double v1,double v2){BigDecimal b1 = new BigDecimal(Double.toString(v1));BigDecimal b2 = new BigDecimal(Double.toString(v2));return b1.subtract(b2).doubleValue();} /*** 提供精确的乘法运算。* @param v1 被乘数* @param v2 乘数* @return 两个参数的积*/public static double mul(double v1,double v2){BigDecimal b1 = new BigDecimal(Double.toString(v1));BigDecimal b2 = new BigDecimal(Double.toString(v2));return b1.multiply(b2).doubleValue();}/*** 提供(相对)精确的除法运算,当发生除不尽的情况时,精确到* 小数点以后10位,以后的数字四舍五入。* @param v1 被除数* @param v2 除数* @return 两个参数的商*/public static double div(double v1,double v2){return div(v1,v2,DEF_SCALE);}/*** 提供(相对)精确的除法运算。当发生除不尽的情况时,由scale参数指* 定精度,以后的数字四舍五入。* @param v1 被除数* @param v2 除数* @param scale 表示表示需要精确到小数点以后几位。* @return 两个参数的商*/public static double div(double v1,double v2,int scale){if(scale<0){throw new IllegalArgumentException("The scale must be a positive integer or zero");}BigDecimal b1 = new BigDecimal(Double.toString(v1));BigDecimal b2 = new BigDecimal(Double.toString(v2));return b1.divide(b2,scale,BigDecimal.ROUND_HALF_UP).doubleValue();}/*** 提供精确的小数位四舍五入处理。* @param v 需要四舍五入的数字* @param scale 小数点后保留几位* @return 四舍五入后的结果*/public static double round(double v,int scale){if(scale<0){throw new IllegalArgumentException("The scale must be a positive integer or zero");}BigDecimal b = new BigDecimal(Double.toString(v));BigDecimal one = new BigDecimal("1");return b.divide(one,scale,BigDecimal.ROUND_HALF_UP).doubleValue();}
}

首发地址:http://www.eoeandroid.com/thread-230579-1-1.html

另外一个地址:http://krislq.com/150   嘎嘎!

转载于:https://www.cnblogs.com/nuliniaoboke/archive/2012/11/21/2780557.html

关于不能够精确的对浮点数进行运算的问题相关推荐

  1. python浮点数怎么运算_Python如何执行精确的浮点数运算

    问题 你需要对浮点数执行精确的计算操作,并且不希望有任何小误差的出现. 解决方案 浮点数的一个普遍问题是它们并不能精确的表示十进制数. 并且,即使是最简单的数学运算也会产生小的误差,比如: >& ...

  2. 计组之数据运算:11、浮点数的运算

    11.浮点数的运算 思维导图 科学技术法的运算 浮点数的运算 舍入问题 浮点数的强制类型转化 思维导图 科学技术法的运算 浮点数的运算 舍入问题 浮点数的强制类型转化 int->float: i ...

  3. 【Python】解决浮点数间运算存在不确定尾数的问题

    #浮点数间运算存在不确定尾数,所以会输出False if 0.1+0.2==0.3:print("Ture\n") else:print("False\n") ...

  4. 计算机系统基础实验 - 同符号浮点数加法运算/无符号定点数乘法运算的机器级表示

    实验3 同符号浮点数加法运算/无符号定点数乘法运算的机器级表示 实验序号:3 实验名称:同符号浮点数加法运算/无符号定点数乘法运算的机器级表示 适用专业:软件工程 学 时 数:2学时 一.实验目的 1 ...

  5. 定点数和浮点数加减乘除运算详解【计算机组成原理】---真的建议收藏啊!!!

    前言: 你知道计算机内部是如何进行加减运算的吗?可能你知道,那你知道计算机内部是如何进行乘除法运算的呢?肯定和我们十进制运算是不一样的.当我查找资料的时候,发现除了书本很少有这样的知识点.所以我想和大 ...

  6. 7744问题(浮点数的运算可能会存在误差)

    7744问题_记:浮点数的运算可能存在误差,不是一定存在,但经常都会 方法一:使用函数sqrt()开平方.floor()返回整数部分判断 //7744,利用+0.5进行四舍五入以避免浮点数运算可能存在 ...

  7. python整数与浮点数混合运算输出结果为_笔记_004_整数和浮点数

    整数 Python 中,除 10 进制,还有其他三种进制: 0b 或 0B,二进制 0 1 0o 或 0O,八进制 0 1 2 3 4 5 6 7 0x 或 0X,十六进制 0 1 2 3 4 5 6 ...

  8. 【Python基础】为何0.1+0.2≠0.3,使用Python程序深入理解计算浮点数的运算

    [Python基础]为何0.1+0.2≠0.3,使用Python程序深入理解计算机浮点数的运算 用过Python这门编程语言的应该都会发现,当我们输入0.1+0.2时,打印出来的却不是0.3,而是0. ...

  9. python中浮点数间运算存在不确定尾数_python 浮点数类型

    - 带有小数点及小数的数字 - 浮点数取值范围和小数精度都存在限制,但常规计算可忽略 - 浮点数的取值范围数量级约为  至 浮点数间运算存在不确定尾数,这不是bug # 浮点数间运算存在不确定尾数 & ...

最新文章

  1. usaco Score Inflation
  2. MQ的引言|不同MQ的特点|RabbitMQ安装
  3. php 腾讯企业邮箱接口,帮助中心 腾讯企业邮箱OpenApi协议
  4. CentOS搭建Sqoop环境
  5. 谈谈Memcached与Redis
  6. multi task训练torch_Multi-task Learning的三个小知识
  7. 折线分割平面(HDU-2050)
  8. 计算机容量单位比T,容量单位.比G大是T.比T大是E.比E大是什么?
  9. UITableView自动计算图片的高度 SDWebImage
  10. #216. 最小花费最短路
  11. Protel 99SE在Win10下按键就卡,无法使用
  12. 九大内置对象和servlet生命周期
  13. 马科维茨投资组合理论(均方模型)(1)
  14. 【损失函数】生成任务感知损失小结
  15. 占书明:win7系统微信突然提示“微信运行错误:当前版本需在windows xp sp3以上系统运行,请安装可用版本或升级系统。点击确认下载安装可用版本”。
  16. 计算机毕业设计Android手机校园外卖订餐APP(源码+系统+mysql数据库+Lw文档)
  17. 面试官:怎么不用定时任务实现关闭订单?
  18. The Thirty-fifth Of Word-Day
  19. 迅雷离线配合Internet Download Manager下载ED2K链接
  20. 好记性不如烂笔头之Java基础复习笔记

热门文章

  1. java 字符串过长_idea java常量字符串过长解决办法
  2. ipc620中文版最新版本_(一)Windows10 家庭中文版Docker安装 搭建docker开发环境
  3. linux查询关键词上下行_【已解决】Linux下通过关键字模糊查找搜索文件
  4. 用python实现计算器功能_使用python实现计算器功能
  5. 027_html框架
  6. 自定义ImageView系列
  7. linux系统查看CPU使用含义、IO、内存、硬盘使用、负载
  8. Unity各个版本的离线文档下载和配置方法
  9. android游戏加载,Android 游戏引擎libgdx 资源加载进度百分比显示案例分析
  10. python list去掉引号_最新的python面试题集170之三(基础性学习)