生成病态数据以测试浮点求和

时间:2011-07-06 20:13:36

标签: java floating-point

我在Java中实现了Kahan floating point summation algorithm。我想将它与Java中的内置浮点加法和Mathematica中的无限精度加法进行比较。但是我的数据集不适合测试,因为数字彼此接近。 (条件号〜= 1)

在我的数据集上运行Kahan会得到与内置+最相同的结果。

有人可以建议如何生成大量可能导致严重舍入错误的数据吗?

5 个答案:

答案 0 :(得分:1)

  

然而,我所拥有的数据集不适合测试,因为数字彼此接近。

听起来你已经知道问题是什么了。得到它=)

您需要一些东西:

  • 数量大不相同的数量,因此较小数字的大部分精度会因天真的总和而丢失。
  • 具有不同符号和几乎相等(或相等)幅度的数字,以便发生灾难性的取消。
  • 设置了一些低位的数字,以增加舍入的效果。

为了让你开始,你可以尝试一些简单的三项和,这应该清楚地显示效果:

1.0 + 1.0e-20 - 1.0

通过简单求和进行评估,这将给出0.0;明显不正确。您还可以查看表单的总和:

a0 + a1 + a2 + ... + an - b

b是天真评估的总和a0 + ... + an

答案 1 :(得分:0)

你想要一堆高精度数字吗?试试这个:

double[] nums = new double[SIZE];
for (int i = 0; i < SIZE; i++)
    nums[i] = Math.rand();

答案 2 :(得分:0)

我们是在谈论数字对还是序列?

如果成对,则从两个数字的1开始,然后在每次迭代中将1除以3​​,将另一个乘以3.可以很容易地计算这些对的理论总和,并且您将获得一大堆舍入误差。 (一些来自分部,一些来自加法。如果你不想要除法错误,那么用2而不是3。)

答案 3 :(得分:0)

通过实验,我发现了以下模式:

public static void main(String[] args) {
    System.out.println(1.0 / 3 - 0.01 / 3);

    System.out.println(1.0 / 7 - 0.01 / 7);

    System.out.println(1.0 / 9 - 0.001 / 9);
}

我减去了素数的近似负幂(它不应该具有二进制形式的精确表示)。但是,有些情况下,这样的表达式会正确评估,例如

    System.out.println(1.0 / 9 - 0.01 / 9);

你可以通过迭代减数的幂来自动化这种方法,并在乘以适当的值时停止产生整数,例如:

    System.out.println((1.0 / 9 - 0.001 / 9) * 9000);
    if (1000 - (1.0 / 9 - 0.001 / 9) * 9000 > 1.0)
        System.out.println("Found it!");

答案 4 :(得分:0)

Scalacheck可能适合您。这是一个简短的样本:

cat DoubleSpecification.scala
import org.scalacheck._

object DoubleSpecification extends Properties ("Doubles") {
        /* 
            (a/1000 + b/1000) = (a+b) / 1000
            (a/x    + b/x   ) = (a+b) / x
        */
        property ("distributive") = Prop.forAll { (a: Int, b: Int, c: Int) => 
            (c == 0 || a*1.0/c + b*1.0/c == (a+b) * 1.0 / c)            }
}       

object Runner { 
    def main (args: Array[String]) {
        DoubleSpecification.check
        println ("...done")
    }
}

要运行它,你需要scala和schalacheck-jar。我使用的是2.8版本(我不必说,你的c-path会有所不同):

 scalac -cp /opt/scala/lib/scalacheck.jar:. DoubleSpecification.scala 
 scala -cp /opt/scala/lib/scalacheck.jar:. DoubleSpecification
! Doubles.distributive: Falsified after 6 passed tests.                       
> ARG_0: 28 (orig arg: 1030341)
> ARG_1: 9 (orig arg: 2147483647)
> ARG_2: 5

Scalacheck采用一些随机值(orig args)并尝试简化这些,如果测试失败,以便找到简单的例子。