內容

名稱

bignum - Perl 的透明大數字支援

語法

use bignum;

$x = 2 + 4.5;                       # Math::BigFloat 6.5
print 2 ** 512 * 0.1;               # Math::BigFloat 134...09.6
print 2 ** 512;                     # Math::BigInt 134...096
print inf + 42;                     # Math::BigInt inf
print NaN * 7;                      # Math::BigInt NaN
print hex("0x1234567890123490");    # Perl v5.10.0 or later

{
    no bignum;
    print 2 ** 256;                 # a normal Perl scalar now
}

# for older Perls, import into current package:
use bignum qw/hex oct/;
print hex("0x1234567890123490");
print oct("01234567890123490");

說明

文字數字常數

預設情況下,每個文字整數都會變成 Math::BigInt 物件,而文字非整數則會變成 Math::BigFloat 物件。數字文字是否被視為整數或非整數僅取決於常數的值,而不取決於其表示方式。例如,常數 3.14e2 和 0x1.3ap8 會變成 Math::BigInt 物件,因為它們都表示十進位數值 314。

預設的 use bignum; 等於

use bignum downgrade => "Math::BigInt", upgrade => "Math::BigFloat";

用於整數和非整數的類別可以在編譯時使用 downgradeupgrade 選項設定,例如

# use Math::BigInt for integers and Math::BigRat for non-integers
use bignum upgrade => "Math::BigRat";

請注意,停用降級和升級不會影響數字文字如何轉換為物件

# disable both downgrading and upgrading
use bignum downgrade => undef, upgrade => undef;
$x = 2.4;       # becomes 2.4 as a Math::BigFloat
$y = 2;         # becomes 2 as a Math::BigInt

升級和降級

預設情況下,當運算結果為整數、Inf 或 NaN 時,即使所有運算元都是升級類別的實例,結果也會降級。

use bignum;
$x = 2.4;       # becomes 2.4 as a Math::BigFloat
$y = 1.2;       # becomes 1.2 as a Math::BigFloat
$z = $x / $y;   # becomes 2 as a Math::BigInt due to downgrading

等效地,預設情況下,當運算結果為有限非整數時,即使所有運算元都是降級類別的執行個體,結果也會升級。

use bignum;
$x = 7;         # becomes 7 as a Math::BigInt
$y = 2;         # becomes 2 as a Math::BigInt
$z = $x / $y;   # becomes 3.5 as a Math::BigFloat due to upgrading

用於降級和升級的類別可以在執行階段使用 "downgrade()""upgrade()" 方法設定,但請參閱以下 "CAVEATS"

升級和降級類別不必是 Math::BigInt 和 Math::BigFloat。例如,若要使用 Math::BigRat 作為升級類別,請使用

use bignum upgrade => "Math::BigRat";
$x = 2;         # becomes 2 as a Math::BigInt
$y = 3.6;       # becomes 18/5 as a Math::BigRat

升級和降級類別可以在執行階段修改

use bignum;
$x = 3;         # becomes 3 as a Math::BigInt
$y = 2;         # becomes 2 as a Math::BigInt
$z = $x / $y;   # becomes 1.5 as a Math::BigFlaot

bignum -> upgrade("Math::BigRat");
$w = $x / $y;   # becomes 3/2 as a Math::BigRat

停用降級不會改變文字常數整數轉換為降級類別的事實,它只會防止運算結果降級。例如,

use bignum downgrade => undef;
$x = 2;         # becomes 2 as a Math::BigInt
$y = 2.4;       # becomes 2.4 as a Math::BigFloat
$z = 1.2;       # becomes 1.2 as a Math::BigFloat
$w = $x / $y;   # becomes 2 as a Math::BigFloat due to no downgrading

如果您希望所有數字文字(整數和非整數)都變成 Math::BigFloat 物件,請使用 bigfloat 實用程式。

等效地,停用升級不會改變文字常數非整數轉換為升級類別的事實,它只會防止運算結果升級。例如,

use bignum upgrade => undef;
$x = 2.5;       # becomes 2.5 as a Math::BigFloat
$y = 7;         # becomes 7 as a Math::BigInt
$z = 2;         # becomes 2 as a Math::BigInt
$w = $x / $y;   # becomes 3 as a Math::BigInt due to no upgrading

如果您希望所有數字文字(整數和非整數)都變成 Math::BigInt 物件,請使用 bigint 實用程式。

您甚至可以執行

use bignum upgrade => "Math::BigRat", upgrade => undef;

這會將所有整數文字轉換為 Math::BigInt 物件,並將所有非整數文字轉換為 Math::BigRat 物件。但是,當涉及兩個 Math::BigInt 物件的運算結果為非整數時(例如,7/2),結果將被截斷為 Math::BigInt,而不是升級為 Math::BigRat,因為升級已停用。

重載

由於所有數字文字都變成物件,因此您可以從 Math::BigInt 和 Math::BigFloat 呼叫所有常用的方法。這甚至在某種程度上適用於表達式

