2010-11-04 104 views
3

我有一个double []巨大的尺寸。 (例如:例如:double[] array = new double[] {2.0, 3.1, 4.2, 8.9, 10.11, ........}在java中不使用循环添加double []数组的元素

我想一次获得该数组的所有元素的总和。 (不使用循环)

你有什么想法做到这一点吗?

+0

你想在double array中添加元素但是从哪里获得这些值?你能否说清楚 – 2010-11-04 07:32:16

+0

什么是双数组?你的意思是一个二维数组?你的元素类型是什么? – 2010-11-04 07:33:18

+0

你是什么意思的“双阵”?一个双打数组''double []'?或者其他一些结构?你想要添加什么元素?你能否在你的问题中增加更多信息? – Guillaume 2010-11-04 07:34:30

回答

9

不,您无法一步计算值列表的总和。即使有API方法或某个提供sum函数的库,它也会在内部使用循环。求和算法的复杂度为O(n)(对于单个CPU)。

出路可能是使用并行计算,但这是一个理论方法来回答你的问题。您至少需要与数组单元一样多的CPU来逐步计算总和。 (或者一个具有与阵列值一样多的FP寄存器的虚构CPU)。


开始之前看的Java API的或其他库:

public static double sum(double...values) { 
    double result = 0; 
    for (double value:values) 
    result += value; 
    return result; 
} 

用法:

double sum = sum(array); // this is in your main code -> no loop (visible) 
+0

谢谢,Andreas_D。我会通过他们 – Namalak 2010-11-04 08:09:35

+1

实际上算法的复杂性是O(n)即使对于多个CPU :-) – paxdiablo 2010-11-04 09:17:55

+0

@paxdiabolo - 我敢打赌O(log n)是可能的,O(1)也许不是。考虑在第一步中添加n/2个值对,然后(n/2)/ 2对总和等等。 (并行处理) – 2010-11-04 09:21:16

9

是的,使用循环。这就是他们的目的。数百个元素对于一个数组来说是一个小小的尺寸,并且几乎没有时间处理。

4

首先, '数百名' 不是 '巨大的'(“百万'是),第二,添加没有循环的元素是不可能的,除非你有一些关于元素的先前信息(比如它们是否是特定系列的一部分)。

+0

这是真的。以前,我只是用了一个词“百”。我知道这可以通过使用循环来完成。任何方式,我想知道的是如何获得双数组的总和,而不使用循环。 – Namalak 2010-11-04 08:04:40

+0

其实数百万这些天也不是很大。数十亿是巨大的。 – 2010-11-04 19:29:40

+0

总结一个百万双倍需要〜0.003秒。 :D – 2010-11-04 19:48:03

1

任何拥有大量双打数组的人都可能会查找cern.colt.list.AbstractDoubleList,它是为优化诸如添加(元素)等操作而构建的。正如其他人所说,如果你想要数组中所有元素的总和,你应该写一个循环。

+0

这种“DoubleList”类没有办法比直接遍历数组并添加元素更快,除非它是以本地代码的形式实现的(它不是)。 – Grodriguez 2010-11-04 08:05:12

+0

我同意,如果你愿意专门使用原始数组。如果你想要像List对象那样的东西,那么我提到的包做的很好(我用它来洗一个大的数组)。 – 2010-11-04 18:34:30

2

循环是最简单和最有效的方法,用于在Java中对数组或集合中的元素进行求和。

有几种方法可以对不涉及显式循环的数组进行求和,但它们涉及使用模拟的高阶函数,并且在使用Java编写时它们很复杂且很难看。 (而且它们很贵,并且在引擎盖下使用循环。)

Java不是一种函数式编程语言。如果您想/需要在Java平台上进行功能编程,请使用Scala或Clojure。

1

环流式是这个最简单的方法,但既然你问了一个不同:

递归:

double sumResult = sum(data, 0, 0); 

double sum(double [] d, int sum, int index) { 
    if (index > d.length) return sum; 
    else return sum(d, sum + d[index], index+1); 
} 

我没有测试过这一点,但它应该沿着上述地方工作。

编辑:它不建议使用这样的构造,因为对于巨大的数组,你可能会非常快地击中StackOverflowException。

+0

开箱即用的思维。但我不确定我会推荐在实际项目中使用它;-) – Guillaume 2010-11-04 08:25:22

+0

它应该是'd.length' ...不是'double.length' – st0le 2010-11-04 08:43:31

+0

我知道您正在尝试执行尾部呼叫优化,bt AFAIK,java不支持它....所以这可以用2个参数完成。 – st0le 2010-11-04 08:48:08

2

