Complex Frequent Errors

下面的錯誤非常經典, 很容易發生, 程式寫好以後很難找到這種錯誤, 說起來也算是一種很有價值的錯誤, 遇見一次如果你能夠徹底了解為什麼會發生這種錯誤, 修改你撰寫程式時思考的邏輯, 你的收穫就很大了。

乘法的錯誤一 有些同學寫完乘法以後, 會用類似下面的測試確認程式的功能:
    Complex x1, x2, x3;
    x1.setValue(2, 0);
    x2.setValue(3, 0);
    x3.setValue(6, 0);
    x1.multiply(x2);
    assert(x1.equal(x3, 1e-10));
為什麼只測試實數呢? 這樣子不是沒有測試到完整的功能嗎? 有可能是因為如果有虛數的話, 乘起來的結果還需要動腦筋算一算才能得到結果, 有一點點偷懶吧!! 下面這個常常發生的錯誤就是只用實數是測不出來的, 你可以試試下面這個測試
    Complex x1, x2, x3;
    x1.setValue(1, 2);
    x2.setValue(3, 4);
    x3.setValue(-5, 10);
    x1.multiply(x2);
    assert(x1.equal(x3, 1e-10));
如果你的 multiply 函式沒辦法通過這個測試... 也許你也有下面這樣子的錯誤
    void Complex::multiply(CComplex &rhs)
    {
        m_real = m_real*rhs.m_real - m_imaginary*rhs.m_imaginary;
        m_imaginary = m_real*rhs.m_imaginary + m_imaginary*rhs.m_real;
    }
    
上面這段程式碼為什麼有錯呢? 因為你在算乘積的 m_imaginary 的時候, m_real 已經是乘積的 m_real 了, 不是原來被乘數的 m_real。

再一次的提醒你, 並不是數學公式有錯, 而是你沒有用 "記憶體變數是一個存放資料的空間" 來思考所犯下的錯誤。

乘法的錯誤二 下面這個測試也是想當然爾的功能, 不過很多同學會忽略而沒有測試:
    Complex x1, x2;
    x1.setValue(1, 2);
    x2.setValue(-3, 4);
    x1.multiply(x1);
    assert(x1.equal(x2, 1e-10));
你的程式通過測試了嗎? 如果沒有的話, 也許是犯了下面這樣的錯誤:
    void Complex::multiply(Complex &rhs)
    {
        double temp;
        temp = m_real;
        m_real = m_real*rhs.m_real - m_imaginary*rhs.m_imaginary;
        m_imaginary = temp*rhs.m_imaginary + m_imaginary*rhs.m_real;
    }
上面這段程式碼為什麼有錯呢? 不是已經用 temp 把被乘數的 m_real 記下來了嗎?! 錯誤的原因是 "你假設 rhs 在計算過程中是不會被修改的", 這是很容易犯的錯, 真的沒有被改到嗎? 被乘數和乘數一定是不同的數嗎? 不會相同嗎?

再一次的提醒你, 並不是數學公式有錯, 而是你撰寫這段程式時作了一個錯誤的假設 - "被乘數和乘數是不同的數"。 正確的寫法應該像這樣:

    void Complex::multiply(Complex &rhs)
    {
        double lhsReal, rhsReal;
        lhsReal = m_real;
        rhsReal = rhs.m_real;
        m_real = m_real*rhs.m_real - m_imaginary*rhs.m_imaginary;
        m_imaginary = lhsReal*rhs.m_imaginary + m_imaginary*rhsReal;
    }
或是
    void Complex::multiply(Complex &rhs)
    {
        Complex newNumber;
        newNumber.m_real = m_real*rhs.m_real - m_imaginary*rhs.m_imaginary;
        newNumber.m_imaginary = m_real*rhs.m_imaginary + m_imaginary*rhs.m_real;
        *this = newNumber; // m_real = newNumber.m_real; 
                           // m_imaginary = newNumber.m_imaginary;
    }

C++ 物件導向程式設計課程 首頁

製作日期: 03/28/2007 by 丁培毅 (Pei-yih Ting)
E-mail: [email protected] TEL: 02 24622192x6615
海洋大學 電機資訊學院 資訊工程學系 Lagoon