2010-11-04 134 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(); 
相關問題