2014-09-28 64 views
1

什麼是計算組號碼,ARR[0]/N+ARR[1]/N...+ARR[N-1]/N(ARR[0]+ARR[1]...+ARR[N-1])/N的平均更準確的方法是什麼? (ARR是一組數字和N是數字的那一套計)什麼是更準確的平均方法,ARR [0]/N + ARR [1]/N ... + ARR [N-1]/N或(ARR [0] + ARR [1] ... + ARR [N-1])/ N爲雙倍?

考慮我已經設置從0.01.0每個範圍(它們是雙\浮點數)號和有幾千其中甚至數百萬。

我公開像遞歸平均新方法(平均雙細胞分化成數組,然後再次平均,直到它輸出一個單元陣列)。

+0

(假設所有數字都是正數)對數字進行排序,從最低到最高,然後從最低到最高添加。 (如果出現負數,則按絕對值排序。)並且不需要將每個元素除以N,只需將總和除以N. – 2014-09-28 18:52:33

+0

另請參閱http://stackoverflow.com/q/13417670/(特別是,Kahan求和) – Nemo 2014-09-28 19:01:02

回答

2

如果接近零值非常接近零,你就會有一個四捨五入的問題的總和(可以舍入誤差向上或向下),或者如果總結大組數字的任何數值範圍。解決此問題的一個方法是使用求和函數,該求和函數僅添加具有相同指數的數字(直到您調用getsum()以獲取總和,並使指數儘可能接近)。示例C++類來執行此操作(注意代碼是使用Visual Studio編譯的,在uint64_t可用之前編寫)。

// SUM contains an array of 2048 IEEE 754 doubles, indexed by exponent, 
// used to minimize rounding/truncation issues when doing 
// a large number of summations 

class SUM{ 
    double asum[2048]; 
public: 
    SUM(){for(int i = 0; i < 2048; i++)asum[i] = 0.;} 
    void clear(){for(int i = 0; i < 2048; i++)asum[i] = 0.;} 
// getsum returns the current sum of the array 
    double getsum(){double d = 0.; for(int i = 0; i < 2048; i++)d += asum[i]; 
        return(d);} 
    void addnum(double); 
}; 

void SUM::addnum(double d)  // add a number into the array 
{ 
size_t i; 

    while(1){ 
//  i = exponent of d 
     i = ((size_t)((*(unsigned long long *)&d)>>52))&0x7ff; 
     if(i == 0x7ff){   // max exponent, could be overflow 
      asum[i] += d; 
      return; 
     } 
     if(asum[i] == 0.){  // if empty slot store d 
      asum[i] = d; 
      return; 
     } 
     d += asum[i];   // else add slot to d, clear slot 
     asum[i] = 0.;   // and continue until empty slot 
    } 
} 
使用之類

示例程序:

#include <iostream> 
#include <iomanip> 
using namespace std; 

static SUM sum; 

int main() 
{ 
double dsum = 0.; 
double d = 1./5.; 
unsigned long i; 

    for(i = 0; i < 0xffffffffUL; i++){ 
     sum.addnum(d); 
     dsum += d; 
    } 
    cout << "dsum    = " << setprecision(16) << dsum << endl; 
    cout << "sum.getsum()  = " << setprecision(16) << sum.getsum() << endl; 
    cout << "0xffffffff * 1/5 = " << setprecision(16) << d * (double)0xffffffffUL << endl; 

    return(0); 
} 
+0

目前還不清楚這是否可能是添加一堆數字的最佳方式。你知道這是真的嗎?如果是這樣,你能提供一個簡單的證明簡圖嗎? – thang 2014-09-28 18:37:10

+0

@thang:這不是最好的方法。但它是我能想到的最合理的方式。對數字進行求和以消除小數量截斷的最低誤差方式是對數字進行排序並將它們從小到大進行求和。 – 2014-09-28 18:42:20

+0

@RafaelBaptista - 總結一組排序的數字並不能解決問題。你仍然可能會用相同的指數對大量數字求和。在這個序列的結尾附近,您將爲相對較大的工作總和添加一個相對較小的數字。 – rcgldr 2014-09-28 18:53:13

0

(ARR[0]+ARR[1]...+ARR[N-1])/N更快,更準確,因爲您省略了無用的部門N,這既減慢了過程速度,又增加了計算中的錯誤。

+0

確保您使用的是一些好的求和算法,如[這裏](http://en.wikipedia.org/wiki/Kahan_summation_algorithm) – 2014-09-28 18:30:25

+0

爲什麼劃分爲每個值計算中正在錯誤?我認爲當你添加兩個值,例如'10000'和'0.1'時,由於它非常小,所以'0.1'輪的誤差非常大。我需要這個可靠的來源。 – KugBuBu 2014-09-28 18:33:53

+0

作爲提示,在添加它們之前按數量級分類,並從低端開始。 (無論如何,如果數字可以正確無誤地添加沒有關係) – Deduplicator 2014-09-28 18:36:43

0

如果你有一堆浮點數的,最準確的方式來獲得平均是這樣的:

template<class T> T mean(T* arr, size_t N) { 
    std::sort(+arr, arr+N, [](T a, T b){return std::abs(a) < std::abs(b);}); 
    T r = 0; 
    for(size_t n = 0; n < N; n++) 
     r += arr[n]; 
    return r/N; 
} 

重要事項:

  • 數字o f首先添加最小幅度以保留有效數字。
  • 只有一個部門,以減少那裏的舍入誤差。

儘管如此,中間和值可能會變得過於龐大。

相關問題