【问题标题】:java floating point accuracy ( 0.1+0.2+...+1.00 ..or.. 1.00+0.99+0.98+...+0.1 )java浮点精度( 0.1+0.2+...+1.00 ..or.. 1.00+0.99+0.98+...+0.1 )
【发布时间】:2015-01-19 02:41:46
【问题描述】:

我正在准备考试,我解决了这个问题

添加 0.1+0.2+...+1.00 ..或.. 1.00+0.99+0.98+...+0.1

在 Java 中以什么顺序添加数字以获得更高的准确性?

【问题讨论】:

  • 你的意思是开始0.01 + 0.02 + ...
  • 如果你真的可以选择,那么 sum(i = 0, n, i) == n * (n+1) / 2,就是 100 * 101 / 2 / 100 == 101 / 2 == 50.5
  • 实际上,@ElliottFrisch 的结合律(除了交换律之外还需要它)不适用于浮点运算。
  • System.out.println(1.1 + 0.0001 + 0.0003 + 1.2 == 1.1 + 1.2 + 0.0001 + 0.0003); 显示为假。 @ElliottFrisch
  • 更引人注目的是,1e100 + 1 - 1e100 == 0

标签: java floating-point floating-accuracy


【解决方案1】:

任何 COBOL 程序员都能立即回答这个问题。

问题的关键在于,如果先将大数相加,则在添加小数时会失去精度。先加上小数。

【讨论】:

  • @tmyklebu - 不,它没有。在你的答案下查看我的评论。
  • @DavidWallace:是的。在我的回答下的评论下查看我的评论。
【解决方案2】:

有一个结果表明,如果以递增顺序添加一系列正数,则可以获得更好的最坏情况错误界限。这个结果并不意味着,对于给定的正数序列,将数字按升序相加会得到更小的误差。

例子:

int main() {
  float f = 0, g = 1;
  for (int i = 1; i <= 99; i++) {
    char buf[42];
    float ff;
    sprintf(buf, "0.%02i", i);
    sscanf(buf, "%f", &ff);
    f += ff;
    sprintf(buf, "0.%02i", 100-i);
    sscanf(buf, "%f", &ff);
    g += ff;
  }
  f += 1;
  printf("%a %a\n", f, g);
}

打印

0x1.940002p+5 0x1.93fffep+5

有问题的 100 个 floats 的确切总和是 0x1.93ffffff8p+5 ,表示这里以递减的顺序求和获胜。

【讨论】:

  • 我正要投票赞成这个答案,以指出最坏情况下的错误界限和实际错误之间的区别。但后来我到了最后一段,决定不这样做。您无法通过将fg 声明为double 来获得准确的结果。使用double 和使用float 存在完全相同类型的错误——它们只是更小。在这种情况下,正确答案是50.5 = 0x1.94p+5,您可以使用铅笔和纸或算盘来计算,但不能使用double。因此,如果两个加法给出0x1.940002p+50x1.93fffep+5,那么它们相等 ...
  • ... 不准确 - 每次计算的误差完全相同。
  • @DavidWallace:阅读代码。所有的和都是大于 2^(-40) 的 2 的幂的倍数。所以是的,您可以通过将fg 声明为double 来获得确切的答案。这 100 个 floats 的确切总和是我给出的数字,它小于 0x1.94p5
  • 是的,但问题不在于添加floats。 float 的可表示性与 OP 的要求完全无关。
  • @tmyklebu 是的,同意,对不起,我的观点是,浮点数的精确总和近似于分数 i/100 小于精确分数总和的 1/2ulp我/100。
【解决方案3】:

由于这是一个算术级数,它的和可以计算如下

Sn = n * (a1 + an) / 2

Sn ... sum
n  ... number of elements
a1 ... first element
an ... last element

当您消除大部分数字时,这似乎是最好的解决方案。

【讨论】:

  • 这是真的,但它实际上并没有回答这个问题。 OP 有两个选项可供选择 - 这不是其中之一。
  • 你是对的。所有人都为我们的学校系统欢呼。
  • 你在考试时问过这个?还是之后?
  • 呃...0.1 + 0.2 ... + 0.98 + 0.99 + 1.00 不是我所知道的算术级数。如果数字是0.01 + 0.02 + ... 0.99 + 1.00,就会是这样。
【解决方案4】:

比将所有数字线性相加更好,您应该研究一种分治法(分别对数组的一半求和)。

这很像Precise sum of floating point numbers

【讨论】:

    猜你喜欢
    • 2013-03-10
    • 2021-11-04
    • 2020-10-24
    • 2011-10-16
    • 2020-02-15
    • 1970-01-01
    • 2014-05-05
    • 1970-01-01
    相关资源
    最近更新 更多