将"0.1"与.1进行比较

Tom*_*m K 5 java string double

我正在努力理解double的局限性.0.1不能在有限系统中表示,因为它是重复的二进制值.但是,当我声明一个变量并给它0.1时,它仍然打印为0.1而不是 .0999999999999999,1.00000000000000001或类似的东西.但是,如果我添加一个具有0.1十次的变量,那么它将出现在.9999999999999999中,这正是我所期望的.

真正的问题是,当我知道这是不可能的时候,为什么打印精确到0.1,我有证据证明这不是真正的价值?

double d  = 0.1;
System.out.printf("%.16f\n",d);
System.out.printf("%.16f", d + d + d + d + d + d + d + d + d + d);
Run Code Online (Sandbox Code Playgroud)

我想要做的是将字符串文字与双重转换进行比较,以查看字符串中的值是否可以用double精确表示.例如:

".5"== .5?预期答案:是的.

".1"== .1?预期答案:没有.

我正在尝试的比较是

number = new BigDecimal("0.1");
d = number.doubleValue();
if (number.compareTo(new BigDecimal(Double.toString(d))) == 0){
    // Doing something
}
Run Code Online (Sandbox Code Playgroud)

任何帮助理解为什么这不区分可以和不能用double表示的值将是值得赞赏的.

Pau*_*ton 4

要测试 a 是否String代表一个double值,您可以这样做:

private static boolean isADouble(String s) {
    return new BigDecimal(s).equals(new BigDecimal(Double.parseDouble(s)));
}

public static void main(String[] args) {
    System.out.println(isADouble("0.1"));  // false
    System.out.println(isADouble("0.5"));  // true
}
Run Code Online (Sandbox Code Playgroud)

这是有效的,因为new BigDecimal(s)产生的BigDecimal值完全等于 所表示的值String,而是最接近new BigDecimal(Double.parseDouble(s))该值的精确值。 double

我会在最后解释为什么number.compareTo(new BigDecimal(Double.toString(d))) == 0不起作用。

当你这样做时

double d = 0.1;
System.out.println(d);
Run Code Online (Sandbox Code Playgroud)

你得到答案是0.1因为d它最接近double“真实” 0.1。(double d = 0.1; 意思是d最接近double0.1。当你写

System.out.println(d + d + d + d + d + d + d + d + d + d);
Run Code Online (Sandbox Code Playgroud)

你看0.9999999999999999而不是1。您看不到的原因1是因为存在double比答案更接近 1 的值(实际上 1double本身就是一个值)。没有理由为什么答案应该是最接近的double,因为d并不是真正的0.1答案(它只是接近它),并且在任何情况下,当您添加浮点数时都会引入不准确的情况。

最后,number.compareTo(new BigDecimal(Double.toString(d))) == 0不起作用,因为即使number.doubleValue()完全,仍然将其转换为0.1,因为没有更接近“真实”的值。Double.toString()String "0.1"double0.1