⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 用masmplus 学习汇编语言(5) .txt

📁 会变语言实现的一些程序
💻 TXT
📖 第 1 页 / 共 2 页
字号:


 



这个程序还不完美,我们还可以调整一下颜色,看得好看一些,还可以改造一下,

改为三叉树,或者改为随机的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指向一个新开辟的内存块
mov al,[esi]
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 + -