?? 用masmplus 學習匯編語言(5) .txt
字號:
這個程序還不完美,我們還可以調整一下顏色,看得好看一些,還可以改造一下,
改為三叉樹,或者改為隨機的n叉樹,每次運行結果都不同... ...
看到這個程序,我提出一個數學問題:繪制的樹干長度,為Len的多少時,能保證
不發生重疊呢?
具體就是說上圖中指出的部分什么情況下不會碰上箭頭指出來的那條線。
Koch Snowflake(科赫雪花)
參考1:http://baike.baidu.com/view/83243.htm
分形
誰創立了分形幾何學?
1973年,曼德勃羅(B.B.Mandelbrot)在法蘭西學院講課時,首次提出了分維和分形幾何的設想。分形(Fractal)一詞,是曼德勃羅創造出來的,其愿意具有不規則、支離破碎等意義,分形幾何學是一門以非規則幾何形態為研究對象的幾何學。由于不規則現象在自然界是普遍存在的,因此分形幾何又稱為描述大自然的幾何學。分形幾何建立以后,很快就引起了許多學科的關注,這是由于它不僅在理論上,而且在實用上都具有重要價值。
分形幾何與傳統幾何相比有什么特點:
⑴從整體上看,分形幾何圖形是處處不規則的。例如,海岸線和山川形狀,從遠距離觀察,其形狀是極不規則的。
⑵在不同尺度上,圖形的規則性又是相同的。上述的海岸線和山川形狀,從近距離觀察,其局部形狀又和整體形態相似,它們從整體到局部,都是自相似的。當然,也有一些分形幾何圖形,它們并不完全是自相似的。其中一些是用來描述一般隨即現象的,還有一些是用來描述混沌和非線性系統的。
什么是分維?
在歐氏空間中,人們習慣把空間看成三維的,平面或球面看成二維,而把直線或曲線看成一維。也可以梢加推廣,認為點是零維的,還可以引入高維空間,但通常人們習慣于整數的維數。分形理論把維數視為分數,這類維數是物理學家在研究混沌吸引子等理論時需要引入的重要概念。為了定量地描述客觀事物的“非規則”程度,1919年,數學家從測度的角度引入了維數概念,將維數從整數擴大到分數,從而突破了一般拓撲集維數為整數的界限。
分維的概念我們可以從兩方面建立起來:一方面,我們首先畫一個線段、正方形和立方體,它們的邊長都是1。將它們的邊長二等分,此時,原圖的線度縮小為原來的1/2,而將原圖等分為若干個相似的圖形。其線段、正方形、立方體分別被等分為2^1、2^2和2^3個相似的子圖形,其中的指數1、2、3,正好等于與圖形相應的經驗維數。一般說來,如果某圖形是由把原圖縮小為1/a的相似的b個圖形所組成,有:
a^D=b, D=logb/loga
的關系成立,則指數D稱為相似性維數,D可以是整數,也可以是分數。另一方面,當我們畫一根直線,如果我們用0維的點來量它,其結果為無窮大,因為直線中包含無窮多個點;如果我們用一塊平面來量它,其結果是0,因為直線中不包含平面。那么,用怎樣的尺度來量它才會得到有限值哪?看來只有用與其同維數的小線段來量它才會得到有限值,而這里直線的維數為1(大于0、小于2)。與此類似,如果我們畫一個Koch曲線,其整體是一條無限長的線折疊而成,顯然,用小直線段量,其結果是無窮大,而用平面量,其結果是0(此曲線中不包含平面),那么只有找一個與Koch曲線維數相同的尺子量它才會得到有限值,而這個維數顯然大于1、小于2,那么只能是小數(即分數)了,所以存在分維。其實,Koch曲線的維數是1.2618……。
Fractal(分形)一詞的由來
據曼德勃羅教授自己說,fractal一詞是1975年夏天的一個寂靜夜晚,他在冥思苦想之余偶翻他兒子的拉丁文字典時,突然想到的。此詞源于拉丁文形容詞fractus,對應的拉丁文動詞是frangere(“破碎”、“產生無規碎片”)。此外與英文的 fraction(“碎片”、“分數”)及fragment(“碎片”)具有相同的詞根。在70年代中期以前,曼德勃羅一直使用英文fractional 一詞來表示他的分形思想。因此,取拉丁詞之頭,擷英文之尾的fractal,本意是不規則的、破碎的、分數的。曼德勃羅是想用此詞來描述自然界中傳統歐幾里德幾何學所不能描述的一大類復雜無規的幾何對象。例如,彎彎曲曲的海岸線、起伏不平的山脈,粗糙不堪的斷面,變幻無常的浮云,九曲回腸的河流,縱橫交錯的血管,令人眼花僚亂的滿天繁星等。它們的特點是,極不規則或極不光滑。直觀而粗略地說,這些對象都是分形。
分形的定義
曼德勃羅曾經為分形下過兩個定義:
(1)滿足下式條件
Dim(A)>dim(A)
的集合A,稱為分形集。其中,Dim(A)為集合A的Hausdoff維數(或分維數),dim(A)為其拓撲維數。一般說來,Dim(A)不是整數,而是分數。
(2)部分與整體以某種形式相似的形,稱為分形。
然而,經過理論和應用的檢驗,人們發現這兩個定義很難包括分形如此豐富的內容。實際上,對于什么是分形,到目前為止還不能給出一個確切的定義,正如生物學中對“生命”也沒有嚴格明確的定義一樣,人們通常是列出生命體的一系列特性來加以說明。對分形的定義也可同樣的處理。
(i)分形集都具有任意小尺度下的比例細節,或者說它具有精細的結構。
(ii)分形集不能用傳統的幾何語言來描述,它既不是滿足某些條件的點的軌跡,也不是某些簡單方程的解集。
(iii)分形集具有某種自相似形式,可能是近似的自相似或者統計的自相似。
(iv)一般,分形集的“分形維數”,嚴格大于它相應的拓撲維數。
(v)在大多數令人感興趣的情形下,分形集由非常簡單的方法定義,可能以變換的迭代產生。
環境變量
以前DOS下有一種叫做“環境變量”的東西,最常用的就是“Path=”。比如,我們設定 “path=c:\masm611\bin”,當我們在某一個目錄下輸入命令 “ml a.asm”的時候如果當前目錄下沒有 “ml.exe” “ml.com” 或者“ml.bat”的時候,系統會自動在path給定的路徑下搜索這些文件,如果找到就會自動運行。 Windows也設計了環境變量,在“系統屬性”“高級”選項卡中:
選擇“環境變量”按鈕:
上圖就是我的環境變量設置,如果你安裝過 VC 或者Delphi那么還會看到更豐富的path設置,這些語言在編譯的時候就是在參考path給定的路徑,調用編譯器。
下面,我們就編寫一個讀取環境變量的程序。程序使用 GetEnvironmentStringsA API,這個API的返回當前進程的環境塊的起始地址。環境塊的結構如下:
Var1=Value1\0
Var2=Value2\0
Var3=Value3\0
...
VarN=ValueN\0\0
這樣的結構在Windows中很常見,后面我們研究剪切板還會遇到這樣結構。
程序的基本思路就是:我們再開辟一塊空間,將環境塊中的東西拷貝過去,在拷貝的過程中,遇到 \0就將它換作回車,最后直接顯示這塊新空間中的內容即可。
;#Mode=CON
.386
.model flat, stdcall
option casemap :none
include windows.inc
include user32.inc
include kernel32.inc
include masm32.inc
includelib user32.lib
includelib kernel32.lib
includelib masm32.lib
include macro.asm
.data?
szBuffer db 100 dup(?)
hStdOut dd ?
hStdin dd ?
hMem dd ?
nwritten dd ?
.CODE
START:
invoke GetStdHandle,STD_OUTPUT_HANDLE
mov hStdOut,eax
invoke GetStdHandle,STD_INPUT_HANDLE
mov hStdin,eax
xor ebx,ebx
invoke VirtualAlloc,ebx,1000,MEM_COMMIT+MEM_RESERVE,PAGE_READWRITE
mov hMem,eax
invoke GetEnvironmentStringsA
mov esi,eax ;esi指向包含環境變量的內存塊
mov edi,hMem
next_symbol: ;edi指向一個新開辟的內存塊
or al,al ;判斷一下,是否為 0
jz end_string ;al=0 表示到結尾
mov [edi],al
next_string:
cmpsb
jmp short next_symbol
end_string:
mov DWORD ptr [edi],0D0A2020h ;在結尾處我們用回車+空格取代之
;(有興趣的讀者可以試試看寫作 0D0A 看看是什么結果)
add edi,3
cmp byte ptr [esi+1],0 ;如果esi的下一個還是0,則說明遇到了0 0表示全部結束
jnz next_string ;否則繼續輸出下一個字符串
inc edi
stosb
invoke StdOut, hMem ;最后顯示結果
invoke GetFileSize,[hStdin],ebx
mov edi,hMem
invoke ReadFile,[hStdin],edi, eax,offset nwritten, ebx
add edi,[nwritten]
mov byte ptr [edi],0
invoke StdOut, hMem
invoke VirtualFree,hMem,1000,MEM_RELEASE
;暫停顯示,回車鍵關閉
invoke StdIn,addr szBuffer,sizeof szBuffer
invoke ExitProcess,0
StdOut proc bufOffs:dword
invoke lstrlen,bufOffs
invoke WriteFile,[hStdOut],bufOffs,eax,offset nwritten,0
ret
StdOut endp
end START
運行結果:
問題是在最上方出現了奇怪的字符 “=::=::\”是我的程序出錯了嗎?經過一番努力,還是沒有搞清楚,于是祭出利器 OllyDBG。這是一款Ring3級別的程序調試器。(此處省略1000字有點介紹)
用法很簡單,使用 File-->Open 選定程序
1號部分是反編譯結果,看起來基本上就是我們的Source Code,2號部分是寄存器信息,3號部分是當前內存的信息,4號部分是堆棧信息,5號是“顯示反匯編窗口中選中的第一個命令的參數及一些跳轉目標地址、字串等”。讀者可以參考http://bbs.pediy.com/showthread.php?s=&threadid=21284 《CCDebuger的OllyDBG入門教學》
單步執行是 F7 或者 F8鍵,他們的區別在于,前者會進入call xxx這樣的調用,而F8則會進入運行后再出來停在call語句的下一條。
我們想知道,調用過API后,返回的內存環境變量是什么樣子的,需要在下圖的地方下一個斷點方法就是雙擊下圖圓圈處,左邊就會變為紅色,表示已經斷在這個地方了。
然后我們再使用F9,讓他自動運行,到這個地方會停下來,再按一次 F8 就會調用這個API并且停在這條語句后面(當然,更方便的方法是直接在后面的那條語句處下斷點,直接運行過去)察看寄存器運行結果:
面熟啊! EAX 給出塊的起始地址(這樣說比“EAX是指向內存塊的指針”更容易理解一點吧?)
我們在下面顯示內存信息的窗口(3號部分),點鼠標右鍵,選擇 Go to-->Exprerssion
在彈出的窗口輸入 eax,表示我要看eax中給出的內存地址的值,然后就是下面的結果:
更面熟!我們確實看到了 “=::=::\”... ...因此,程序沒有問題,不過為什么會是這樣的結果,
我也不知道了... ...
此外,更方便的方法是使用 GetEnvironmentVariable API,它能夠指定返回那個環境變量的值,
比如,可以直接返回“OS”的值“ Windows_NT”。有興趣的讀者可以試試看......
《用MasmPlus學習匯編語言》已經寫了5期了,每一期我都特意“設計”了很多“不完美”的地方,留給讀者來實現,好比我們在叢林中探險,除了指出深處的寶藏之外,還給出了很多的岔路口,我相信嘗試每一個岔路也會讓你收獲無窮。
參考:
http://msdn2.microsoft.com/en-us/library/ms683187.aspx
--------------------------------------------------------------------------------
<<<上一篇 歡迎訪問AoGo匯編小站:http://www.aogosoft.com 下一篇>>>
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -