【问题标题】:Comparing "0.1" to .1将“0.1”与 0.1 进行比较
【发布时间】:2015-05-31 23:59:47
【问题描述】:

我正在努力了解 double 的局限性。 0.1 不能在有限系统中表示,因为它是重复的二进制值。但是,当我声明一个变量并给它 0.1 时,它仍然打印为 0.1 和 not .0999999999999999、1.000000000000001 或类似的东西。但是,如果我添加一个 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);

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

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

".1" == .1?预期答案:否。

我正在尝试的比较是

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

任何帮助理解为什么这不能区分可以和不能用双精度表示的值。

【问题讨论】:

  • 你确定BigInteger在这里是正确的吗?还有,为什么不直接支持dBigDecimal构造函数呢?
  • 你是对的,它应该是 BigDecimal。我只是想获取相关的代码并犯了那个错误。我在问题中更正了它。

标签: java string double


【解决方案1】:

要测试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
}

之所以有效,是因为new BigDecimal(s) 产生的BigDecimalString 所表示的值完全相等,而new BigDecimal(Double.parseDouble(s)) 是与该值最接近double 的精确值.

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

当你这样做时

double d = 0.1;
System.out.println(d);

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

System.out.println(d + d + d + d + d + d + d + d + d + d);

您看到的是0.9999999999999999 而不是1。您看不到1 的原因是因为有double 值比答案更接近1(实际上一个是double 值本身)。没有理由为什么答案应该是最接近的double,因为首先d 并不是真正的0.1(它只是接近它),并且无论如何当你添加浮点引入了不准确的数字。

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

【讨论】:

  • “最后,number.compareTo(new BigDecimal(Double.toString(d))) == 0 不起作用,因为” 你无法将 BigIntegerBigDecimal :)。但你可能是对的,如果 OP 会读取编译器错误并改用 number = new BigDecimal("0.1");
  • @Tom 很好。我没有注意到问题中提到了BigInteger
  • 感谢您的帮助。我确实在最初的问题中不小心使用了 BigInteger。我已经编辑过了。感谢您的帮助。我以前从未使用过Bigs,我正试图让他们失望。我有点惊讶他们没有内置 Math 类函数。
  • @TomK 他们有一些基本的东西,比如#abs#devide#multiply#plus#pow#subtract
  • @TomK Math 中的许多方法在BigDecimal 中实际上没有任何意义。 BigDecimal 用于精确计算,例如财务计算。它并不真正适用于高级数学。你甚至不能用BigDecimal 来表示像三分之一这样的简单分数,更不用说立方根或三角比了。你需要一个专门的图书馆来处理这种事情。
猜你喜欢
  • 2018-10-04
  • 2013-03-10
  • 2020-02-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-09
  • 1970-01-01
相关资源
最近更新 更多