最近在時間的細屑裡面擠出病毒般大小的時間來看GF調不出來的程式,簡直是鬱悶死人了。又要看好多年沒有真正用過的C++,真是一種頭痛欲裂的感覺,在一次感受到C++的瘋狂之處……(這個程式其實之前確實是在用C++寫的,後來因為某種原因,放棄了C++當中的++部分,用了幾乎純粹C的功能來編寫。準確一點講,標題應該是“這年頭,還有人用C的嗎?”)
大家先來看兩張對比的圖,著一張是正確的輸出結果:
再來看一張錯誤的輸出結果:(這一個是我需要調的程式)
然後就開始要求我GF趕緊對公式,對比正確輸出所用程式的代碼,看看兩者到底有什麼地方不一樣。由於兩個程式所用的座標系不一樣,所以對比起來比較困難,最後費了好大的勁,把座標系修改成完全一樣的之後,發現問題依舊。這個時候另外一個現象更加困惑了我:在修改錯誤程式的座標系之後,發現圖形的縮小程度明顯改善了,但是仍然是嚴重收斂的。這個現象著實打擊了我一下,因為我一開始只是以為是誤差量的積累造成的。難道說就是調整了一下幾個公式的位置以及一些加號或減號就會造成誤差累積量的不同?還真是前所未見的情況!
這裡整個調試過程是非常痛苦的,因為總共大約有幾千萬次的迴圈,計算量之大不可想象。而輸出正確和錯誤的程式之間,在大約每60次迴圈才會產生大約1x10-7細微差別。難為我GF在那裡單步調試了幾十萬次的迴圈,真是可憐啊。到底是哪裡出了問題呢?多虧我用VC7來運行了一遍,才發現問題所在。(之前都是我在抽空Review代碼,GF在1000km+的距離以外用VC6在調試。)下面這段代碼就是存在錯誤的地方:void MultiMatr(int s, int n, int t, double *arr1, double *arr2, double *result)
{
double *tmp;
for (int i = 0; i < s; i++)
{
for (int j = 0; j < t; j++)
{
tmp = result + t * i + j;
*tmp = 0;
for (int k = 0; k < n; k++)
{
*tmp += ((*(arr1 + n * i + k)) * (*(arr2 + t * k + j)));
}
}
}
}
/**//***************************** update ***************************/
void UpdateQ(double WnbbA[3])
{
int i;
double deltaSita0, angSin, angCos;
double deltaSita[3], qChange[3], qTrans[4][4];
deltaSita0 = 0;
for (i = 0; i < 3; i++)
{
deltaSita[i] = WnbbA[i] * quaDel;
deltaSita0 += deltaSita[i] * deltaSita[i];
}
deltaSita0 = sqrt(deltaSita0);
angCos = cos(deltaSita0 / 2);
if (deltaSita0 == 0)
angSin = 0.5;
else
angSin = sin(deltaSita0 / 2.0)/deltaSita0;
qTrans[0][0] = qTrans[1][1] = qTrans[2][2] = qTrans[3][3] = angCos;
qTrans[0][1] = qTrans[3][2] = -(angSin * deltaSita[0]);
qTrans[1][0] = qTrans[2][3] = -qTrans[0][1];
qTrans[0][2] = qTrans[1][3] = -(angSin * deltaSita[1]);
qTrans[2][0] = qTrans[3][1] = -qTrans[0][2];
qTrans[0][3] = qTrans[2][1] = -(angSin * deltaSita[2]);
qTrans[3][0] = qTrans[1][2] = -qTrans[0][3];
MultiMatr(4, 4, 1, (double*)qTrans, (double*)q, (double*)qChange);
for (i = 0; i < 4; i++)
q[i] = qChange[i];
}
大家看出來那裡錯了嗎?真是稀鬆平常的錯誤啊!害死人了。