- 浏览: 376533 次
- 性别:
- 来自: 武汉
文章分类
最新评论
-
angryid:
dsafddsfssssssssddsdsasssssssss ...
freemarker学习笔记---assign标签 -
lylovejava0:
数据库里字段不能转换。。这样会慢死。。在说如果表里有分区等设置 ...
Oracle 时间段查询 -
greatjone:
必须得评论下,这篇博文相当实用,在csdn上找个东西老还要积分 ...
MyEclipse下安装jad插件 -
mytream:
...
模拟tomcat工作原理 -
liujianche11:
小心点 createdate<=to_date('20 ...
Oracle 时间段查询
- Java中的简单浮点数类型float和double不能够进行运算。不光是Java,在其它很多编程语言中也有这样的问题。
如果我们编译运行下面这个程序会看到什么?
public
class
Test
{
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
Java
中的简单浮点数类型float
和double
不能够进行运算。不光是Java
,在其它很多编程语言中也有这样的问题。在大多数情况下,计算的结果是准确的,但是多试几次(可以做一个循环)就可以试出类似上面的错误。现在终于理解为什么要有BCD
码了。
这个问题相当严重,如果你有9.999999999999
元,你的计算机是不会认为你可以购买10
元的商品的。
在有的编程语言中提供了专门的货币类型来处理这种情况,但是Java
没有。现在让我们看看如何解决这个问题。
四舍五入
我们的第一个反应是做四舍五入。Math
类中的round
方法不能设置保留几位小数,我们只能象这样(保留两位):
public
double
round(
double
value)
{
return
Math.round(value * 100) / 100.0;
}
非常不幸,上面的代码并不能正常工作,给这个方法传入4.015
它将返回4.01
而不是4.02
,如我们在上面看到的
4.015*100=401.49999999999994
因此如果我们要做到精确的四舍五入,不能利用简单类型做任何运算
java.text.DecimalFormat
也不能解决这个问题:
System.out.println(new java.text.DecimalFormat("0.00").format(4.025));
输出是4.02
BigDecimal
在《Effective Java
》这本书中也提到这个原则,float
和double
只能用来做科学计算或者是工程计算,在商业计算中我们要用java.math.BigDecimal
。BigDecimal
一共有4
个够造方法,我们不关心用BigInteger
来够造的那两个,那么还有两个,它们是:
BigDecimal(double val)
Translates a double into a BigDecimal.
BigDecimal(String val)
Translates the String repre sentation of a BigDecimal into a BigDecimal.
上面的API
简要描述相当的明确,而且通常情况下,上面的那一个使用起来要方便一些。我们可能想都不想就用上了,会有什么问题呢?等到出了问题的时候,才发现上面哪个够造方法的详细说明中有这么一段:
Note:
the results of this constructor can be somewhat unpredictable. One
might assume that new BigDecimal(.1) is exactly equal to .1, but it is
actually equal to
.1000000000000000055511151231257827021181583404541015625. This is so
because .1 cannot be represented exactly as a double (or, for that
matter, as a binary fraction of any finite length). Thus, the long value
that is being passed in to the constructor is not exactly equal to .1,
appearances nonwithstanding.
The (String) constructor, on the other
hand, is perfectly predictable: new BigDecimal(".1") is exactly equal to
.1, as one would expect. Therefore, it is generally recommended that
the (String) constructor be used in preference to this one.
原来我们如果需要精确计算,非要用String
来够造BigDecimal
不可!在《Effective Java
》一书中的例子是用String
来够造BigDecimal
的,但是书上却没有强调这一点,这也许是一个小小的失误吧。
解决方案
现在我们已经可以解决这个问题了,原则是使用BigDecimal
并且一定要用String
来够造。
但是想像一下吧,如果我们要做一个加法运算,需要先将两个浮点数转为String
,然后够造成BigDecimal
,在其中一个上调用add
方法,传入另一个作为参数,然后把运算的结果(BigDecimal
)再转换为浮点数。你能够忍受这么烦琐的过程吗?下面我们提供一个工具类Arith
来简化操作。它提供以下静态方法,包括加减乘除和四舍五入:
public static double add(double v1,double v2)
public static double sub(double v1,double v2)
public static double mul(double v1,double v2)
public static double div(double v1,double v2)
public static double div(double v1,double v2,int scale)
public static double round(double v,int scale)
附录
源文件Arith.java
:
import
java.math.BigDecimal;
public
class
Arith
{
//
默认除法运算精度
private
static
final
int
DEF_DIV_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_DIV_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();
}
}
评论
Java 语言支持两种基本的浮点类型: float 和 double 。java 的浮点类型都依据 IEEE 754 标准。IEEE 754 定义了32 位和 64 位双精度两种浮点二进制小数标准。
IEEE 754 用科学记数法以底数为 2 的小数来表示浮点数。
对于32 位浮点数float用 第1 位表示数字的符号,用第2至9位来表示指数,用 最后23 位来表示尾数,即小数部分。
float(32位):
对于64 位双精度浮点数,用 第1 位表示数字的符号,用 11 位表示指数,52 位表示尾数。
double(64位):
任何一个数字,在java底层表示都必须转换成这种科学计数法来表示,那么我们来想想看什么时候这个数字会无法表示呢?那么只有两种情形:
1.幂数不够表示了:这种情况往往出现在数字太大了,超过幂数所能承受的范围,那么这个数字就无法表示了。如幂数最大只能是10,但是这个数字用科学计数法表示时,幂数一定会超过10,就没办法了。
2.尾数不够表示了:这种情况往往出现在数字精度太长了,如1.3434343233332这样的数字,虽然很小,还不超过2,这种情况下幂数完全满足要求,但是尾数已经不能表示出来了这么长的精度。
http://www.just4e.com/jdk-1.6_CN/zh_CN/api/java/text/DecimalFormat.html
谢谢分享
发表评论
-
Java内存分析工具
2012-01-17 10:45 1610Java运行时数据区包含 ... -
中文乱码问题案例分析
2011-10-14 12:50 1900案例: 1、 环境介绍: 项目 ... -
button在Firefox下点击提交表单(form)的问题
2011-09-21 10:33 1158【关键词】Button Form FireFox ... -
模拟tomcat工作原理
2011-07-28 13:10 1103httpserver原理:服务器端 打开一个socket,一直 ... -
EL表达式中empty的用法
2011-07-07 17:07 2454在做jsp系统的时候经常会使用el标签,而empty ... -
解决TOMCAT控制台输出 “Parameters: Invalid chunk ignored.”
2011-07-05 13:27 1213用过tomcat的都知道,request参数中如果有程 ... -
if 和 else if
2011-06-20 11:23 789最近做项目碰到服务器端验证用到了大量的if语句,首先不 ... -
java枚举类详解
2011-06-16 13:05 1485JDK1.6增添了一些新的特性,其中枚举就是其中比较重要 ... -
Java正则表达式的使用
2011-05-20 10:01 663import java.util.regex.Matcher; ... -
Cookie的MaxAge属性及其使用
2011-05-07 01:14 5845首先,看看API文档中对M ... -
根据不同情况提交表单
2011-05-05 10:29 1109在项目开发的过程中经常涉及到表单提交的问题,为了使得 ... -
Jsp传递中文参数详解
2011-05-01 17:39 933目前在jsp页面中传递中文参数,主要有两种方式: ... -
存储基础知识:数据一致性
2011-04-18 11:00 1606一、概述 数据一致性是指关联数据之间的逻辑关系是否正确和完整 ... -
java 检查 URL 合法性
2011-04-15 10:19 4803/** * URL检查& ... -
关于用SimpleDateFormat进行日期格式化的问题
2011-04-01 13:45 1031做了遮掩一个实验: public static vo ... -
深入Java对象的比较
2011-03-31 18:22 1394深入Java对象的比较 ... -
commons-fileupload上传组件学习记录
2011-03-30 11:18 2196最近在用commons-fileupload做文件 ... -
Web上传文件的原理及实现[转]
2011-03-30 02:48 1023现在有很多 Web程序都有上传功能,实现上传功能的组件 ... -
java保留两位小数
2011-03-29 18:23 1065java保留两位小数问题: 方式一: ... -
RequestDispatcher接口中的include()方法和forward()方法的区别
2011-03-24 23:12 1369请求转发中 RequestDispatcher 接口中的 ...
相关推荐
Java中的`BigDecimal`类是用于表示和操作高精度浮点数的重要工具,尤其适用于需要进行精确计算的场景,如财务和货币计算。由于基本数据类型`double`和`float`在进行大数值或高精度计算时可能会导致精度丢失,因此`...
JAVA基础:java.math.BigDecimal的使用方法. JAVA基础:java.math.BigDecimal的使用方法.
在Java编程语言中,处理大数(大数据量的整数)加法时,通常会使用`java.math.BigDecimal`类。这个类提供了精确的浮点数运算,特别适合于需要高精度计算的情况,如金融计算或者复杂的数学运算。下面将详细讨论`...
Java中BigInteger的数学运算,BigDecimal 加减乘除运算,Java在java.math包中提供的API类BigDecimal,用来对超过16位有效位的数进行精确的运算。双精度浮点型变量double可以处理16位有效数。在实际应用中,需要对更大...
在Java编程语言中,`java.lang.Math`类提供了一系列用于执行基本数学运算的方法和常量。这个类包含静态方法和常量,使得开发者无需实例化对象即可直接调用其功能,极大地简化了数学计算的过程。 ### 常量 #### ...
* java.math 是 Java 2 Platform 的一部分,提供了用于执行任意精度整数算法 (BigInteger) 和任意精度小数算法 (BigDecimal) 的类。 21、网络应用程序:java.net 为实现网络应用程序提供类。 * java.net 是 Java 2...
Java在java.math包中提供的API类BigDecimal,用来对超过16位有效位的数进行精确的运算。双精度浮点型变量double可以处理16位有效数。在实际应用中,需要对更大或者更小的数进行运算和处理。float和double只能用来做...
Java Double相加出现的怪事 Java 中的浮点数类型 float 和 double 在进行运算时会出现不精确的问题,这是因为计算机无法精确地表示十进制小数。...在商业计算中,我们应该使用 java.math.BigDecimal 来解决这个问题。
除了这些基本的数学操作,Java还提供了其他类来处理复数(`java.math.Complex`),大数(`java.math.BigInteger`和`java.math.BigDecimal`)以及高精度浮点数(`java.math.BigDecimal`)。这些类在需要更高精度或更...
`BigDecimal`类在Java等其他语言中是专门用来处理高精度十进制数的,它提供了丰富的算术运算方法,确保计算结果的精确性。在JavaScript中,虽然没有内置的`BigDecimal`类,但开发者可以通过第三方库来实现类似的功能...
在Java编程语言中,`Math`类提供了几个用于处理数值的静态方法,其中包括`Math.round()`, `Math.ceil()`, 和 `Math.floor()`。这些方法主要用于处理浮点数,将它们转换成整数,但每种方法的取整策略不同。下面我们将...
下面是关于 BigDecimal 的使用方法和注意事项: 1. 导包:在使用 BigDecimal 之前,需要导入 java.math.BigDecimal 包。 2. 创建 BigDecimal 对象:可以通过多种方式创建 BigDecimal 对象,例如将 double 或 ...
在Java编程语言中,`BigDecimal` 类位于 `java.math`...总的来说,`BigDecimal` 类是Java中处理高精度计算的重要工具,理解其构造函数和方法的用法,以及如何避免精度问题,对于编写准确的财务或科学计算程序至关重要。
java.math 提供用于执行任意精度整数算法 (BigInteger) 和任意精度小数算法 (BigDecimal) 的类。 java.net 为实现网络应用程序提供类。 java.nio 定义作为数据容器的缓冲区,并提供其他 NIO 包的概述。 java.nio....
这两个类位于`java.math`包下,为开发者提供了超越基本数据类型(如int、long和double)的计算能力。在深入分析`BigInteger`和`BigDecimal`的源代码之前,我们先来理解这两个类的基本概念和用途。 `BigInteger`类:...
为了应对浮点数运算可能出现的精度问题,Java提供了`java.math`包,其中包含了一些用于精确数学计算的类,比如`BigDecimal`。本文将深入探讨Java中常用的数学类以及如何进行精确的浮点数运算,包括加减乘除、四舍五...
3. **使用`Byte`, `Short`, `Long`, `Float`, `BigInteger`, `BigDecimal`等类的转换方法**:这些类也有类似的转换方法,如果输入不符合它们的转换规则,都会抛出异常。 处理`NumberFormatException`的方法有以下几...
在Java编程语言中,控制输出...总结来说,`NumberFormat`和`java.math`包的`BigInteger`、`BigDecimal`类是Java中处理格式化输出和高精度计算的关键工具。它们提供了丰富的功能,确保了在各种场景下的灵活性和精度。
BigDecimal类位于java.math类包下,提供了多种构造函数和方法来实现精确计算。 首先,我们来看下如何构造一个BigDecimal对象。它的构造函数很多,这里挑选最常用的两个来演示一下:一个就是BigDecimal(double val)...
23. **java.math**:提供大整数(BigInteger)和高精度小数(BigDecimal)计算的类。 24. **java.net**:网络编程的类,包括Socket、ServerSocket和URL等。 25. **java.nio**:非阻塞I/O(New I/O)包,提供缓冲区...