比较 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 转换为双精度的固有舍入误差,乘法方法可能无法获得最接近精确除法结果的结果。
哪个表达更准确,为什么?我认为如果它不是 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 转换为双精度的固有舍入误差,乘法方法可能无法获得最接近精确除法结果的结果。