perl -Mbignum -le '$x = 1234; print $x->bdec()'
perl -Mbignum -le 'print 1234->copy()->binc();'
perl -Mbignum -le 'print 1234->copy()->binc()->badd(6);'

選項

bignum 識別一些選項,可以在透過 use 載入時傳遞。下列選項存在

a 或準確度

這會設定所有數學運算的準確度。引數必須大於或等於零。請參閱 Math::BigInt 的 bround() 方法以取得詳細資訊。

perl -Mbignum=a,50 -le 'print sqrt(20)'

請注意,同時設定精度和準確度是不可能的。

p 或精度

這會設定所有數學運算的精度。引數可以是任何整數。負值表示小數點後固定位數,而正值則從小數點左邊四捨五入到此位數。0 表示四捨五入為整數。請參閱 Math::BigInt 的 bfround() 方法以取得詳細資訊。

perl -Mbignum=p,-50 -le 'print sqrt(20)'

請注意,同時設定精度和準確度是不可能的。

l、lib、try 或 only

載入不同的數學函式庫,請參閱 "數學函式庫"

perl -Mbignum=l,GMP -e 'print 2 ** 512'
perl -Mbignum=lib,GMP -e 'print 2 ** 512'
perl -Mbignum=try,GMP -e 'print 2 ** 512'
perl -Mbignum=only,GMP -e 'print 2 ** 512'
hex

使用可處理大數字的版本覆寫內建 hex() 方法。這會透過將其匯出至目前套件來覆寫它。在 Perl v5.10.0 及更新版本中,這並非必要,因為只要 bignum pragma 處於作用中,hex() 便會在目前範圍內以字面方式覆寫。

oct

使用可處理大數字的版本覆寫內建 oct() 方法。這會透過將其匯出至目前套件來覆寫它。在 Perl v5.10.0 及更新版本中,這並非必要,因為只要 bignum pragma 處於作用中,oct() 便會在目前範圍內以字面方式覆寫。

v 或版本

這會列印出模組的名稱和版本,然後結束。

perl -Mbignum=v

數學函式庫

與數字相關的數學運算(預設情況下)是由後端函式庫模組 Math::BigInt::Calc 執行。預設值等同於說

use bignum lib => 'Calc';

你可以使用下列方式變更:

use bignum lib => 'GMP';

下列會先嘗試尋找 Math::BigInt::Foo,然後是 Math::BigInt::Bar,如果也失敗,則改用 Math::BigInt::Calc

use bignum lib => 'Foo,Math::BigInt::Bar';

使用 c<lib> 會在找不到任何指定的函式庫時發出警告,而 Math::BigIntMath::BigFloat 則會改用預設函式庫之一。若要抑制此警告,請改用 try

use bignum try => 'GMP';

如果你希望程式碼在改用時中斷,請改用 only

use bignum only => 'GMP';

請參閱各模組文件以取得進一步詳細資料。

方法呼叫

由於所有數字現在都是物件,因此你可以使用 Math::BigInt 和 Math::BigFloat API 中的方法。

但須注意。使用下列方式複製數字時,只會建立淺層副本。

$x = 9; $y = $x;
$x = $y = 7;

使用副本或原始值搭配超載數學運算沒問題,例如,下列運算會成功

$x = 9; $y = $x;
print $x + 1, " ", $y,"\n";     # prints 10 9

但呼叫任何會直接修改數字的方法,都會導致同時摧毀原始值和副本

$x = 9; $y = $x;
print $x->badd(1), " ", $y,"\n";        # prints 10 10

$x = 9; $y = $x;
print $x->binc(1), " ", $y,"\n";        # prints 10 10

$x = 9; $y = $x;
print $x->bmul(2), " ", $y,"\n";        # prints 18 18

使用不會修改,但會測試內容的方法

$x = 9; $y = $x;
$z = 9 if $x->is_zero();                # works fine

請參閱超載中的複製建構函式和 = 的文件,以及 Math::BigFloat 中的文件以取得進一步詳細資料。

方法

inf()

返回 inf 作為物件的捷徑。很有用,因為 Perl 並非總是能正確處理裸字 inf

NaN()

返回一個物件形式的 NaN 的捷徑。這很有用,因為 Perl 並非總是能正確地處理裸字 NaN

e
# perl -Mbignum=e -wle 'print e'

傳回歐拉數 e,又稱 exp(1) (= 2.7182818284...)。

PI
# perl -Mbignum=PI -wle 'print PI'

傳回 PI (= 3.1415926532..)。

bexp()
bexp($power, $accuracy);

傳回歐拉數 e 提升到適當的次方,達到所需的精度。

範例

# perl -Mbignum=bexp -wle 'print bexp(1,80)'
bpi()
bpi($accuracy);

傳回 PI,達到所需的精度。

範例

# perl -Mbignum=bpi -wle 'print bpi(80)'
accuracy()

設定或取得精度。

precision()

設定或取得精度。

round_mode()

設定或取得捨入模式。

div_scale()

設定或取得除法比例。

upgrade()

