繁体   English   中英

双减法精度问题

[英]Double subtraction precision issue

我的同事做了这个实验:

public class DoubleDemo {

      public static void main(String[] args) {
           double a = 1.435;
           double b = 1.43;
           double c = a - b;
           System.out.println(c);
      }
 }

对于这个一年级的操作,我期望这个输出:

0.005

但出乎意料的是,输出是:

0.0050000000000001155

这么简单的操作,为什么double会失败? 如果 double 不是这项工作的数据类型,我应该使用什么?

double在内部存储为二进制的分数——比如1/4 + 1/8 + 1/16 + ...

0.005 -- 或值1.435 -- 不能存储为二进制的精确分数,因此double不能存储精确值0.005 ,并且减去的值不是很精确。

如果您关心精确的十进制算术,请使用BigDecimal

您可能还会发现 这篇文章很有用。

double 和 float不完全是实数

在任何范围内都有无限数量的实数,但只有有限数量的位来表示它们! 出于这个原因,双精度和浮点数预计会出现舍入误差。

您得到的数字是最接近的数字,可以用浮点表示中的 double 表示。

有关更多详细信息,您可能需要阅读 这篇文章[警告:可能是高级别的]。

您可能想要使用BigDecimal来精确地获得一个十进制数 [但是当您尝试获得1/3时,您将再次遇到舍入错误]。

由于“幕后”发生的舍入, doublefloat算法永远不会完全正确。

本质上双精度和浮点数可以有无限数量的小数,但在内存中它们必须由一些实数表示。 因此,当您执行此十进制算术时,会发生舍入过程,并且如果您将所有小数都考虑在内,通常会偏离很小的数量。

如前所述,如果您需要完全精确的值,则使用BigDecimal以不同方式存储其值。 这是 API

是的,它使用 BigDecimal 操作以这种方式工作

private static void subtractUsingBigDecimalOperation(double a, double b) {
  BigDecimal c = BigDecimal.valueOf(a).subtract(BigDecimal.valueOf(b));
  System.out.println(c);
}

在此处输入图片说明

public class BigDecimalExample {

    public static void main(String args[]) throws IOException {

      //floating point calculation
      double amount1 = 2.15;
      double amount2 = 1.10;
      System.out.println("difference between 2.15 and 1.0 using double is: " + (amount1 - amount2));

      //Use BigDecimal for financial calculation
      BigDecimal amount3 = new BigDecimal("2.15");
      BigDecimal amount4 = new BigDecimal("1.10") ;
      System.out.println("difference between 2.15 and 1.0 using BigDecimal is: " + (amount3.subtract(amount4)));       
    }      
}

输出

使用 double 的 2.15 和 1.0 之间的差异是:1.0499999999999998 使用 BigDecmial 的 2.15 和 1.0 之间的差异是:1.05

 //just try to make a quick example to make b to have the same precision as a has, by using BigDecimal

 private double getDesiredPrecision(Double a, Double b){
     String[] splitter = a.toString().split("\\.");
     splitter[0].length();   // Before Decimal Count
     int numDecimals = splitter[1].length(); //After Decimal Count

     BigDecimal bBigDecimal = new BigDecimal(b);
     bBigDecimal = bBigDecimal.setScale(numDecimals,BigDecimal.ROUND_HALF_EVEN);

     return bBigDecimal.doubleValue();  
 }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM