如何在 Perl 中强制使用 long double
How to force long double in Perl
我在做算术或尝试打印(调试)这么大的数字时失去了精度:
1234567890.123456789
我认为我的问题在于 $d(算术结果)和 $e 的格式化打印。
我怎样才能强制长双打?我的 Perl 版本(SUN 上的 5.8.4)说这是可能的。
sprintf 有一个用于长双打(q 或 L 或 ll)的大小选项,但我还没有弄清楚如何使用它,也不知道它是否适用于 printf。
编辑: 我添加了 BigFloat,效果很好!但我还是想强制长双打。
尝试加上 1234567890 + 0.123456789
并减去 1234567890 - 0.123456789.
use Config;
use Math::BigFloat;
$a = 1234567890;
$b = 123456789;
$c = $b/1e9; # 0.123456789
$d = $a + $c; # not enough precision (32-bit or double?)
$e = sprintf("%d.%.9d",$a,$b); # combine as strings
$f = 1234567890.123456789; # for reference (not enough precision)
# Use BigFloat to bypass lack of longdbl
$aBig = Math::BigFloat->new("$a");
$dSum = $aBig->fadd("$c"); # $dSum = $a + $c
$aBig = Math::BigFloat->new("$a"); # <-- Need a new one for every operation?
$dDif = $aBig->fsub(abs("$c")); # $dDif = $a - $c
print "a $a\n"; # 1234567890
print "c $c\n"; # 0.123456789
print "d=a+c $d\n"; # 1234567890.12346 <-- **Problem**
print "dSum=a+c $dSum\n"; # 1234567890.123456789 <-- Solution
print "dDif=a-c $dDif\n"; # 1234567890.876543211 <-- Solution
print "e $e\n"; # 1234567890.123456789
print "f $f\n"; # 1234567890.12346 <-- double, 52-bit, not longdbl?
printf ("printf e 20.9f %20.9f\n",$e); # 1234567890.123456717 <-- **Problem**
printf ("printf dSum 20.9f %20.9f\n",$dSum); # 1234567890.123456717 <-- **Problem**
printf ("printf dSum 20s %20s\n",$dSum); # 1234567890.123456789
printf ("printf dDif 20.9f %20.9f\n",$dDif); # 1234567890.876543283 <-- **Problem**
printf ("printf dDif 20s %20s\n",$dDif); # 1234567890.876543211
print "uselongdouble $Config{uselongdouble}\n"; # empty. No long doubles by default
print "d_longdbl $Config{d_longdbl}\n"; # "define". Supports long doubles
print "size double longdbl $Config{doublesize} $Config{longdblsize}\n"; # Ans 8 16
我也使用这段代码来尝试理解类型,但没有太大帮助。有没有人用它来解释这样的问题?
use Devel::Peek 'Dump';
Dump ($dSum); # Wow, it's complicated
Dump ($f);
bignum 将重载当前范围内的所有运算符以使用任意精度整数和浮点运算。
use bignum;
my $f = 123456789.123456789;
print "$f\n"; # 123456789.123456789
print $f + $f, "\n"; # 246913578.246913578
在幕后,bignum 将所有数字常量适当地转换为 Math::BigInt 和 Math::BigNum 对象。
重要的是要注意 bignum 是词法范围的并且不会影响整个程序。例如...
{
use bignum;
$f = 123456789.123456789; # $f is a Math::BigNum object
}
$g = 123456789.123456789; # $g is a regular NV
print "$f\n"; # 123456789.123456789
print "$g\n"; # 123456789.123457
# This will use Math::BigNum's addition method, but $g has already lost precision.
print $f + $g, "\n"; # 246913578.246913789
通过对某些操作使用 Math::BigInt::GMP plugin to use the GNU Multiple Precision Arithmetic Library,您可以获得更好的性能。您必须首先使用正常的 CPAN 安装过程安装该模块(您不需要 GMP)。然后告诉bignum使用GMP。
use bignum lib => "GMP";
Perl 有一种 float 大小,叫做 NV
。 NV
的大小在构建 Perl 时决定。
$ perl -V:nvsize
nvsize='8';
此信息也可以通过 Config 模块在 Perl 程序中访问。
$ perl -MConfig -E'say $Config{nvsize}'
8
构建 Perl 后无法更改 NV
的大小。
在构建 Perl 时,您可以强制构建 Perl 以使用 long double
浮点数:
sh Configure -Duselongdouble ...
-or-
perlbrew install -Duselongdouble ...
-or-
perlbrew install --ld ...
如果您不想重建您的 perl
或制作一个新的,您将需要使用一个模块。我推荐 Math::LongDouble,因为它提供对原生 long double
浮点数的访问,并且尽可能透明。
另一种选择是使用任意精度的库,例如 Math::BigFloat,但如果您只需要 long double
.
,那会比必要的慢
我在做算术或尝试打印(调试)这么大的数字时失去了精度: 1234567890.123456789
我认为我的问题在于 $d(算术结果)和 $e 的格式化打印。 我怎样才能强制长双打?我的 Perl 版本(SUN 上的 5.8.4)说这是可能的。 sprintf 有一个用于长双打(q 或 L 或 ll)的大小选项,但我还没有弄清楚如何使用它,也不知道它是否适用于 printf。
编辑: 我添加了 BigFloat,效果很好!但我还是想强制长双打。
尝试加上 1234567890 + 0.123456789 并减去 1234567890 - 0.123456789.
use Config;
use Math::BigFloat;
$a = 1234567890;
$b = 123456789;
$c = $b/1e9; # 0.123456789
$d = $a + $c; # not enough precision (32-bit or double?)
$e = sprintf("%d.%.9d",$a,$b); # combine as strings
$f = 1234567890.123456789; # for reference (not enough precision)
# Use BigFloat to bypass lack of longdbl
$aBig = Math::BigFloat->new("$a");
$dSum = $aBig->fadd("$c"); # $dSum = $a + $c
$aBig = Math::BigFloat->new("$a"); # <-- Need a new one for every operation?
$dDif = $aBig->fsub(abs("$c")); # $dDif = $a - $c
print "a $a\n"; # 1234567890
print "c $c\n"; # 0.123456789
print "d=a+c $d\n"; # 1234567890.12346 <-- **Problem**
print "dSum=a+c $dSum\n"; # 1234567890.123456789 <-- Solution
print "dDif=a-c $dDif\n"; # 1234567890.876543211 <-- Solution
print "e $e\n"; # 1234567890.123456789
print "f $f\n"; # 1234567890.12346 <-- double, 52-bit, not longdbl?
printf ("printf e 20.9f %20.9f\n",$e); # 1234567890.123456717 <-- **Problem**
printf ("printf dSum 20.9f %20.9f\n",$dSum); # 1234567890.123456717 <-- **Problem**
printf ("printf dSum 20s %20s\n",$dSum); # 1234567890.123456789
printf ("printf dDif 20.9f %20.9f\n",$dDif); # 1234567890.876543283 <-- **Problem**
printf ("printf dDif 20s %20s\n",$dDif); # 1234567890.876543211
print "uselongdouble $Config{uselongdouble}\n"; # empty. No long doubles by default
print "d_longdbl $Config{d_longdbl}\n"; # "define". Supports long doubles
print "size double longdbl $Config{doublesize} $Config{longdblsize}\n"; # Ans 8 16
我也使用这段代码来尝试理解类型,但没有太大帮助。有没有人用它来解释这样的问题?
use Devel::Peek 'Dump';
Dump ($dSum); # Wow, it's complicated
Dump ($f);
bignum 将重载当前范围内的所有运算符以使用任意精度整数和浮点运算。
use bignum;
my $f = 123456789.123456789;
print "$f\n"; # 123456789.123456789
print $f + $f, "\n"; # 246913578.246913578
在幕后,bignum 将所有数字常量适当地转换为 Math::BigInt 和 Math::BigNum 对象。
重要的是要注意 bignum 是词法范围的并且不会影响整个程序。例如...
{
use bignum;
$f = 123456789.123456789; # $f is a Math::BigNum object
}
$g = 123456789.123456789; # $g is a regular NV
print "$f\n"; # 123456789.123456789
print "$g\n"; # 123456789.123457
# This will use Math::BigNum's addition method, but $g has already lost precision.
print $f + $g, "\n"; # 246913578.246913789
通过对某些操作使用 Math::BigInt::GMP plugin to use the GNU Multiple Precision Arithmetic Library,您可以获得更好的性能。您必须首先使用正常的 CPAN 安装过程安装该模块(您不需要 GMP)。然后告诉bignum使用GMP。
use bignum lib => "GMP";
Perl 有一种 float 大小,叫做 NV
。 NV
的大小在构建 Perl 时决定。
$ perl -V:nvsize
nvsize='8';
此信息也可以通过 Config 模块在 Perl 程序中访问。
$ perl -MConfig -E'say $Config{nvsize}'
8
构建 Perl 后无法更改 NV
的大小。
在构建 Perl 时,您可以强制构建 Perl 以使用 long double
浮点数:
sh Configure -Duselongdouble ...
-or-
perlbrew install -Duselongdouble ...
-or-
perlbrew install --ld ...
如果您不想重建您的 perl
或制作一个新的,您将需要使用一个模块。我推荐 Math::LongDouble,因为它提供对原生 long double
浮点数的访问,并且尽可能透明。
另一种选择是使用任意精度的库,例如 Math::BigFloat,但如果您只需要 long double
.