在刚刚做完的一个项目中,遇到了double型计算不精确的问题。到网上查找后,问题得到解决。经验共享,在这里总结一下。
Java中的浮点数类型float和double不能够进行精确运算。这个问题有时候非常严重。比如,经过double型直接计算,1.4×1.5有时会得出2.0999999999999996的结果,但实际上,应该得到2.10。而且,类似的情况并不仅限于乘法计算。
在有的编程语言中提供了专门的货币类型来处理这种情况,但是Java没有。所以,在商业计算中我们要用:java.math.BigDecimal 。
BigDecimal一共有4个构造方法,其中不属于int的有两个,它们是:
1、BigDecimal(double val)
Translates a double into a BigDecimal.
2、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不可。
一、解决方案:
现在已经可以解决这个问题了,原则是使用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();
}
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();
}
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();
}
public static double div(double v1,double v2){
return div(v1,v2,DEF_DIV_SCALE);
}
/**
* 提供(相对)精确的除法运算。当发生除不尽的情况时,由scale参数指
* 定精度,以后的数字四舍五入。
*/
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();
}
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();
}
}
分享到:
相关推荐
本篇主要介绍16位、32位以及64位数据如何转换为浮点型(float)和双浮点型(double)。 首先,我们要理解二进制、16进制与浮点数的关系。计算机内部存储数字都是以二进制形式,而16进制是人类更易读的一种表示方式...
在 Java 中,数据类型可以分为整型、浮点型、字符型和布尔型四种主要类型。了解 Java 的数据类型对于编写高效、可靠的 Java 程序非常重要。 §2.1 数据类型 Java 的数据类型可以分为两大类:基本类型和引用类型。...
Java 中 float 和 double 的区别详解 float 和 double 是 Java 中两种基本数据类型,都是用来表示实数的,但是它们有很大的区别。float 是单精度类型,精度是 8 位有效数字,取值范围是 10 的 -38 次方到 10 的 38 ...
1. **数据类型**:Java提供了两种主要的数据类型来处理数字——整型(int, long, short, byte)和浮点型(float, double)。在这个计算器中,整型用于处理没有小数部分的数值,而浮点型则用于处理包含小数的数值。...
【Java浮点型计算器】是一个基于Java编程语言开发的图形用户界面(GUI)应用程序,它提供了基本的数学运算,包括加法、减法、乘法和除法,针对浮点数进行计算。浮点型计算器的主要特点在于处理带有小数部分的数值,...
在Java中,浮点数有两种主要形式:单精度浮点数(float)和双精度浮点数(double),它们分别使用32位和64位来存储。 1. **字节序**:在进行16进制到浮点数的转换时,必须考虑到字节序,即字节在内存中的排列顺序。...
本文将详细探讨如何使用Java语言来实现IEEE 754标准中的单精度浮点数(Float)的解析过程。 #### IEEE 754标准简介 IEEE 754标准定义了浮点数的二进制格式以及运算规则。对于单精度浮点数来说,它占用32位(4字节...
MySQL数据库则提供了多种小数类型,包括浮点型(FLOAT和DOUBLE)和定点型(DECIMAL)。浮点型小数使用科学计数法存储,提供较广的数值范围,但可能牺牲精度以节省存储空间。相比之下,定点型小数如DECIMAL,其精度是...
首先,我们要理解Java的基础数据类型,包括整型(byte, short, int, long)、浮点型(float, double)以及它们在数值计算中的应用。Java的数据类型提供了精确的数值存储和运算,但需要注意浮点型数据在进行计算时...
本文主要探讨了浮点类型数据,即float和double在内存中的表示方式,以及由此产生的精度问题。 首先,浮点类型数据有两种主要形式:单精度(float)和双精度(double)。float在内存中占用32位,而double占用64位。这...
浮点型数据与IEEE754标准互转是计算机科学中的一个重要话题,特别是在数值计算、图形处理和数据存储等领域。IEEE754是国际电工委员会(IEEE)制定的一套浮点数运算标准,用于规范浮点数在计算机硬件中的表示方式。这...
1. **基本数据类型与运算符**:Java提供了八种基本数据类型,包括整型(byte, short, int, long)、浮点型(float, double)以及布尔型(boolean)。在数值计算中,理解和掌握这些数据类型的范围、精度以及它们之间...
- 基本数据类型:Java的基本数据类型包括整型(int、short、byte、long)、浮点型(float、double)、字符型(char)和布尔型(boolean)。 - Unicode编码:Unicode编码使用16位bit。 - 布尔型赋值:布尔型变量只能...
一些初学JAVA的朋友可能会遇到JAVA的数据类型之间转换的苦恼,例如,整数和float,double型之间的转换,整数和String类型之间的转换,以及处理、显示时间方面的问下面笔者就开发中的一些体会介绍给大家。 我们知道,...
Number(p,s) 类型对应 Java 中的浮点型,包括 float 和 double 等。 在 Oracle 中,Date 类型对应 Java 中的 java.util.Date 和 java.sql.Date 类型。其中 java.util.Date 类型的作用范围更广泛,因此通常应用于...
- **浮点型**:`float`, `double` - **字符型**:`char` - **布尔型**:`boolean` 2. **变量与常量**:Java中可以通过使用关键字`final`来声明不可更改的常量。变量用于存储数据,可以根据需要进行更改。 3. **...
例如,整型(int)与浮点型(float/double)之间的转换。`MathUtil`类可能会提供一些静态方法,如`toInt(double value)`将双精度浮点数转换为整型,或者`toDouble(int value)`将整型转换为双精度浮点数。 2. **加法...
- **数据类型**:掌握Java中的基本数据类型(如整型int、浮点型float/double、字符型char)以及引用数据类型(如数组、类)。 - **变量与操作符**:学习变量声明与初始化,理解不同类型的变量作用域;熟悉算术、...
7. **单精度浮点型(float)到双精度浮点型(double)的转换**:这是唯一一种只涉及到浮点型数据的自动转换规则。 8. **禁止的类型转换**:有一些类型的转换是不允许的,比如从较宽类型向较窄类型转换时,如果没有显式...
float 属于 Java 中的浮点型,也叫单精度浮点型,长度为 4 字节(32bit),变量初始化默认值为 0.0f。包装类为 Float。 2. double double 属于 Java 中的浮点型,也叫双精度浮点型,长度为 8 字节(64bit),变量...