如果您真的关心准确性,一个简单的循环可能会导致一些问题。双打不包含任意精度。这里有一个简单的例子来展示使用循环的缺点。

float f = 0; 
for(int i = 0; i < 1000*1000*1000; ++i){ 
    ++f; 
} 
System.out.println(f); 

我们希望f会是10亿或1.0E9,而我们会得到1.6777216E7。这是因为float只能保持大约6-7位的精度。双精度可以保持大约16-17位的精度,这意味着它不太可能存在问题,但它不能解决问题。

要解决这个问题,当它们之间存在较大的差异时,我们不需要添加两个数字。这可以简单地使用PriorityQueue完成。我们将拿出前两个数字,添加它们,然后将它们放回队列中。当队列只剩下1个数字时,我们将其返回。

public static double queueSum(double[] da){ 
    PriorityQueue<Double> pq = new PriorityQueue<Double>(da.length); 
    for(double d : da) 
     pq.add(d); 
    while(pq.size() > 1) 
     pq.add(pq.poll() + pq.poll()); 
    return pq.poll(); 
} 

当然,准确性的确是以牺牲时间为代价的。这从循环和O(n)到O(n lg(n)),更不用说涉及的对象的开销。

由于双打比浮球更精确,除非您有大量的双打(数百万/十亿)和/或您的数字之间有很大的差异,否则您可能不需要使用此功能。

编辑: 如果所有数字的大小大致相同,此代码将有助于避免问题以及保持O(n)时间。如果两个样本之间存在较大的幅度差异,或者数字以可能导致幅度差异较大的方式进行分布,则可能会遇到与以前相同的问题。

public static double treeSum(double[] da){ 
    double[] dc = da.clone(); 
    int len = dc.length; 
    while(len > 1){ 
     len = (len + 1)/2; 
     for(int i = 0; i < len; ++i) 
      dc[i] += dc[i + len]; 
     dc[len] = 0; 
    } 
    return dc[0]; 
} 
2

如果你的阵列分配给DoubleMatrix1D对象cern.colt.matrix库中,可以使用zSum()方法,它将返回数组中的所有元素的总和,而无需环路

your_sum = your_array.zSum()

1

您需要创建嵌套类内部的功能和使用递归的内部嵌套类做加法:

public double sumArrayNoLoop(double[] v){ 
class compute { 
      double total = 0.0; 
      public void sumArray(double[] v,int offset){ 
       if((offset - 1) < 0) return; 
       if(offset > (v.length - 1)) offset = v.length; 
       total += v[offset - 1]; 
       sumArray(v,offset - 1); 

      } 

     } 

    compute c = new compute(); 
    c.sumArray(v, v.length); 
    return c.total; 
} 

3

我宁愿采用以下方法。

package rfcampusdata; 

public class TestClass { 
    public static void main(String[] args) { 
    String str = "1,2,3,4,5"; 
    String[] arr = str.split(","); 
    int length = arr.length; 

    System.out.println(sum(length, arr)); 
    } 

    static Double temp = new Double(0); 

    public static Double sum(int length, String[] arr) { 
    int length_m = length - 1; 
    String[] arr_m = arr; 
    temp += Double.parseDouble(arr[length_m]); 
    if (length_m != 0) { 
     sum(length_m, arr_m); 
    } else { 
     // temp += Integer.parseInt(arr[0]); 
     // System.out.println(temp); 
    } 
    return temp; 

    } 
1

朋友,这是我已经完成的完美解决方案。我正在采取复杂的条件与字符串。我们可以直接使用double数组。

public class TestClass { 
    public static void main(String[] args) { 
    String str = "1,2,3,4,5"; 
    String[] arr = str.split(","); 
    int length = arr.length; 

    System.out.println(sum(length, arr)); 
    } 

    static Double temp = new Double(0); 

    public static Double sum(int length, String[] arr) { 
    int length_m = length - 1; 
    String[] arr_m = arr; 
    temp += Double.parseDouble(arr[length_m]); 
    if (length_m != 0) { 
     sum(length_m, arr_m); 
    } else { 
     // temp += Integer.parseInt(arr[0]); 
     // System.out.println(temp); 
    } 
    return temp; 

    } 

好日子!!!!

2

如果你的阵列中的数据类型是对象类型,不是原始类型,那么您可以在的Java 8使用这样的:

Double[] test = new Double[] {2.0, 3.1, 4.2, 8.9, 10.11}; 
List<Double> list = Arrays.asList(test); 
double sum = list.stream().mapToDouble(p -> p).sum(); 
System.out.println(sum); 
3

在Java 8:

Arrays.stream(array).sum(); 

而且如果你想在多个CPU上并行:

Arrays.stream(array).parallel().sum(); 
相关问题