Delphi程式碼最佳化(二) 整數篇 (轉)

worldblog發表於2007-12-04
Delphi程式碼最佳化(二) 整數篇 (轉)[@more@]

程式碼(二) 整數篇

 :namespace prefix = o ns = "urn:schemas--com::office" />

儘量使用32位變數

在32位程式碼中,32位變數是預設處理格式;16位變數(,shortint,wchar)的運算會令臨時切換為16位處理,因而需要雙倍的處理時間;相較之下,8位變數(byte,char)只要不與其它混用,卻不會太慢。如果實在需要多次使用一個8或16位變數,可以考慮把它臨時轉換成32位變數,這隻需要一步賦值:ADWord:=Aword;

 

避免使用子域型別

Pascal語言的一大優勢便是其豐富的資料型別,Delphi之 Pascal繼承了這一傳統,列舉和子域型別即屬此類。但不幸的是,他們會為最佳化帶來麻煩,因為它們的佔用的位元組數取決於其子域的大小。比如一個元素數不超過256個的列舉型別會佔用1個位元組,而例如MyYear=1900..2000則會佔用兩個位元組,而如前文所述,16位變數是很慢的。

 

簡化

過於複雜的表示式會妨礙的自動最佳化,這時可以考慮引入臨時變數來化簡表示式,這樣可能(!)可以得以最佳化,更重要的是提高了程式碼的可讀性。

 

不再畏懼乘法

PII出現以前,乘法運算是相當費時的,以至於當時的經典最佳化方法便是把一類特殊的乘法轉變為移位運算和加法。而今,在作為標準的PII上,乘法和多數其它運算一樣,只需要一個指令週期即可完成。當然Delphi編譯器仍然會把諸如*2之類的運算最佳化為shl 1,這也不壞,不是嗎?

 

臨時子域型別

才揭過子域型別的短,又來說它的妙用:-p 但這也不是真正的子域型別,不過是形式上相似罷了。像以下的語句:

if  ((x>=0) and (x=<10)) or ((x>=20) and (x<=30))  then …

可以改寫為:

if  x in [0..10,20..30]  then …

子域數越多,最佳化效果越明顯。不過除了在NOI題目裡以外,天下可沒有免費餡餅,這回的代價是佔用一個臨時暫存器。

 

movzx 與 xor/mov

這是讀入小於32位資料的兩種不同方法,後者在PII以前更具優勢,而前者在PII上因其亂序的特性而顯得更有。編譯器對此的取捨規則似乎很複雜,必要時還是自己用嵌入好了。

 

大整數運算

對付大整數(超過32位的),你有四種武器(為什麼不是七種?問Borland,別來問我)——int64、comp、double和extended。其中除了64位整數型別int64外,其餘都是浮點數,其運算都是由FPU指令實現的。這其中的comp型別,結構同int64一模一樣,按照Borland的官方說法,comp型別已經過時,應當被int64所取代,理由很簡單——整數運算總比浮點快吧。然而根據一項在PII上進行的測試,int64除了在加減運算中具有無可比擬的優勢外,在乘除方面,竟比浮點數還慢!

好在還有老當益壯的comp,只是稍有些繁瑣。

首先將變數宣告為int64,並宣告兩個輔助元:

var

 a,b,c,d,e: int64;

 ca:comp absolute a;

 cc:comp absolute c;

加減法不用變,除法就如下處理:

c:=trunc(ca/b); //is faster than c:= a div b

乘法這麼來:

e:=round(ca*b+cc*d); //is faster than e:=a*b+c*d;

 


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-988197/,如需轉載,請註明出處,否則將追究法律責任。

相關文章