2010-04-27 170 views
1

在我的程序中編碼矩陣乘法,我得到了精度誤差(大矩陣結果不準確)。矩陣乘法的精度誤差

這是我的代碼。當前對象將數據存儲在扁平數組中,並逐行排列。其他矩陣B的數據存儲在一個扁平數組中,列後列(所以我可以使用指針算術)。

protected double[,] multiply (IMatrix B) 
{ 
    int columns = B.columns; 
    int rows = Rows; 
    int size = Columns; 

    double[,] result = new double[rows,columns]; 
    for (int row = 0; row < rows; row++) 
    { 
     for (int col = 0; col < columns; col++) 
     { 
      unsafe 
      { 
       fixed (float* ptrThis = data) 
       fixed (float* ptrB = B.Data) 
       { 
        float* mePtr = ptrThis + row*rows; 
        float* bPtr = ptrB + col*columns; 
        double value = 0.0; 
        for (int i = 0; i < size; i++) 
        { 
         value += *(mePtr++) * *(bPtr++); 
        } 
        result[row, col] = value; 
       } 
      } 
     } 
    } 
} 

實際上,該代碼是一個比較複雜:我做了幾個塊乘法東西(所以不是從0到大小有我的,我從localStart到localStop去),再總結產生的矩陣。

我的問題:一個大的矩陣我得到精度誤差:

NUnit.Framework.AssertionException: Error at (0,1) 
    expected: <6.4209571409444209E+18> 
    but was: <6.4207619776304906E+18> 

任何想法?

+0

也許使用'precision'標籤應該會自動打開關於在這些問題中經常出現的浮點數學的網頁? – Skizz 2010-04-27 13:20:36

回答

0

下襬,它並沒有真正解決您的問題,但在NUnit的,可以允許有精度誤差,選擇該小量

0

作爲出發點的值,使用double隨處可見,而不是float

+0

我的數組已經是float [],不能改變任何東西。內存問題在某些時候,整個應用程序使用float []等。 – Wam 2010-04-27 12:44:14

+0

然後我不確定你有什麼可以做的。你拋棄了精確性;沒有多少巧妙的東西可以讓它恢復。 – 2010-04-27 13:08:34

1

我原來說你應該把floats轉換成doubles。但是,正如你指出的那樣會打破你的算法。

你可以嘗試:

value += (double)*(mePtr++) * (double)*(bPtr++); 

一個問題,您的代碼,因爲它現在代表的是乘法在float精密正在做,然後添加到double。首先鑄造到double會有所幫助。

使用中間變量double可能會更清楚 - 但這取決於您。

如果這不能給你想要的準確度,那麼你需要考慮使用decimal而不是double。但是,這可能會導致性能下降,所以先做一些基準測試。

+0

是的,但是將mePtr和bPtr轉換爲double,我仍然可以使用mePtr ++,還是僅使用數組的一半元素? b.data是float [],如果mePtr是一個指向b.data [0]的雙指針,不會mePtr ++在右邊8個字節,所以b.data [2]而不是b.data [1]? – Wam 2010-04-27 12:39:41

+0

@Wam - 在這種情況下,你將不得不在計算中將值加倍 - 我會更新答案 – ChrisF 2010-04-27 12:46:19

+0

試過了,它不能解決我的問題...... – Wam 2010-04-27 12:57:24

0

至少,你應該在整個使用雙打。花車非常不精確。

+0

那麼,浮點數比雙精度要差, 這是肯定的。但是,所有的(幾乎所有的,我的統計都是不準確的)浮點數是不精確的。 – 2010-04-27 12:27:58

+0

@高,雙精度比浮點精度高29位。這使他們精確到大約一億倍。 – 2010-04-27 13:07:07

+1

@Marcelo - 確實如此。我們還有很多人在進行嚴格的數字運算,不得不擔心長時間運算中精度的下降。將花車改爲雙打只會推遲它不會將其刪除的問題。當然,有時它會推遲問題,直到計算完成。 – 2010-04-27 14:05:16

1

也許你所要做的就是使用Kahan summation。但是你可以用never expect得到,確切地說具有浮點數學的特定結果。

0

這是一種稱爲「矩陣蠕變」的現象,如果您不一致地對矩陣進行標準化,矩陣運算會逐漸發生。

1

原來,這只是一個錯誤。結束了那不是有:

float* mePtr = ptrThis + row*rows; 
float* bPtr = ptrB + col*columns; 

爲我行的正確索引是:

float* mePtr = ptrThis + row * size; 
float* bPtr = ptrB + col * size; 

對不起,這裏沒有真正看中的答案。但感謝您的幫助!