文档章节

Java Double相加出现的怪事

o
 onedotdot
发布于 2017/11/05 16:36
字数 962
阅读 23
收藏 0

问题的提出:   

  编译运行下面这个程序会看到什么

 

[java] view plaincopy

  1. public class test {  
  2.     public static void main(String args[]) {  
  3.         System.out.println(0.05 + 0.01);  
  4.         System.out.println(1.0 - 0.42);  
  5.         System.out.println(4.015 * 100);  
  6.         System.out.println(123.3 / 100);  
  7.     }  
  8. };  


你没有看错!结果确实是

 

 

[java] view plaincopy

  1. 0.060000000000000005     
  2. 0.5800000000000001     
  3. 401.49999999999994     
  4. 1.2329999999999999     

 

 

Java中的简单浮点数类型float和double不能够进行运算。不光是Java,在其它很多编程语言中也有这样的问题。在大多数情况下,计算的结果是准确的,但是多试几次(可以做一个循环)就可以试出类似上面的错误。现在终于理解为什么要有BCD码了。   
  这个问题相当严重,如果你有9.999999999999元,你的计算机是不会认为你可以购买10元的商品的。   
  在有的编程语言中提供了专门的货币类型来处理这种情况,但是Java没有。现在让我们看看如何解决这个问题。    
    解决方案   
  现在我们已经可以解决这个问题了,原则是使用BigDecimal并且一定要用String来够造。   
  但是想像一下吧,如果我们要做一个加法运算,需要先将两个浮点数转为String,然后够造成BigDecimal,在其中一个上调用add方法,传入另一个作为参数,然后把运算的结果(BigDecimal)再转换为浮点数。你能够忍受这么烦琐的过程吗?下面我们提供一个工具类Arith来简化操作。它提供以下静态方法,包括加减乘除和四舍五入:

 

[java] view plaincopy

  1. public static double add(double v1, double v2);  
  2.   
  3.     public static double sub(double v1, double v2);  
  4.   
  5.     public static double mul(double v1, double v2);  
  6.   
  7.     public static double div(double v1, double v2);  
  8.   
  9.     public static double div(double v1, double v2, int scale);  
  10.   
  11.     public static double round(double v, int scale);  

 

[java] view plaincopy

  1. package org.nutz.mvc.core;  
  2.   
  3. import java.math.BigDecimal;  
  4.   
  5. public class Arith {  
  6.     // 源文件Arith.java:  
  7.   
  8.     /** 
  9.      * 由于Java的简单类型不能够精确的对浮点数进行运算,这个工具类提供精 确的浮点数运算,包括加减乘除和四舍五入。 
  10.      */  
  11.   
  12.     // 默认除法运算精度  
  13.     private static final int DEF_DIV_SCALE = 10;  
  14.   
  15.     // 这个类不能实例化  
  16.     private Arith() {  
  17.     }  
  18.   
  19.     /** 
  20.      * 提供精确的加法运算。 
  21.      *  
  22.      * @param v1 
  23.      *            被加数 
  24.      * @param v2 
  25.      *            加数 
  26.      * @return 两个参数的和 
  27.      */  
  28.   
  29.     public static double add(double v1, double v2) {  
  30.         BigDecimal b1 = new BigDecimal(Double.toString(v1));  
  31.         BigDecimal b2 = new BigDecimal(Double.toString(v2));  
  32.         return b1.add(b2).doubleValue();  
  33.     }  
  34.   
  35.     /** 
  36.      * 提供精确的减法运算。 
  37.      *  
  38.      * @param v1 
  39.      *            被减数 
  40.      * @param v2 
  41.      *            减数 
  42.      * @return 两个参数的差 
  43.      */  
  44.   
  45.     public static double sub(double v1, double v2) {  
  46.         BigDecimal b1 = new BigDecimal(Double.toString(v1));  
  47.         BigDecimal b2 = new BigDecimal(Double.toString(v2));  
  48.         return b1.subtract(b2).doubleValue();  
  49.     }  
  50.   
  51.     /** 
  52.      * 提供精确的乘法运算。 
  53.      *  
  54.      * @param v1 
  55.      *            被乘数 
  56.      * @param v2 
  57.      *            乘数 
  58.      * @return 两个参数的积 
  59.      */  
  60.   
  61.     public static double mul(double v1, double v2) {  
  62.         BigDecimal b1 = new BigDecimal(Double.toString(v1));  
  63.         BigDecimal b2 = new BigDecimal(Double.toString(v2));  
  64.         return b1.multiply(b2).doubleValue();  
  65.     }  
  66.   
  67.     /** 
  68.      * 提供(相对)精确的除法运算,当发生除不尽的情况时,精确到 小数点以后10位,以后的数字四舍五入。 
  69.      *  
  70.      * @param v1 
  71.      *            被除数 
  72.      * @param v2 
  73.      *            除数 
  74.      * @return 两个参数的商 
  75.      */  
  76.   
  77.     public static double div(double v1, double v2) {  
  78.         return div(v1, v2, DEF_DIV_SCALE);  
  79.     }  
  80.   
  81.     /** 
  82.      * 提供(相对)精确的除法运算。当发生除不尽的情况时,由scale参数指 定精度,以后的数字四舍五入。 
  83.      *  
  84.      * @param v1 
  85.      *            被除数 
  86.      * @param v2 
  87.      *            除数 
  88.      * @param scale 
  89.      *            表示表示需要精确到小数点以后几位。 
  90.      * @return 两个参数的商 
  91.      */  
  92.   
  93.     public static double div(double v1, double v2, int scale) {  
  94.         if (scale < 0) {  
  95.             throw new IllegalArgumentException(  
  96.                     "The   scale   must   be   a   positive   integer   or   zero");  
  97.         }  
  98.         BigDecimal b1 = new BigDecimal(Double.toString(v1));  
  99.         BigDecimal b2 = new BigDecimal(Double.toString(v2));  
  100.         return b1.divide(b2, scale, BigDecimal.ROUND_HALF_UP).doubleValue();  
  101.     }  
  102.   
  103.     /** 
  104.      * 提供精确的小数位四舍五入处理。 
  105.      *  
  106.      * @param v 
  107.      *            需要四舍五入的数字 
  108.      * @param scale 
  109.      *            小数点后保留几位 
  110.      * @return 四舍五入后的结果 
  111.      */  
  112.   
  113.     public static double round(double v, int scale) {  
  114.         if (scale < 0) {  
  115.             throw new IllegalArgumentException(  
  116.                     "The   scale   must   be   a   positive   integer   or   zero");  
  117.         }  
  118.         BigDecimal b = new BigDecimal(Double.toString(v));  
  119.         BigDecimal one = new BigDecimal("1");  
  120.         return b.divide(one, scale, BigDecimal.ROUND_HALF_UP).doubleValue();  
  121.     }  
  122. };  

