在算术或尝试打印(调试)这么大的数字时,我失去了精确度: 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);
答案 0 :(得分:2)
Perl有一个大小的浮点数,它被称为NV
。构建Perl时会确定NV
的大小。
$ 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
,则速度会慢一些。
答案 1 :(得分:1)
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插件将GNU Multiple Precision Arithmetic Library用于某些操作,您可以获得更好的性能。您必须首先使用正常的CPAN安装过程安装该模块(您不需要GMP)。然后告诉bignum使用GMP。
use bignum lib => "GMP";