内容

名称

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()" 方法设置,但请参见下面的 "注意事项"

用于降级和升级的类不必是 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 或 accuracy

这将为所有数学运算设置精度。参数必须大于或等于零。有关详细信息,请参见 Math::BigInt 的 bround() 方法。

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

请注意,无法同时设置精度和准确度。

p 或 precision

这将为所有数学运算设置精度。参数可以是任何整数。负值表示小数点后固定位数,而正值表示四舍五入到小数点左边的该位数。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 编译指示处于活动状态,hex() 就会在当前范围内词法覆盖。

oct

用可以处理大数字的版本覆盖内置的 oct() 方法。这通过将其导出到当前包来覆盖它。在 Perl v5.10.0 及更高版本中,这并不那么必要,因为只要 bignum 编译指示处于活动状态,oct() 就会在当前范围内词法覆盖。

v 或 version

这会打印出模块的名称和版本,然后退出。

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 或更高版本。

注意事项

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(以及此模块)接受十六进制、八进制和二进制浮点数字面量,但在 Perl 版本低于 v5.32.0 时谨慎使用它们,因为某些版本的 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 版本低于 v5.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 的 Web 界面(需要登录)。我们会收到通知,然后您会在我对错误进行更改时自动收到进度通知。

支持

您可以使用 perldoc 命令找到此模块的文档。

perldoc bignum

您也可以在以下位置查找信息

许可证

此程序是自由软件;您可以根据与 Perl 本身相同的条款重新分发和/或修改它。

另请参阅

bigintbigrat

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

作者