設定或取得降級類別升級到的類別(如果有的話)。將升級類別設定為 undef 以停用升級。請參閱下方的 /CAVEATS

downgrade()

設定或取得升級類別降級到的類別(如果有的話)。將降級類別設定為 undef 以停用升級。請參閱下方的 "CAVEATS"

in_effect()
use bignum;

print "in effect\n" if bignum::in_effect;       # true
{
    no bignum;
    print "in effect\n" if bignum::in_effect;   # false
}

如果 bignum 在目前的範圍內有效,則傳回 true 或 false。

此方法僅適用於 Perl v5.9.4 或更新版本。

CAVEATS

upgrade() 和 downgrade() 方法

請注意,使用 "upgrade()""downgrade()" 方法在執行階段同時設定升級和降級類別,可能無法達到預期的效果

# Assuming that downgrading and upgrading hasn't been modified so far, so
# the downgrade and upgrade classes are Math::BigInt and Math::BigFloat,
# respectively, the following sets the upgrade class to Math::BigRat, i.e.,
# makes Math::BigInt upgrade to Math::BigRat:

bignum -> upgrade("Math::BigRat");

# The following sets the downgrade class to Math::BigInt::Lite, i.e., makes
# the new upgrade class Math::BigRat downgrade to Math::BigInt::Lite

bignum -> downgrade("Math::BigInt::Lite");

# Note that at this point, it is still Math::BigInt, not Math::BigInt::Lite,
# that upgrades to Math::BigRat, so to get Math::BigInt::Lite to upgrade to
# Math::BigRat, we need to do the following (again):

bignum -> upgrade("Math::BigRat");

在執行階段執行此操作的較簡單方法是使用 import(),

bignum -> import(upgrade => "Math::BigRat",
                 downgrade => "Math::BigInt::Lite");
十六進位、八進位和二進位浮點數文字

Perl(和此模組)接受十六進位、八進位和二進位浮點數文字,但在 v5.32.0 之前的 Perl 版本中使用時請小心,因為某些版本的 Perl 會在不提示的情況下提供錯誤的結果。

運算子與文字重載

bigrat 透過重載整數和浮點數字面值的處理方式,將它們轉換為 Math::BigRat 物件。

這表示僅包含字串值或字串字面值的算術運算會使用 Perl 的內建運算子執行。

例如

use bigrat;
my $x = "900000000000000009";
my $y = "900000000000000007";
print $x - $y;

在預設的 32 位元建置中會輸出 0,因為 bignum 永遠不會看到字串字面值。若要確保表達式全部都視為 Math::BigFloat 物件,請在表達式中使用字面數字

print +(0+$x) - $y;
範圍

Perl 不允許重載範圍,因此您既不能安全地將範圍與 bignum 端點一起使用,迭代器變數也不是 Math::BigFloat

use 5.010;
for my $i (12..13) {
  for my $j (20..21) {
    say $i ** $j;  # produces a floating-point number,
                   # not an object
  }
}
in_effect()

此方法僅適用於 Perl v5.9.4 或更新版本。

hex()/oct()

bignum 會以可處理大整數值的版本覆寫這些常式。不過,在 Perl 5.9.4 版之前,除非您特別使用兩個匯入標籤「hex」和「oct」要求,否則不會發生這種情況 - 然後它會成為全域性的,而且無法在範圍內使用 no bignum 停用。

use bignum qw/hex oct/;

print hex("0x1234567890123456");
{
    no bignum;
    print hex("0x1234567890123456");
}

第二次呼叫 hex() 會針對不可移植的常數發出警告。

將其與下列內容比較

use bignum;

# will warn only under Perl older than v5.9.4
print hex("0x1234567890123456");

範例

一些很酷的命令列範例,用來讓 Python 群眾印象深刻 ;)

perl -Mbignum -le 'print sqrt(33)'
perl -Mbignum -le 'print 2**255'
perl -Mbignum -le 'print 4.5+2**255'
perl -Mbignum -le 'print 3/7 + 5/7 + 8/3'
perl -Mbignum -le 'print 123->is_odd()'
perl -Mbignum -le 'print log(2)'
perl -Mbignum -le 'print exp(1)'
perl -Mbignum -le 'print 2 ** 0.5'
perl -Mbignum=a,65 -le 'print 2 ** 0.2'
perl -Mbignum=l,GMP -le 'print 7 ** 7777'

錯誤

請將任何錯誤或功能要求回報至 bug-bignum at rt.cpan.org,或透過網路介面回報至 https://rt.cpan.org/Ticket/Create.html?Queue=bignum(需要登入)。我們會收到通知,然後當我進行變更時,您會自動收到錯誤進度的通知。

支援

您可以使用 perldoc 指令尋找此模組的說明文件。

perldoc bignum

您也可以在下列位置尋找資訊

授權

此程式是免費軟體;您可以在與 Perl 相同的條款下重新散布或修改它。

另請參閱

bigintbigrat

Math::BigIntMath::BigFloatMath::BigRatMath::Big,以及 Math::BigInt::FastCalcMath::BigInt::PariMath::BigInt::GMP

作者