2014年5月28日 星期三

C++ - 整數運算之溢位偵測

整數運算中,最容易產生溢位問題的估計是階層運算。設計一個factorial遞回函式來運算階層,輸入是一個整數N,輸出則為N!的結果,輸入和輸出的整數資料型態一致,假設使用unsigned int作為整數資料型態,該factorial函式表示如下:
unsigned int factorial(unsigned int N)
{
    return (N == 0 || N == 1) ? 1 : N * factorial(N - 1);
}
這是很簡單的一個寫法,用unsigned int是因為階層的定義要求為正整數或0。這個寫法並沒考量到溢位問題,當輸入的N為13時,就會產生溢位問題。

如果是兩個整數相加,溢位會多增加一個位元,可以檢查兩個整數相加是否會有進位現象,進位後會不會超出資料型態的位元數,來判斷相加會不會產生溢位。

可是階層運算是乘法運算,無法用相加的溢位判斷方式,而要用其他的方式判斷。

方式一:溢位旗標的判斷。因為暫存器的關係,僅適用於int、unsigned int等32位元的整數資料型態,若用於其他位元數的整數資料型態會判斷錯誤。
unsigned int factorial(unsigned int N)
{
    unsigned int product = 0;
    product = (N == 0 || N == 1) ? 1 : N * factorial(N - 1);
    __asm jo overflowed;
    if (0)
    {
overflowed:
        throw(std::out_of_range("Overflowed"));
    }
    return product;
}
方法二:除法運算檢查。適用各種整數資料型態。
int factorial(int N)
{
    int product = 0;
    if (N < 0) // 限定N為正整數或0
    {
        throw(std::out_of_range("Negative integer"));
    }
    if (N == 0 || N == 1)
    {
        product = 1;
    }
    else
    {
        int multiplicand = factorial(N - 1);
        product = N * multiplicand;
        if (product / N != multiplicand) throw(std::out_of_range("Overflowed"));
    }
    return product;
}
方法三:自訂BigInteger的資料型態。 BigInteger的數字是使用字元陣列來表示,運算採取字元陣列的方式做運算,加減乘除也需要自訂,因為是用字元陣列來表示一個數字,所以該數字理論上可以無限大(實際上會受限字元陣列所能表示的最大長度)。

方法二就已經足夠使用,方法三就留給以後需要的時候再來實作。

2014年5月8日 星期四

Doxygen - 圖形化類別關聯性

Doxygen是一套利用程式註解的方式,建立出程式說明文件的軟體。
Graphviz是一套利用命令和參數畫出關係圖的軟體。
Doxygen產出文件時,可以透過參數設定,使用Graphviz來繪圖。操作步驟為:

  1. 先安裝DoxygenGraphviz這兩套軟體。
  2. 設定環境變數,將Graphviz安裝路徑\bin設定在環境變數path。
  3. 設定Doxygen的執行參數。如果是使用doxygen參數檔的方式,HAVE_DOT這個參數要設定為YES,其他與dot相關的參數則可自行調整。如果是使用wizard圖形視窗的方式,在Expert頁籤的Topics選單中有個Dot項目,點選Dot後,將HAVE_DOT勾選起來,其他相關參數則可自行調整。
最後,建立完文件,在類別分類中就可以看到關係圖了。

2013年12月6日 星期五

Python - 函示宣告與呼叫順序

Python因為是直譯式語言,函式必須要先宣告才能呼叫,所以很常看到main函式寫在程式檔案的後面。但是,如果想先寫呼叫再宣告函式,也是可以的,只要利用from import:(範例檔為test.py)
from test import *
if __name__ == "__main__":
    main()

def main():
    print("main")
    sub()
  
def sub():
    print("sub")

執行後的輸出為:
main
sub

2013年2月19日 星期二

C# - 表格排版與隱藏元件

想要的效果:
  1. GUI呈現為表單輸入。
  2. 配合不同編譯版本,表單上的輸入控制項有一些需要被隱藏起來。

問題與解決方法:
  1. 同一份程式碼,要有不同編譯版本,採用Predefined macro(#if、#define、#elif……)。
  2. C#的GUI排版有FlowLayoutPanel和TableLayoutPanel。為了讓GUI呈現表單的整齊格式,採用TableLayoutPanel來排版。
  3. 要隱藏控制項,因為表單上的控制項是已知,所以要被隱藏的控制項設定狀態為Hide,包含相關的Label也要一併隱藏。

2013年1月22日 星期二

Windows - batch檔案的暫停執行

執行batch檔(.bat),若想讓指令暫緩執行,可以利用特殊技巧來實現,例如想要暫停10秒鐘,可以在想暫停的地方用ping指令來達到這個目的:
@ping 127.0.0.1 -n 10 -w 1000 > nul

2012年12月12日 星期三

Ubuntu - 操作Tomcat

在Ubuntu安裝好Tomcat後,可以利用終端機輸入指令,啟動或關閉Tomcat,例如:
  啟動: /etc/init.d/tomcat7 start
  停止: /etc/init.d/tomcat7 stop
重新啟動: /etc/init.d/tomcat7 restart
要能做到這些動作,必須要先寫shell script。Tomcat安裝好後會有已寫好的startup.sh和shutdown.sh,再來是要在/etc/init.d/新增一個tomcat7的檔案,檔案內容為:
#這裡是使用j2ee的java library,請依據個人安裝版本和路徑做更動
export JAVA_HOME=/home/minimum/glassfish3/jdk7
case $1 in
start)
  #請依據個人安裝路徑做更動
  sh /usr/share/tomcat7/bin/startup.sh
  ;;
stop)
  #請依據個人安裝路徑做更動
  sh /usr/share/tomcat7/bin/shutdown.sh
   ;;
restart)
  #請依據個人安裝路徑做更動
  sh /usr/share/tomcat7/bin/shutdown.sh
  sh /usr/share/tomcat7/bin/startup.sh
  ;;
esac
exit 0
 存檔後,就能利用上述指令啟動或關閉Tomcat。

2012年11月1日 星期四

C++ - 建立process執行外部程式

目的:建立一個process,並執行外部程式。
要求:視窗隱藏,輸出重新導向到指定的檔案。
// Setting security for output handle (necessary)
SECURITY_ATTRIBUTES sa;
memset(&sa, 0, sizeof(SECURITY_ATTRIBUTES));
sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = TRUE;

// Setting output handle
HANDLE hConsoleRedirect = CreateFile((L"out.txt").c_str(), GENERIC_WRITE|GENERIC_READ, FILE_SHARE_WRITE|FILE_SHARE_READ|FILE_SHARE_DELETE, &sa, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if(hConsoleRedirect == INVALID_HANDLE_VALUE) return;

// Setting console standup info
STARTUPINFO si;
memset(&si, 0, sizeof(STARTUPINFO));
si.cb = sizeof(si);
si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
si.wShowWindow = SW_HIDE;
si.hStdOutput = hConsoleRedirect;
si.hStdError = hConsoleRedirect;

// Setting process info
PROCESS_INFORMATION pi;
memset(&pi, 0, sizeof(PROCESS_INFORMATION));       

// Excute command
wstring cmd = L"program.exe -argument";
bool bResult = CreateProcess(NULL, (LPWSTR) cmd.c_str(), NULL, NULL, TRUE, CREATE_NEW_CONSOLE|CREATE_UNICODE_ENVIRONMENT, NULL, NULL, &si, &pi);
DWORD ret = WaitForSingleObjectEx(pi.hProcess, INFINITE, FALSE);

// Close handles
CloseHandle(hConsoleRedirect);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);