Delphi程式碼最佳化(三) 浮點篇 (轉)

worldblog發表於2007-12-06
Delphi程式碼最佳化(三) 浮點篇 (轉)[@more@]

撰文/杜嵩 月光轉載自員雜誌第三期

忘掉extended

  extended很大(10位元組,如果程式碼對齊就有12位元組),讀寫運算都很慢,是的大敵。且2-4對extended的程式碼對齊有。因此,若非必要,不要用extended。
  同時,在混合浮點型別的運算中,為了不丟失精度,臨時變數以extended型別,所以要避免混合浮點運算。
  還有,用const定義的常量,如不加指明,則也預設為extended型別。解決辦法是,配合$J指示字,定義指明型別常量(typed constand)。

改變FPU控制字

  預設的FPU控制字令除法運算和PII/PIII上的平方根運算慢而精確,當無須得到這樣的結果時,可用Set8087CW讓FPU“偷懶”。
對於Single型別:Set8087CW(Default8087CW and $FCFF)
對於Double型別:Set8087CW((Default8087CW and $FCFF) or $0200)
對於extended型別:Set8087CW(Default8087CW or $0300)

多用Round

  Trunc會讀寫FPU指令字,而Round不會,所以可以的話,儘量用Round。

傳送實參

  對於返回浮點值的,入口和出口處會有附加的壓棧退棧,對形如:
function func(x : SomeType): SomeFloat;
  不妨改寫為:
procedure func(x : SomeType; var fp : SomeFloat);
  對於在過程中未修改的浮點形參,沒必要用const修飾,因為那除了增加一個編譯期檢查外,別無用處。相應的對策是用var修飾為實參,強制傳址。

自己動手,豐衣足食

  Delphi本身不對浮點運算作任何最佳化,因此很多時候,還得自己用來解決。
  值得注意的是,Delphi中浮點異常的觸發,不是在出錯之後,而是在下一條浮點指令之前。因此,通常的作法是,在一次浮點操作完畢後,加一條FWAIT指令。

減少除法

  除法,即多次的減法,其代價是相當昂貴的,因而有必要減少除法的次數。
  另外,對於簡單除法(如:a/5),編譯器不一定(?!)會將其變為乘法(a*0.2),比如:
  fp:=fp*3*4/5+3*4/2;
  在Delphi 4中,會被編譯為:
  fp:=fp*3*4/5+6;
  而只有:
  fp:=3*4/5*fp+3*4/2;
  才會被編譯為:
  fp:=2.4*fp+6;
  鑑於編譯器的繁複規則,建議這一步最佳化自己完成。

浮點零的檢查

  檢查一個浮點數是否為零,如果簡單的“Afloat=0”,會把0轉換為浮點零。而更好的辦法是這樣:
  對於Single型別:(D(pointer(Asingle))shl 1) =0
  對於Double型別:
type
  DoubleData=record lo,hi:Dword end;
Var
  ADouble:Double;
  Dd:DoubleData absolute Adouble;
begin
  …
  if ((dd.hi shl 1)+dd.lo)=0 then …
end;
  此法在PII上有30%-40%的提升。


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

相關文章