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计算精度问题的更多相关文章

  1. java中int,float,long,double取值范围,内存泄露

    java中int,float,long,double取值范围是多少? 写道 public class TestOutOfBound { public static void main(String[] ...

  2. MySQL中 DECIMAL FLOAT DOUBLE的区别

    第一篇文章: MySQL中Decimal类型和Float Double等区别 MySQL中存在float,double等非标准数据类型,也有decimal这种标准数据类型. 其区别在于,float,d ...

  3. Java中long和double的原子性

    Java中long和double的原子性 java中基本类型中,long和double的长度都是8个字节,32位(4字节)处理器对其读写操作无法一次完成,那么,JVM,long和double是原子性的 ...

  4. Java中String转换Double类型 Java小数点后留两位

    Java中String转换Double类型 double num1 = 0.0; String qq = "19.987"; num1 = Double.valueOf(qq.to ...

  5. 在JAVA中怎么比较Double类型数据的大小

    在JAVA中怎么比较Double类型数据的大小  我来答  浏览 33044 次   3个回答 #活动# “双11”答题活动,奖励加码!最高得2000元购物礼金! pollutedair 2015- ...

  6. Java中的浮点型(Double&Float)计算问题

    在刚刚做完的一个项目中,遇到了double型计算不精确的问题.到网上查找后,问题得到解决.经验共享,在这里总结一下. Java中的浮点数类型float和double不能够进行精确运算.这个问题有时候非 ...

  7. JAVA中使用浮点数类型计算时,计算精度的问题

    标题     在Java中实现浮点数的精确计算    AYellow(原作) 修改    关键字     Java 浮点数 精确计算   问题的提出:如果我们编译运行下面这个程序会看到什么?publi ...

  8. C#中float, double的精度问题

    在工作中我发现了一个C#浮点数的精度问题,以下的程序运行结果并未得到我预期的结果: view source print? 01 namespace FloatTest 02 03     class ...

  9. 关于c中 int, float, double转换中存在的精度损失问题

    先看一段代码实验: #include<limits> #include<iostream> using namespace std; int main() { unsigned ...

随机推荐

  1. 记一次phoenix在不加索引的情况调优,由6s以上时间变成不到1s

    背景: 网约车预约单查询: 这里面恶心的地方是: 1个时间窗口要查询6种时间:推送订单时间(来自mongodb).有效抢单时间(来自mongodb).抢单成功时间(实时kafka).取消订单时间(实时 ...

  2. spring事务之事务传播机制和隔离级别

    Spring事务传播行为 运用Spring事务,必须要深入理解它的传播机制,否则会遇到各种意想不到的坑,Spring定义了七种传播行为. public interface TransactionDef ...

  3. shell脚本编程进阶

    在linux shell中,通常我们将一些命令写在一个文件中就算是一个shell脚本了,但是如果需要执行更为复杂的逻辑判断,我们就需要使用流程控制语句来支持了.所谓流程控制既是通过使用流程控制语句对程 ...

  4. legend3---15、像粉丝数、关注数、课程数等数量数据如何处理

    legend3---15.像粉丝数.关注数.课程数等数量数据如何处理 一.总结 一句话总结: 在主表中加入这种数量字段:比如在用户表中加入粉丝数,关注数字段 普通更新:增加数量的时候将数据插入到关联表 ...

  5. R语言:各类型数据文件的导入

    导入csv: read.csv() 导入txt: read.table() 注意,txt文件编码为unicode的导入r会报错,需转换成ANSI 读入excel:需要安装xlsx包,安装此包前先下载好 ...

  6. Kbengine游戏引擎-【4】demo-kbengine_unity3d_demo 在容器docker上安装测试

    git地址:https://github.com/kbengine/kbengine_unity3d_demo Demo中文地址:https://github.com/kbengine/kbengin ...

  7. LC 873. Length of Longest Fibonacci Subsequence

    A sequence X_1, X_2, ..., X_n is fibonacci-like if: n >= 3 X_i + X_{i+1} = X_{i+2} for all i + 2 ...

  8. vuex中的babel编译mapGetters/mapActions报错解决方法

    vex使用...mapActions报错解决办法 vuex2增加了mapGetters和mapActions的方法,借助stage2的Object Rest Operator 所在通过 methods ...

  9. Android的内部存储

    路径:/data/data/包名/ this.getCacheDir() = /data/data/com.example.qq/cache/ getFilesDir() = /data/data/c ...

  10. rally使用tempest进行测试

    安装 通过Rally进行Tempest测试,执行如下命令创建tempest实例,Rally会自动同步tempest代码至本地: rally verify create-verifier --name ...