比较 x*0.1 和 x/10.0 计算浮点数的精度

comparing accuracy for calculating floating point with x*0.1 and x/10.0

哪个表达更准确,为什么?我认为如果它不是 10.0 并且它是某个整数 k 的 2^k,那么我们只需要在指数中减去 k。但是有10个,我想不出比较它们的方法...

计算完全可以在java的BigDecimal中完成。所有有限双精度数都精确转换为 BigDecimal。基于这两种思路,可以对两种方法进行比较:

import java.math.BigDecimal;
import java.util.Random;

public class Test {
  public static void main(String[] main) {
    testDivide(1);
    testDivide(10);
    testDivide(1e6);
    Random rand = new Random(3);
    for(int i=0;i<1000000;i++){
      testDivide(rand.nextDouble());
    }
    System.out.println("Equal results: "+equals);
    System.out.println("Divide by 10 better: "+divBetter);
    System.out.println("Multiply by 0.1 better: "+multBetter);
  }

  private static int equals;
  private static int divBetter;
  private static int multBetter;

  public static void testDivide(double x) {
    BigDecimal tenth = new BigDecimal("0.1");
    double mult = x * 0.1;
    double div = x / 10;
    BigDecimal exact = new BigDecimal(x).multiply(tenth);
    BigDecimal multError = exact.subtract(new BigDecimal(mult)).abs();
    BigDecimal divError = exact.subtract(new BigDecimal(div)).abs();
    int comparison = divError.compareTo(multError);
    if(comparison == 0){
      equals++;
    } else if(comparison < 0){
      divBetter++;
    } else {
      multBetter++;
    }
  }
}

我得到了:

Equal results: 649781
Divide by 10 better: 350222
Multiply by 0.1 better: 0

正如@njuffa 的评论中所暗示的,乘法再好不过了。 10 可以精确地表示为双精度数,需要除以产生最接近实数除法结果的可表示数。由于将 0.1 转换为双精度的固有舍入误差,乘法方法可能无法获得最接近精确除法结果的结果。