C# 入門指南 - 修正後的數學公式

程式中可能會發生的錯誤有三種,分別是語法錯誤 (syntax error) 、執行期間錯誤 (run-time error) 及語意錯誤 (sematic error)




編譯器 (compiler) 會直接幫我們挑出語法錯誤,例如打錯識別字 (identifier) 名稱或是漏打分號等等。執行期間錯誤的話, C# 另有例外處理 (exception handling) 的機制,使我們可處理如開啟指定檔名的檔案,然而檔案卻不存在的情況。三種錯誤中最麻煩的,就是語意錯誤了,因為有語意錯誤的程式,程式可以順利執行完畢,卻跑出錯誤的結果。


我們的 Encrypt 類別 (class) 目前正是碰到了發生語意錯誤的情況,這是說
y = a * x + b
m = y % n
r = m + diff


其中 a 與 b 若是 1 到 9 隨機整數,有些組合成立,可以得到正確結果,有些組合卻會得到錯誤的結果,這是為什麼呢?嗯,好麻煩唷!這樣就得討論好多數學,打斷我們發展程式的腳步,因此我們不會也不打算仔細討論這背後的數學理論,我們繼續測試,直接來找出哪些組合會得到錯誤的結果吧!


要知道哪些組合可能會發生錯誤,我們就得知道 a 與 b 的值,這不難,印出來就看得到了,我們將 setArray() 加入印出 ab 值的陳述 (statement) ,因此新的 encrypt00.cs 如下
class Encrypt {
    string cArray;
        
    public void setArray() {
        System.Random r = new System.Random();
        int a = r.Next(1, 10);
        int b = r.Next(1, 10);
        System.Console.Write("a: " + a + ", b: " + b + ", ");
            
        int x, y, m;
        char c = 'a';
        int i;
        System.Text.StringBuilder s = new System.Text.StringBuilder();
        for (i = 0; i < 26; i++) {
            x = c;
            y = x * a + b;
            m = y % 26;
            s.Append((char) (m + 97)); 
            c++; 
        }
    
        this.cArray = s.ToString();   
    }
    
    static void Main() {
        for (int i = 0; i < 16; i++) {
            Encrypt e = new Encrypt();
            e.setArray();
            System.Console.WriteLine("e" + i + ": "+ e.cArray);
            System.Threading.Thread.Sleep(1000);
        }
    }
}

/* 《程式語言教學誌》的範例程式
    http://pydoing.blogspot.com/
    檔名:encrypt00.cs
    功能:示範 C# 程式 
    作者:張凱慶
    時間:西元 2012 年 10 月 */


我們用到 System.Console.Write() ,這是另外一個在命令列印出訊息的方法,它與 println() 的差別是不會印出新行符號,也就是 '\n' 。


來編譯執行看看囉



我們可以發現以下這幾組 (a, b) 出現問題
(4, 8) (2, 5) (4, 5)


共通的特點 a 是偶數,所以 a 不能是偶數嗎?我們繼續改寫進行測試
class Encrypt {
    string cArray;
        
    public void setArray() {
        System.Random r = new System.Random();
        int a = 0;
        int b = 0;
        // 限定 a 為偶數
        while (a % 2 == 0) {
            a = r.Next(1, 10);
            b = r.Next(1, 10);
        }
        System.Console.Write("a: " + a + ", b: " + b + ", "); 
            
        int x, y, m;
        char c = 'a';
        int i;
        System.Text.StringBuilder s = new System.Text.StringBuilder();
        for (i = 0; i < 26; i++) {
            x = c;
            y = x * a + b;
            m = y % 26;
            s.Append((char) (m + 97)); 
            c++; 
        }
    
        this.cArray = s.ToString();   
    }
    
    static void Main() {
        for (int i = 0; i < 16; i++) {
            Encrypt e = new Encrypt();
            e.setArray();
            System.Console.WriteLine("e" + i + ": "+ e.cArray);
            System.Threading.Thread.Sleep(1000);
        }
    }
}

/* 《程式語言教學誌》的範例程式
    http://pydoing.blogspot.com/
    檔名:encrypt00.cs
    功能:示範 C# 程式 
    作者:張凱慶
    時間:西元 2012 年 10 月 */


編譯後執行,如下



這裡
int a = 0;
int b = 0;
// 限定 a 為偶數
while (a % 2 == 0) {
    a = r.Next(1, 10);
    b = r.Next(1, 10);
}


a % 2 計算出 a 除以 2 的餘數,如果 a 除以 2 等於 0 ,那麼意味著 a 為 0 或偶數。我們用 a % 2 等於 0 當條件 (condition) ,迴圈 (loop) 在 a 為奇數時就會結束。


嗯,我們用肉眼檢查,似乎只要 a 為奇數,計算出的結果就不會有問題。因此,公式應修正如下
y = a * x + b // a % 2 != 0
m = y % n
r = m + diff


也就是在 a % 2 不等於 0 之時,公式才成立。嗯,目前我們都是修改 setArray() 進行測試,如果我們希望 Encrypt 更完備, Encrypt 的屬性 (property) 設定應該要放在建構子 (constructor) 之中。


中英文術語對照
語法錯誤syntax error
執行期間錯誤run-time error
語意錯誤sematic error
編譯器compiler
識別字identifier
例外處理exception handling
類別class
陳述statement
條件condition
迴圈loop
屬性property
建構子constructor


您可以繼續參考
軟體開發


相關目錄
回 C# 入門指南
回 C# 教材
回首頁


參考資料
http://msdn.microsoft.com/zh-tw/library/ms173109%28v=vs.80%29.aspx
http://msdn.microsoft.com/zh-tw/library/x9afc042.aspx
http://msdn.microsoft.com/zh-tw/library/ms229036%28v=vs.80%29.aspx
http://msdn.microsoft.com/zh-tw/library/0b0thckt.aspx

1 則留言:

印度錐子 提到...

「我們用到 System.Console.Write() ,這是另外一個在命令列印出訊息的方法,它與 println() 的差別是不會印出新行符號,也就是 '\n' 。」

println() 是 python 的吧!?