本文转载自:http://blog.csdn.net/z69183787/article/details/42148387

o
粉丝 8
博文 375
码字总数 16064
作品 0
朝阳
私信 提问
MAC下java_home问题

最近买了mac,还在熟悉中。安装环境过程中,发现了一些问题。这里说一下java_home的问题。 1.mac自带jdk为1.6,在命令行查看java -version,显示为1.6。 2.下载oracle的jdk1.7,安装后,命令...

lawrenceli
2014/04/03
0
0
Java自动装箱-拆箱机制究竟是什么

支持原文:http://tryenough.com/java-autobox 自动装箱和拆箱从Java 1.5开始引入,目的是将原始类型值转自动地转换成对应的对象。 什么是自动装箱和拆箱 自动装箱就是Java自动将原始类型值转...

TryEnough
03/13
0
0
String ,  StringBuffer ,  StringBuilder的区别

String , StringBuffer , StringBuilder的区别 String 首先,String 是用来表示一个字符串常量的,它是一个不可变对象,意味着,一旦我们创建了某个字符串之后,就不能再改变它的值了,我们可...

tsmyk0715
2018/10/17
0
0
java 算法问题,求double集合里,值相加无限接近100的,最少有多少个?

如题:java 算法问题,求double集合里,值相加无限接近100的,最少有多少个?

心心相印
2017/02/27
299
2
浅谈把Java字节码译为C代码的意义

Java字节码是基于栈的一种编码。这种编码方式十分方便解释器的设计,但同时不利于程序分析,因此一些高效的代码优化技术无法方便的Java字节码上实现。 先大体说说Java字节码的特点。目前版本...

小欣妹妹
2018/04/26
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Flutter移动端实战手册

该文章属于<简书 — 刘小壮>原创,转载请注明: <简书 — 刘小壮> https://www.jianshu.com/p/d27c1f5ee3ff iOS接入Flutter 在进行iOS和Flutter的混编时,iOS比Android的接入方式略复杂,但也...

刘小壮
17分钟前
0
0
测试环境项目一键部署

git项目测试环境一键部署脚本 #!/bash/sh pid=`ps -ef | grep 'user_demo.jar' | grep -v grep | awk '{print $2}'` kill -9 $pid #跳转到git clone下目录 cd /home/apple/userdemo/ #拉取最......

ccman996
20分钟前
0
0
应用框架(spring-boot参数配置与使用)

这很耳东先生
26分钟前
0
0
使用SecureCRT从windows上传文件到Linux

点击File,然后选择SFTP,打开SFTP,然后进行下列操作。 1.指定文件所在路径 lcd E:\ 2.查看当前windows文件所在路径 lpwd 3.指定linux下文件上传路径 cd /usr/local 4.查询当前linux文件上传...

大雁南飞了
29分钟前
1
0
前后端分离-前端搭建(Vue)(3)加入Element和axios

继续上篇博客的Vue刚刚搭建完 , https://my.oschina.net/u/4116654/blog/3064431 这次我们来把Element 和axios弄好 首先先安装Element 下载好了之后 在src目录下的main.js里去添加Element的...

咸鱼-李y
40分钟前
0
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部