2017-04-02 74 views
0

我正在嘗試編寫一個函數,它使用最小二乘方法計算數據表中的迴歸直線,但我遇到了一些嚴重的問題。避免舍入雙數

我的第一個問題是,我不知道爲什麼我的「線性迴歸」函數將迭代的結果四捨五入,即使我試圖使用其他「更大」的類型。

我的第二個問題是,我的代碼的最後一部分給了y截距(b)和斜率(a)的錯誤結果,我認爲這可能是一個轉換問題,但我不太確定。如果是這種情況,我應該怎麼做才能避免它?

void RegLin (const vector<double>& valuesX, const vector<double>& valuesY, vector<double>& PenOrd) { 

unsigned int N=valuesX.size(); 

long double SomXi{0}; 
    for (unsigned i=0; i<N; ++i){ 
    SomXi+=valuesX.at(i); 
    } 

long double SomXiXi{0};    
    for (unsigned i=0; i<N; ++i){    //Here is a problem (number rounded) Expected value: 937352,25/Given value: 937352 
    SomXiXi+=(valuesX.at(i))*(valuesX.at(i)); 
    } 

long double SomYi{0}; 
    for (unsigned i=0; i<N; ++i){ 
    SomYi+=valuesY.at(i); 
    } 

long double SomXiYi{0}; 
    for (unsigned i=0; i<N; ++i){    //Here is the same problem Excepted value: 334107,41/Given value: 334107 
    SomXiYi+=(valuesX.at(i))*(valuesY.at(i)); 
    } 

long double a=(SomYi*SomXiXi-SomXi*SomXiYi)/(N*SomXiXi-pow(SomXi,2)); //Bad result 

long double b=(N*SomXiYi-SomYi*SomXi)/(N*SomXiXi-pow(SomXi,2)); //Bad result 

PenOrd.push_back(a); 
PenOrd.push_back(b); 

return; 
} 

預先感謝您的支持

P.S:我用g ++以及2011年的C++標準。

+3

「四捨五入結果」的描述是沒有意義的。描述你的意思(例如用一個示例輸入,預期輸出和實際輸出)。 – Peter

+0

我不太清楚你在問什麼。但是,猜測;也許你想讀這些(並記住,浮點數學不是確切的 - 它不能):http://stackoverflow.com/questions/588004/is-floating-point-math-broken,https: //docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html –

+0

對於a和b的公式看起來不正確。看看維基百科上的正確公式:https://en.wikipedia.org/wiki/Simple_linear_regression #Fitting_the_regression_line你在哪裏計算Xi和Yi的平均值?這是一個完整的解決方案btw:http://stackoverflow.com/a/18974171/1291717 –

回答

2

有你的努力的幾點。我是理論物理和數學數學傢伙。所以,讓我與你分享一些最佳實踐。

首先,我從來沒有遇到需要使用long double。堅持與double,因爲如果這還不夠,那麼你應該考慮工作日誌日誌圖進一步分析你的數據。

二,你是using unsigned int而不是int。您不應該使用那麼多的值(即值對)進行迴歸工作,因爲您的整數計數器不能使用int或最好的std::size_t。由於累積數值舍入問題,使用太多值會降低準確性。所以不要使用超過10000到100萬的值,除非你有足夠的理由這麼做。第三,它很快就變得有必要不要直接添加你的方塊(例如,對於SumXiXi等),而是在實際總結它們之前對你的貢獻進行排序。你正確地將它們總結起來,從最小的價值觀開始,隨着對你的資金的不斷增長的貢獻。這是停留在累計舍入問題之上的唯一途徑。

四,控制結果。結果可靠性的一個好兆頭是可以實現的,如果你工作兩次,一次就像你去過的一樣。,使用x_iy_i - xy_i - x_iy + xy formuae),然後作爲第二種方法使用仍然未乘法的公式(x_i - x)(y_i - y)。使用任一公式都可以得出非常可比的結果。

因此,也許是做數值迴歸工作的一個繞道,希望它可能有所幫助。

此致,Micha

+0

考慮[Kahan求和](https://en.wikipedia.org/wiki/Kahan_summation_algorithm)以限制加起來的平方的舍入誤差。 –

0

浮點數值計算的第一條規則是:「只能使用同一順序的值」。

浮點數學運算非常簡單,例如,加法(float):

1e6 + 1e-6 = 1000000 + 0.000001 = 1000000.000001 = 1000000 = 1e6 
              ^
            precision limit 

所以,正如你所看到的,結果是「四捨五入」的。

0

這entirerly可能是你給的錯誤是由於2個possibilites:

1)你的編譯器long double == double和你得到錯誤的結果

2)浮點運算,並不代表100%的準確度值因此'0.10 != 0.10 written as float/double

根據你在做什麼樣的計算,我會建議你增加一些功率值,或者改變數據浮動和存儲值的兩倍。