转自:http://superivan.iteye.com/blog/963628

[1] 精确的浮点运算: 
在Java里面,有时候为了保证数值的准确性需要精确的数据,先提供一个例子就可以发现问题了:

public class FloatNumberTester {
public static void main(String args[]){
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

这样的话这个问题就相对严重了,如果我们使用123.3元交易,计算机却因为1.2329999999999999而拒绝了交易,岂不是和实际情况大相径庭。

[2] 四舍五入: 
另外的一个计算问题,就是四舍五入。但是Java的计算本身是不能够支持四舍五入的,比如:

public class GetThrowTester {
public static void main(String args[]){
System.out.println(4.015 * 100.0);
}

这个输出为: 
401.49999999999994 
所以就会发现这种情况并不能保证四舍五入,如果要四舍五入,只有一种方法 
java.text.DecimalFormat:

import java.text.DecimalFormat;
public class NumberFormatMain {
public static void main(String args[]){
System.out.println(new DecimalFormat("0.00").format(4.025));
System.out.println(new DecimalFormat("0.00").format(4.024));
}
}

上边代码输出为:

4.02
4.02

发现问题了么?因为DecimalFormat使用的舍入模式, 舍入模式 详情参见本文最后部分。 
[3] 浮点输出: 
  Java浮点类型数值在大于9999999.0就自动转化成为科学计数法,看看下边的例子:

public class FloatCounter {
public static void main(String args[]){
System.out.println(9969999999.04);
System.out.println(199999999.04);
System.out.println(1000000011.01);
System.out.println(9999999.04);
}
}

输出结果为:

9.96999999904E9
1.9999999904E8
1.00000001101E9
9999999.04

但是有时候我们不需要科学计数法,而是转换成为字符串,所以这样可能会有点麻烦。 
总结: 
所以在项目当中,对于浮点类型以及大整数的运算 还是尽量不要用double,long等基本数据类型以及其包装类,还是用Java中提供的BigDecimal,BigInteger等大数值类型来代替吧。 
但这里特别说明一下BigDecimal类的两个构造函数的区别,他们分别是: 
new BigDecimal(String  val ) 和 new BigDecimal(double  val )

public class BigDecimalMain {
public static void main(String args[]){
System.out.println(new BigDecimal(123456789.01).toString());
System.out.println(new BigDecimal("123456789.01").toString());
}
}

输出结果有一次令人意外了,同时两者之间的区别也一目了然了:

123456789.01000000536441802978515625
123456789.01

所以在 就是想利用double原始类型进行了相关计算之后再转成BigDecimal类型 的场合下,为了防止精度出现偏离,建议使用参数为String类型的该构造方法。即new BigDecimal(String  val )。

BigDecimal舍入模式介绍: 
  舍入模式在java.math.RoundingMode 里面: 
RoundingMode.CEILING :向正无限大方向舍入的舍入模式。如果结果为正,则舍入行为类似于 RoundingMode.UP;如果结果为负,则舍入行为类似于 RoundingMode.DOWN。注意,此舍入模式始终不会减少计算值

输入数字 使用CEILING舍入模式将数字舍入为一位数 
5.5
2.5
1.1
1.0
-1.0 -1 
-1.1 -1 
-1.6 -1 
-2.5 -2
-5.5 -5

RoundingMode.DOWN :向零方向舍入的舍入模式。从不对舍弃部分前面的数字加 1(即截尾)。注意,此舍入模式始终不会增加计算值的绝对值

输入数字 使用DOWN舍入模式将数字舍入为一位数 
5.5
2.5
1.1
-1.0 -1 
-1.6 -1 
-2.5 -2 
-5.5 -5 

RoundingMode.FLOOR :向负无限大方向舍入的舍入模式。如果结果为正,则舍入行为类似于 RoundingMode.DOWN;如果结果为负,则舍入行为类似于 RoundingMode.UP。注意,此舍入模式始终不会增加计算值

输入数字 使用FLOOR舍入模式将输入数字舍入为一位 
5.5
2.3
1.6
1.0
-1.1 -2 
-2.5 -3 
-5.5 -6

RoundingMode.HALF_DOWN :向最接近数字方向舍入的舍入模式,如果与两个相邻数字的距离相等,则向下舍入。如果被舍弃部分 > 0.5,则舍入行为同 RoundingMode.UP;否则舍入行为同 RoundingMode.DOWN

输入数字 使用HALF_DOWN输入模式舍入为一位 
5.5
2.5
1.6
1.0
-1.1 -1 
-1.6 -2 
-2.5 -2 
-5.5 -5 

RoundingMode.HALF_EVEN :向最接近数字方向舍入的舍入模式,如果与两个相邻数字的距离相等,则向相邻的偶数舍入。如果舍弃部分左边的数字为奇数,则舍入行为同 RoundingMode.HALF_UP;如果为偶数,则舍入行为同 RoundingMode.HALF_DOWN。注意,在重复进行一系列计算时,此舍入模式可以在统计上将累加错误减到最小。此舍入模式也称为“银行家舍入法”,主要在美国使用。此舍入模式类似于 Java 中对 float 和 double 算法使用的舍入策略

输入数字 使用HALF_EVEN舍入模式将输入舍为一位 
5.5
2.5
1.6
1.1
-1.0 -1 
-1.6 -2 
-2.5 -2 
-5.5 -6 

RoundingMode.HALF_UP :向最接近数字方向舍入的舍入模式,如果与两个相邻数字的距离相等,则向上舍入。如果被舍弃部分 >= 0.5,则舍入行为同 RoundingMode.UP;否则舍入行为同 RoundingMode.DOWN。注意,此舍入模式就是通常学校里讲的四舍五入

输入数字 使用HALF_UP舍入模式舍入为一位数 
5.5
2.5
1.6
1.0
-1.1 -1 
-1.6 -2 
-2.5 -3 
-5.5 -6 

RoundingMode.UNNECESSARY :用于断言请求的操作具有精确结果的舍入模式,因此不需要舍入。如果对生成精确结果的操作指定此舍入模式,则抛出 ArithmeticException

输入数字 使用UNNECESSARY模式 
5.5 抛出 ArithmeticException 
2.5 抛出 ArithmeticException 
1.6 抛出 ArithmeticException 
1.0
-1.0 -1.0 
-1.1 抛出 ArithmeticException 
-1.6 抛出 ArithmeticException 
-2.5 抛出 ArithmeticException 
-5.5 抛出 ArithmeticException

RoundingMode.UP :远离零方向舍入的舍入模式。始终对非零舍弃部分前面的数字加 1。注意,此舍入模式始终不会减少计算值的绝对值

输入数字 使用UP舍入模式将输入数字舍入为一位数 
5.5
1.6
1.1
1.0
-1.1 -2 
-1.6 -2 
-2.5 -3 
-5.4 -6
import  java.math.BigDecimal;
import java.text.DecimalFormat;
/**
*使用舍入模式的格式化操作
**/
public class DoubleFormat {
public static void main(String args[]){
DoubleFormat format = new DoubleFormat();
System.out .println(format.doubleOutPut(12.345, 2));
System.out .println(format.roundNumber(12.335, 2));
}
public String doubleOutPut(double v,Integer num){
if ( v == Double.valueOf(v).intValue()){
return Double.valueOf(v).intValue() + "" ;
}else {
BigDecimal b = new BigDecimal(Double.toString(v));
return b.setScale(num,BigDecimal.ROUND_HALF_UP ).toString();
}
}
public String roundNumber(double v,int num){
String fmtString = "0000000000000000" ; //16bit
fmtString = num>0 ? "0." + fmtString.substring(0,num):"0" ;
DecimalFormat dFormat = new DecimalFormat(fmtString);
return dFormat.format(v);
}
}

这段代码的输出为:

12.35
12.34

Double与BigDecimal 精度问题的更多相关文章

  1. java防止double和float精度丢失的方法

    在浮点数当中做运算时经常会出现精度丢失的情况,如果做项目不作处理的话会对商家造成很大的影响的.项目尤其是金融相关的项目对这些运算的精度要求较高. 问题原因:首先计算机进行的是二进制运算,我们输入的十进 ...

  2. java中double和float精度丢失问题及解决方法

    在讨论两位double数0.2和0.3相加时,毫无疑问他们相加的结果是0.5.但是问题总是如此吗? 下面我们让下面两个doubles数相加,然后看看输出结果: @Test public void te ...

  3. double,失去精度

    double,失去精度: amount.doubleValue() * 使用 BigDecimal: public static double add(double d1,double d2){ Bi ...

  4. [ JAVA编程 ] double类型计算精度丢失问题及解决方法

    前言 如果你在测试金融相关产品,请务必覆盖交易金额为小数的场景.特别是使用Java语言的初级开发. Java基本实例 先来看Java中double类型数值加.减.乘.除计算式实例: public cl ...

  5. [转]double与BigDecimal

    转自:http://superivan.iteye.com/blog/963628 [1] 精确的浮点运算: 在Java里面,有时候为了保证数值的准确性需要精确的数据,先提供一个例子就可以发现问题了: ...

  6. java中double和float精度丢失问题

    为什么会出现这个问题呢,就这是java和其它计算机语言都会出现的问题,下面我们分析一下为什么会出现这个问题:float和double类型主要是为了科学计算和工程计算而设计的.他们执行二进制浮点运算,这 ...

  7. BigDecimal精度详解

    [BigDecimal精确度的计数保留法及精度丢失的解决办法] 目录 BigDecimal精确度的计数保留法 1.ROUND_UP 2.ROUND_DOWN 3.ROUND_HALF_UP 4.ROU ...

  8. Java中如何解决double和float精度不准的问题

    我们知道浮点数是无法在计算机中准确表示的,例如0.1在计算机中只是表示成了一个近似值,因此,对付点数的运算时结果具有不可预知性. 在进行数字运算时,如果有double或float类型的浮点数参与计算, ...

  9. iOS项目double、float精度丢失解决办法

    描述 在iOS项目中老是遇到double.float精度丢失的问题 PS: NSString * jsonStr = @"{\"9.70\":9.70,\"67 ...

随机推荐

  1. openresty + lua 3、openresty http 调用

    http 的话,openresty 已经集成,ng 的话,自己引入即可. github 地址:https://github.com/pintsized/lua-resty-http github 里提 ...

  2. http://vjudge.net/contest/view.action?cid=51142#problem/C 精度转换的一道题。。。

    C - Get-Together at Den's Time Limit:1000MS     Memory Limit:65536KB     64bit IO Format:%I64d & ...

  3. [ASE][Daily Scrum]11.12

    这几天Jiafan同学回学校去了,服务器的问题暂时未解决.继续搭建服务器中: View Shilin Liu 修复tank的错位问题 产生残缺地图         Client Jiafan Zhu( ...

  4. C#操作数据表中XML格式的数据

    以前还真没有见过数据表中存储XML格式的数据,刚开始听说的时候,还以为是数据表中有XML的字段类型, 再了解,其实也就是字符串类型的,只不过字符串的格式是XML格式的.确实孤陋寡闻!汗... (可添加 ...

  5. WPF学习笔记(1):DataGrid单元格实现逐键过滤功能

    最近,开始学习WPF,其UI设计完全颠覆了传统的设计理念,为程序员提供了极大的自由发挥空间,让我为之惊叹,且为之着迷.然而,WPF在国内的热度却并不高,大部分贴子都是2012年以前的,出版的图书也很少 ...

  6. 关于WordCount的作业

    一.开发者:201631062418 二.代码地址:https://gitee.com/YsuLIyan/WordCount 三.作业地址:https://edu.cnblogs.com/campus ...

  7. Python黑客——快速编写信息收集器

    i春秋作家:大木瓜 环境:Python 3模块:LxmlRequestBeautifulsoup开始:首先看一下目标站: http://gaokao.chsi.com.cn/gkxx/zszcgd/d ...

  8. file_put_contents 换行

    file_put_contents('test.text', json_encode($result) . PHP_EOL, FILE_APPEND);

  9. activemq在一台服务器上启动多个Broker

    步骤如下: 1.把整个conf文件夹复制一份,比如叫conf2 2.修改里面的activemq.xml文件 ①brokerName不能和原来的重复 ②数据存放的文件名称不能重复,比如<kahaD ...

  10. java批量读取多个文件并存入数据库

    有时候服务运行的日志文件,需要统计分析,但数据量很大,并且直接在文件中看很不直观,这时可以将文件中的内容导入到数据库,入库后的数据就可以按照需求进行统计分析了. 这个是以服务器的访问日志作为示例,一个 ...