目錄

名稱

perlnumber - Perl 中數字和數字運算的語意

語法

$n = 1234;		    # decimal integer
$n = 0b1110011;	    # binary integer
$n = 01234;		    # octal integer
$n = 0x1234;	    # hexadecimal integer
$n = 12.34e-56;	    # exponential notation
$n = "-12.34e56";	    # number specified as a string
$n = "1234";	    # number specified as a string

說明

此文件說明 Perl 內部如何處理數字值。

此處完全忽略 Perl 的運算子重載功能。運算子重載允許使用者定義數字的行為,例如對任意大整數、任意精度的浮點數、對「特殊」數字(例如模數運算或 p 進位運算)進行運算等。詳情請參閱 overload

儲存數字

Perl 可以用 3 種不同的方式在內部表示數字:原生整數、原生浮點數和十進位字串。十進位字串可能包含指數符號部分,例如 "12.34e-56"。此處的「原生」表示「perl 編譯時使用的 C 編譯器支援的格式」。

當我們談論原生整數時,「原生」一詞的意義並不大,但當涉及原生浮點數時,意義就大了。原生整數一詞的唯一含意是,支援的最大和最小真整數量的限制接近 2 的次方。然而,「原生」浮點數有一個最基本的限制:它們只能表示那些在轉換為二進位分數時具有相對「短」表示的數字。例如,0.9 無法用原生浮點數表示,因為 0.9 的二進位分數是無限的

binary0.1110011001100...

序列 1100 不斷重複。除了這個限制之外,當二進位數表示為浮點數時,其指數也受到限制。在典型的硬體上,浮點數值可以儲存最多 53 個二進位數,且二進位指數介於 -1024 和 1024 之間。在十進位表示中,這接近於 16 個十進位數,且十進位指數在 -304..304 範圍內。所有這些的結果是,Perl 無法在這些架構上將像 12345678901234567 這樣的數字儲存為浮點數,而不會造成資訊遺失。

類似地,十進制字串只能表示具有有限小數展開的數字。由於它們是字串,因此長度可以任意,這些數字的指數或小數位數沒有實際限制。(但請注意,我們正在討論這些數字的儲存規則。您可以儲存如此「大」的數字,並不表示對這些數字執行的運算會使用所有有效數字。有關詳細資訊,請參閱「數字運算子與數字轉換」。)

事實上,儲存在原生整數格式中的數字可以儲存在有號原生格式或無號原生格式中。因此,儲存在原生整數中的 Perl 數字的限制通常為 -2**31..2**32-1,對於 64 位元整數則有適當的修改。同樣地,這並不表示 Perl 只可以對此範圍內的整數執行運算:可以在浮點格式中儲存更多整數。

總而言之,Perl 數字值只能儲存具有有限小數展開或「短」二進制展開的數字。

數字運算子與數字轉換

如前所述,Perl 可以使用三種格式儲存數字,但大多數運算子通常只了解其中一種格式。當數字值作為參數傳遞給此類運算子時,它會轉換為運算子了解的格式。

可以進行六種此類轉換

native integer        --> native floating point	(*)
native integer        --> decimal string
native floating_point --> native integer		(*)
native floating_point --> decimal string		(*)
decimal string        --> native integer
decimal string        --> native floating point	(*)

這些轉換受以下一般規則支配

限制:上面標記為(*)的轉換涉及 C 編譯器執行的步驟。特別是,所使用的編譯器的錯誤/功能可能會導致上述某些規則中斷。

Perl 數字運算的類型

Perl 操作會將數字參數視為四種不同的方式之一:強制轉換為整數、浮點數或字串格式;或者根據運算元的格式而有不同的行為。強制將數字值轉換為特定格式並不會改變儲存在該值中的數字。

所有需要整數格式參數的運算子都會將參數視為模數運算,例如在 32 位元架構上為 mod 2**32。因此,sprintf "%u", -1 會提供與 sprintf "%u", ~0 相同的結果。

算術運算子

二元運算子 + - * / % == != > < >= <= 和一元運算子 - abs-- 會嘗試將參數轉換為整數。如果兩個轉換都可以在不喪失精確度的情況下進行,且運算可以在不喪失精確度的情況下執行,則會使用整數結果。否則,參數會轉換為浮點數格式,並使用浮點數結果。轉換快取(如上所述)表示整數轉換不會丟棄浮點數的小數部分。

++

++ 的行為與上述其他運算子相同,但如果它是一個符合 /^[a-zA-Z]*[0-9]*\z/ 格式的字串,則會使用 perlop 中所述的字串遞增。

use integer 期間的算術運算子

在強制使用 use integer; 的範圍中,上面列出的幾乎所有運算子都會強制將其參數轉換為整數格式,並傳回整數結果。例外情況是 abs++--,它們在使用 use integer; 時不會改變其行為。

其他數學運算子

例如 **sinexp 等運算子會強制參數轉換為浮點數格式。

位元運算子

如果參數不是字串,則會強制轉換為整數格式。

use integer 期間的位元運算子

強制參數轉換為整數格式。此外,位元運算內部使用有號整數,而非預設的無號整數。

預期為整數的運算子

強制參數轉換為整數格式。例如,這適用於 sysread 的第三個和第四個參數。

預期為字串的運算子

強制參數轉換為字串格式。例如,這適用於 printf "%s", $value

儘管強制參數轉換為特定格式不會變更儲存的數字,但 Perl 會記住此類轉換的結果。特別是,儘管第一次此類轉換可能會花費時間,但重複的運算不需要重新執行轉換。

作者

Ilya Zakharevich ilya@math.ohio-state.edu

Gurusamy Sarathy <gsar@ActiveState.com> 的編輯調整

Nicholas Clark <nick@ccl4.org> 的 5.8.0 更新

另請參閱

overloadperlop