Java中的float、double计算精度问题
java中的float、double计算存在精度问题,这不仅仅在java会出现,在其他语言中也会存在,其原因是出在IEEE 754标准上。
而java对此提供了一个用于浮点型计算的类——BigDecimal(java.math.BigDecimal),通过将double替换成BigDecimal进行计算可以获得较为精确的计算结果。
BigDecimal的构造方法有许多,在此推荐使用BigDecimal(String val)的构造方法,通过String字符串进行构造。可能会有人直接使用BigDecimal(double val)去构造,但为什么推荐要使用String而不用double直接构造?原因如BigDecimal(double val)前的注释所说:
Translates a {@code double} into a {@code BigDecimal} which is the exact decimal representation of the {@code double}'s binary floating-point value. The scale of the returned {@code BigDecimal} is the smallest value such that (10 scale val) is an integer.
Notes: The results of this constructor can be somewhat unpredictable. One might assume that writing {@code new BigDecimal(0.1)} in Java creates a {@code BigDecimal} which is exactly equal to 0.1 (an unscaled value of 1, with a scale of 1), but it is actually equal to 0.1000000000000000055511151231257827021181583404541015625.This is because 0.1 cannot be represented exactly as a {@code double} (or, for that matter, as a binary fraction of any finite length). Thus, the value that is being passed in to the constructor is not exactly equal to 0.1, appearances notwithstanding.
The {@code String} constructor, on the other hand, is perfectly predictable: writing {@code new BigDecimal("0.1")} creates a {@code BigDecimal} which is exactly equal to 0.1, as one would expect. Therefore, it is generally recommended that the {@linkplain #BigDecimal(String) String constructor} be used in preference to this one.
When a {@code double} must be used as a source for a {@code BigDecimal}, note that this constructor provides an exact conversion; it does not give the same result as converting the {@code double} to a {@code String} using the {@link Double#toString(double)} method and then using the {@link #BigDecimal(String)} constructor. To get that result, use the {@code static} {@link #valueOf(double)} method.
balabala的一大段?挑出重点看,Notes(说明):The results of this constructor can be somewhat unpredictable(这个结果可能是不可预测的)。原因在后面一句话也说了,若用 0.1 new一个BigDecimal,则它实际上是等于0.1000000000000000055511151231257827021181583404541015625,原因无需细看,跳过。
The {@code String} constructor, on the other hand, is perfectly predictable(通过字符串构造,是可以完全预测的)。到此注释说的差不多了。
而BigDecimal中一系列的add、subtract等方法对应着加减乘除就不必多说。
到这里就结束了吗?不,如果单纯的将double替换成BigDecimal,就会大幅降低程序的运行速度,因此需要进行一定的优化:非替换,而是改进。
依旧用double定义、储存数据,但计算时,使用BigDecimal进行计算(若需要精确的计算),最后只需.doubleValue()即可得到较为精确的double类型的计算结果了。
由此可以编写一个用于浮点型计算的工具类,专职浮点型计算工作。
import java.math.BigDecimal; /**
* 浮点型较为精确计算工具类
*/
public class CalculateUtil {
/**
* 私有构造
*/
private CalculateUtil(){}
/**
* 加法运算
* @param num1 被加数
* @param num2 加数
* @return 两数之和
*/
public static double add(double num1, double num2){
BigDecimal b1 = new BigDecimal(Double.toString(num1));
BigDecimal b2 = new BigDecimal(Double.toString(num2));
return b1.add(b2).doubleValue();
}
/**
* 减法运算
* @param num1 被减数
* @param num2 减数
* @return 两数之差
*/
public static double sub(double num1, double num2){
BigDecimal b1 = new BigDecimal(Double.toString(num1));
BigDecimal b2 = new BigDecimal(Double.toString(num2));
return b1.subtract(b2).doubleValue();
}
/**
* 乘法运算
* @param num1 被乘数
* @param num2 乘数
* @return 两数之积
*/
public static double mul(double num1, double num2){
BigDecimal b1 = new BigDecimal(Double.toString(num1));
BigDecimal b2 = new BigDecimal(Double.toString(num2));
return b1.multiply(b2).doubleValue();
}
/**
* 除法运算(小数点后10位)
* @param num1 被除数
* @param num2 除数
* @return 两数之商
*/
public static double div(double num1, double num2){
return div(num1, num2, 10);
} /**
* 除法运算
* @param num1 被除数
* @param num2 除数
* @param scale 小数点后精度位数
* @return 两数之商
*/
public static double div(double num1, double num2, int scale){
if(scale<0)
throw new IllegalArgumentException("The scale must be a positive integer or zero");
BigDecimal b1 = new BigDecimal(Double.toString(num1));
BigDecimal b2 = new BigDecimal(Double.toString(num2));
return b1.divide(b2, scale, BigDecimal.ROUND_HALF_UP).doubleValue();
}
/**
* 四舍五入
* @param num 需要四舍五入的数
* @param scale 小数点后精度位数
* @return 四舍五入值
*/
public static double round(double num, int scale){
if(scale<0)
throw new IllegalArgumentException("The scale must be a positive integer or zero");
BigDecimal b1 = new BigDecimal(Double.toString(num));
return b1.divide(new BigDecimal("1"), scale, BigDecimal.ROUND_HALF_UP).doubleValue();
} }
Java中的float、double计算精度问题的更多相关文章
- java中int,float,long,double取值范围,内存泄露
java中int,float,long,double取值范围是多少? 写道 public class TestOutOfBound { public static void main(String[] ...
- MySQL中 DECIMAL FLOAT DOUBLE的区别
第一篇文章: MySQL中Decimal类型和Float Double等区别 MySQL中存在float,double等非标准数据类型,也有decimal这种标准数据类型. 其区别在于,float,d ...
- Java中long和double的原子性
Java中long和double的原子性 java中基本类型中,long和double的长度都是8个字节,32位(4字节)处理器对其读写操作无法一次完成,那么,JVM,long和double是原子性的 ...
- Java中String转换Double类型 Java小数点后留两位
Java中String转换Double类型 double num1 = 0.0; String qq = "19.987"; num1 = Double.valueOf(qq.to ...
- 在JAVA中怎么比较Double类型数据的大小
在JAVA中怎么比较Double类型数据的大小 我来答 浏览 33044 次 3个回答 #活动# “双11”答题活动,奖励加码!最高得2000元购物礼金! pollutedair 2015- ...
- Java中的浮点型(Double&Float)计算问题
在刚刚做完的一个项目中,遇到了double型计算不精确的问题.到网上查找后,问题得到解决.经验共享,在这里总结一下. Java中的浮点数类型float和double不能够进行精确运算.这个问题有时候非 ...
- JAVA中使用浮点数类型计算时,计算精度的问题
标题 在Java中实现浮点数的精确计算 AYellow(原作) 修改 关键字 Java 浮点数 精确计算 问题的提出:如果我们编译运行下面这个程序会看到什么?publi ...
- C#中float, double的精度问题
在工作中我发现了一个C#浮点数的精度问题,以下的程序运行结果并未得到我预期的结果: view source print? 01 namespace FloatTest 02 03 class ...
- 关于c中 int, float, double转换中存在的精度损失问题
先看一段代码实验: #include<limits> #include<iostream> using namespace std; int main() { unsigned ...
随机推荐
- 2016 ACM-ICPC NEERC F. Foreign Postcards (概率DP)
2016 ACM-ICPC NEERC F. Foreign Postcards 题意:有一串由C.W组成的字符串,每次截取长度为k(1<=k<=n且k随机)的前缀,如果该前缀首位为W,则 ...
- 【洛谷4001】 [ICPC-Beijing 2006]狼抓兔子(最小割)
传送门 洛谷 Solution 直接跑最小割板子就好了. 代码实现 #include<stdio.h> #include<stdlib.h> #include<strin ...
- OpenDayLight安装Features
OpenDayLight 0.4.4-Beryllium-SR4 opendaylight-user@root>feature:install odl-restconf opendaylight ...
- VMware Workstation 与 Device/Credential Guard 不兼容
之前在本机搭建Docker for Windows的时候,启用了win10自带的虚拟Hyper-V,但是win10的虚拟与VMware Workstation的虚拟有冲突,运行VMware Works ...
- Phos 技术服务支持
Phos Mail: tencenter@163.com
- 前端知识点回顾之重点篇——CSS中vertical align属性
来源:https://www.cnblogs.com/shuiyi/p/5597187.html 行框的概念 红色(line-height)为行框的顶部和底部,绿色(font-size)为字体的高度, ...
- ExcelUtility 对excel的序列化与反序列化,支持当单元格中数据为空时将属性赋值为指定类型的默认值
源码https://github.com/leoparddne/EPPlusHelper 安装: Install-Package ExcelUtility -Version 1.1.4 需要为对象添加 ...
- 小D课堂 - 新版本微服务springcloud+Docker教程_4-02 微服务调用方式之ribbon实战 订单调用商品服务
笔记 2.微服务调用方式之ribbon实战 订单调用商品服务 简介:实战电商项目 订单服务 调用商品服务获取商品信息 1.创建order_service项目 2 ...
- 一百一十六:CMS系统之使用阿里大于sdk发送短信验证码
阿里大于短信平台:https://dysms.console.aliyun.com/dysms.htm#/overview 使用教程:https://blog.csdn.net/qq103189393 ...
- Delphi7-TClientDataSet: 查找
TClientDataSet[12]: 查找 方法有:1.Locate: 根据字段列表和对应的字段值查找并定位, 找到返回 True.2.Lookup: 根据字段列表和对应的字段值查找, 返回需要的字 ...