【问题标题】:Java Double Precision: Different formula leads to different result [duplicate]Java双精度:不同的公式导致不同的结果[重复]
【发布时间】:2016-11-04 13:26:43
【问题描述】:

今天我发现一个有趣的事实,即公式会影响结果的精度。请看下面的代码

double x = 7d
double y = 10d
​println(1-x/y​)
println((y-x)/y​)​

这段代码我是用groovy写的,你可以把它当成Java

结果是

1-x/y: 0.30000000000000004
(y-x)/y: 0.3

有趣的是,两个应该相等的公式有不同的结果。

  • 谁能帮我解释一下?
  • 我可以将第二个公式应用到任何适用的地方,作为双精度问题的有效解决方案吗?

【问题讨论】:

  • 尝试打印出所有的中间结果。其中一个可能略有偏差,因为它无法以 base-2 准确表示。
  • 一点也不奇怪:一个极端的例子是1-sqr(cos(x)),其中 sqr 表示平方。这在数学上等于sqr(sin(x))。现在尝试将这些公式评估为接近 0 的 x

标签: java groovy double


【解决方案1】:

要控制浮点运算的精度,您应该使用java.math.BigDecimal。 你可以这样做。

BigDecimal xBigdecimal = BigDecimal.valueOf(7d);
BigDecimal yBigdecimal = BigDecimal.valueOf(10d);
System.out.println(BigDecimal.valueOf(1).subtract(xBigdecimal.divide(yBigdecimal)));

谁能帮我解释一下?

Java 中的 float 和 double 基本类型是浮点数,其中数字存储为分数和指数的二进制表示。

更具体地说,双精度浮点值如double类型是64位值,其中:

1 位表示符号(正或负)。 11 位为指数。 有效数字为 52 位(小数部分为二进制)。 这些部分组合起来产生一个值的双重表示。

查看this

有关如何在 Java 中处理浮点值的详细说明,请遵循 Java 语言规范的浮点类型、格式和值。

byte、char、int、long 类型是定点数,是数字的精确表示。与定点数不同,浮点数有时(可以安全地假设“大部分时间”)无法返回数字的精确表示。这就是为什么在 1 - (x / y​) 的结果中最终得到 0.30000000000000004 的原因。

当需要一个精确的值(例如 1.5 或 150.1005)时,您需要使用其中一种能够精确表示数字的定点类型。

正如我已经在上面的示例中展示的那样,Java 有一个 BigDecimal 类,它可以处理非常大的数字和非常小的数字。

【讨论】:

    猜你喜欢
    • 2013-08-11
    • 1970-01-01
    • 1970-01-01
    • 2013-08-12
    • 2012-03-15
    • 1970-01-01
    • 2020-01-13
    • 2018-09-01
    • 2021-04-20
    相关资源
    最近更新 更多