浮點數

lua-users home
wiki

引言

時不時地在 Lua 郵件列表上,有人粗略地提問:「使用浮點數運算在整數應用程式上可以嗎?」本討論旨在減輕此類恐懼,同時也不會錯誤呈現確實存在的這些問題。

浮點數數字在 Lua 中成為唯一數字類型的主要問題在於大多數程式設計師不了解浮點數。浮點數數字比整數(定點數)還要複雜得多。大多數程式設計師對浮點數的心理模型是,運算結果有時會產生極輕微的誤差。因此,人們會因此而感到緊張。但此心理模型是錯誤的;將浮點數運算建模為「正確答案 + 雜訊」是錯誤的,特別是在處理最常見的浮點數類型 IEEE-754 時。

解決這個整體問題的方法是教育。 文件、網站、常見問答、wiki 等應該更多地強調雙精度浮點數的基本整數向後相容性。

在進一步探討之前,應注意到,儘管浮點數數字經常在 Lua 中用作數字類型,但 Lua 並不依賴浮點數,而且可以用任何一種數字類型進行編譯,例如單精度浮點數、整數,甚至是某些非常陌生的數字表示[*5]。當然,例如果您使用整數數字類型編譯 Lua,則除法等語義將發生重大變化,但這在嵌入式處理器上可能並不讓人感到意外。[*1] ARM、Coldfire 和各種類型的嵌入式 MIPS 沒有 FPU,但這些仍然很廣泛地使用。[*2]

準確度

如果您有標準的現代(2000 年)桌上型電腦,那麼您就有 IEEE 754 雙精度浮點數。[*4]

以下是關於(IEEE 754)64 位元雙精度浮點數數字(「雙精度」)與 32 位元整數的一些重點

摘要:就準確度、範圍和「向後相容性」而言,64 位元精度的浮點數運算比 32 位元整數運算更好。不過,請參閱注意事項部分。

算術運算

IEEE 754 定義基本的數學運算,+ - * (乘法)/(除法),以產生最接近準確數學答案的結果。特別是,如果答案正確可以表示為雙精度浮點數,那麼答案會是那個答案;否則,有兩個最接近準確答案的雙精度浮點數(一個高於,一個低於),其中一個會根據捨入模式選取。

對於涉及整數的運算,大多數運算都是準確的。如果我計算 2+5,則由於準確的數學答案為 7,它也是 IEEE 754 答案。

效能

大型 CPU

關於效能,現在大多數嚴肅的現代桌上型 CPU 都能處理雙倍浮點數,其速度與整數一樣快,甚至更快。這包括現代 MIPS R5000 和現代 PPC 700 和更好的處理器。常見的 FPU 運算是一時脈吞吐量。加法減法比較乘法。(更好的是,一個乘法加法指令可能會在僅 FPU 的情況下達成一時脈吞吐量,讓其比 ALU 中的整數乘法加法更快。多重位元組架構和 SIMD 可以進一步改善浮點運算。儘管這可能與 Lua 無關。)浮點乘法通常比整數乘法更快(因為浮點乘法更常用,CPU 設計人員花更多努力優化該路徑)。浮點除法可能會很慢(通常超過 10 個週期),但整數除法也是如此。

坦承來說,Intel 的 Pentium 設計名列第三(因為它的 FP 暫存器太少了)。但 Intel 正在迎頭趕上。

唯一剩下的效能考量是浮點數到整數轉換。不論你是否喜歡,記憶體載入指令都會使用一個地址和位元組位移(即兩個整數值)來運作。因此,如果 CPU 的浮點轉整數轉換效能在浮點運算中比整數運算差的話,使用浮點數代替整數進行任何效能儲存都將是徒勞的。有些說明指出,浮點轉整數轉換可能會對效能造成毀滅性的影響 [1]。(對於 gcc-3.4 和大約 2006 年的 AMD 處理器,問題已不復存在,但自行測試看看。從該連結編譯基準測試非常容易。)

記憶體

對於這些嚴肅的現代桌上型 CPU 的使用者來說,唯一主要的潛在問題剩下記憶體頻寬和記憶體使用量。假設由於這些物件在 Lua 中的儲存格(聯合結構)大小,這些考量實際上無關緊要。

這方面的硬資料會很好,例如在各種(或一種)架構下配合單精密度和雙精密度浮點數配置的適當聯合的 sizeof()

-- 在 8 位元組結構對齊的世界中,它們實際上不會佔據更多空間,儘管如果物件結構因為 FP 數值的大小而超過 64 位元組,大小問題便會「該死地」顯而易見。FP 數值在 CPU 快取中也會佔用更多空間 -- 不僅暫存器會受到影響。 -- ChuckAdams

小型 CPU

有使用較舊、較小或嵌入式 CPU 的使用者沒有浮點運算、沒有 64 位元浮點運算、CPU 模擬浮點運算,或硬體浮點運算效能很慢。這些包括 80386、68040、ARM 等。希望 luaconfig.h 功能可以滿足他們的需求。

摘要:約在 2001 年,您平均入門級 10 美元的 CPU 晶片,有能力以 64 位元雙倍的速度和準確度(或更多)執行整數運算。這些 CPU 的使用者不應只因為在 lua 中使用雙倍浮點運算而付出任何成本,且有可能獲益。較小晶片的使用者很可能會被迫在 lua 中只使用整數運算。

-- 如下所述,使用最廣泛的嵌入式 CPU 之一,大多數 ARM 晶片沒有硬體浮點運算支援。這意味著每次在 int 和 float 之間的轉換,以及每次運算都是一個函式呼叫(通常為內嵌)。雙倍運算更糟。當您考慮到 NaN 和非正規化數字的檢查時,與整數相比,其負擔相當顯著(是的,我有實際測試)。--BenStJohn?

儘管 Lua 的數字類型可以建構為整數,但在使用前建議進行實際測試,因為(即使在僅限整數的處理器上),速度提升可能不如想像中那麼顯著,而且失去浮點運算可能會讓一些運算變得更複雜。另請注意,Lua 5.3 已內建明確的整數支援功能。

eLua http://www.eluaproject.net/ 是針對某些微控制器的一個 Lua 分支,它有一個選用的整數建置功能。然而,需要注意的是,標準 Lua 也很容易建置於像 ARM7TDMI 這類核心上,因為來源是標準 C。如果必要,可以套用整數變更。

注意事項

實際效能可能有所不同。範例原因

參考資料

這些文章不依任何特定的相關順序所排列

-- MartinHollis(原作者)

腳註 / 註解


最新變更 · 偏好設定
編輯 · 歷史記錄
最後編輯時間:2017 年 11 月 2 日下午 11:58 GMT (差異)