0

到目前为止,我的直觉是一组数字的总和与它们相加的顺序无关。下面,随机数的集合是由seed=0决定的,但是顺序是由线程中的执行顺序决定的。

我想使用来自多线程计算的大量双精度数的总和作为校验和。有没有办法找到一个对总和中的组成数字最敏感但对特定随机加法序列不敏感的和的舍入方案?

import java.io.IOException;
import java.util.ArrayList;
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class Test implements Callable<Double> {

    public static class Sum {

        double sum = 0;

        public synchronized void add(double val) {
            sum += val;
        }

        public double getSum() {
            return sum;
        }
    };
    Sum sum;

    public Test(Sum sum) {
        this.sum = sum;
    }

    @Override
    public Double call() {
        Random rand = new Random(0);
        for (long i = 0; i < 1000000L; i++) {
            sum.add(rand.nextDouble());
        }
        return 0D;
    }

    static double mean() {
        Sum sum = new Sum();
        int cores = Runtime.getRuntime().availableProcessors();
        ExecutorService pool = Executors.newFixedThreadPool(cores);
        ArrayList<Future<Double>> results = new ArrayList<>();
        double x = 0;
        for (int i = 0; i < cores; i++) {
            Test test = new Test(sum);
            results.add(pool.submit(test));
        }

        for (Future<Double> entry : results) {
            try {
                x += entry.get();
            } catch (InterruptedException ex) {
                throw new RuntimeException("Thread interrupted.", ex);
            } catch (ExecutionException ex) {
                throw new RuntimeException("Excecution exception:");
            }
        }

        pool.shutdown();

        return sum.getSum();
    }

    public static void main(String[] args) throws IOException {
        for (int i = 0; i < 10; i++) {
            System.out.format("Avg:%22.20f\n", mean());
        }
    }
}
4

3 回答 3

4

假设您的数据结构已正确同步,则顺序不应影响最终总和,前提是操作是可交换的。

换句话说,只要a + b与 相同b + a

浮点数并非总是如此,因为它们毕竟是您想要的数字的近似值。

添加两个数字(ab以上)可能是可交换的,但是当数字的数量变大时它会变得更加复杂。

例如,如果您将可能的最小数字添加到(相对)较大的数字中,那么您只有一定精度的事实意味着您最终会得到更大的数字,例如:

      -20
1 + 10     => 1

因此,如果您添加很多次(准确地说是 10 20),您仍然会得到:10-2011

      -20    -20    -20        -20    -20    -20
1 + 10   + 10   + 10   ... + 10   + 10   + 10      => 1
    \__________________________________________/
                      20
                    10   of these

但是,如果您首先将所有这些值加在一起,您将得到(a),然后添加到该值将给您:10-201 12

  -20    -20    -20        -20    -20    -20
10   + 10   + 10   ... + 10   + 10   + 10    + 1   => 2
\__________________________________________/
                  20
                10   of these

(a)这不一定完全正确,因为一旦累积量变得足够大,以至于该值对其产生零影响,累积量就会停止增加。10-20

但是,它不会出现在累计金额为零的地方,因此您应该会看到最终总和的差异。

于 2013-05-21T01:39:56.250 回答
1

同步方法应该处理线程问题。所以这甚至应该发生在一个“核心”上。

我可以想象,由于舍入误差的不同影响,添加双打的工作方式因顺序而异。

例如,BIG + 1 可能与 BIG + 2 相同,这违反了基本的算术合理性。这对你来说是浮点数。

于 2013-05-21T01:39:14.953 回答
1

如果要添加大小差异很大的双精度数,则应首先按绝对值对它们进行排序,然后从最小值开始。

于 2013-05-21T01:47:20.810 回答