博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java Double相加出现的怪事
阅读量:6257 次
发布时间:2019-06-22

本文共 3247 字,大约阅读时间需要 10 分钟。

hot3.png

问题的提出:   

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

 

[java] 

  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] 

  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] 

  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] 

  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.      *  v1 
  23.      *            被加数 
  24.      *  v2 
  25.      *            加数 
  26.      *  两个参数的和 
  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.      *  v1 
  39.      *            被减数 
  40.      *  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. };  

转载于:https://my.oschina.net/newchaos/blog/1561073

你可能感兴趣的文章
iOS---后台运行机制详解
查看>>
python-装饰器的最终形态和固定格式 语法糖
查看>>
iphone配置实用工具iPhone Configuration Utility
查看>>
Centos搭建开发环境,PHP7+ Nginx1.12+ Mysql5.7
查看>>
RSA的密钥把JAVA格式转换成C#的格式
查看>>
转载 HTTPS 之fiddler抓包、jmeter请求
查看>>
Android常用查询网站
查看>>
wifi diplasy流程介绍
查看>>
使用浏览器做编辑器
查看>>
【20181030T1】排列树【树形结构+组合数】
查看>>
windows&linux双系统时间相差8小时
查看>>
史上最详细的linux网卡ifcfg-eth0配置详解
查看>>
iphone-common-codes-ccteam源代码 CCUIScreen.m
查看>>
SDO_Geometry相关学习(转载)
查看>>
二叉查找(排序)树的分析与实现
查看>>
LeetCode-230. Kth Smallest Element in a BST
查看>>
js之隔行换色
查看>>
使用EMQ搭建MQTT服务器
查看>>
P3379 【模板】最近公共祖先(LCA)(树链剖分)版
查看>>
利用GCC编译器生成动态链接库和静态链接库
查看>>