Perl 5.16.3和5.8.7中的浮动精度差异
在使用不同版本的perl运行时,下面的代码片段给出了不同的输出:
#!/usr/bin/env perl my $number1 = 2.198696207; my $number2 = 2.134326286; my $diff = $number1 - $number2; print STDOUT "n 2.198696207 - 2.134326286: $diffn"; $number1 = 0.449262271; $number2 = 0.401361096; $diff = $number1 - $number2; print STDOUT "n 2.198696207 - 2.134326286: $diffn"; PERL 5.16.3: – perl -v This is perl 5,version 16,subversion 3 (v5.16.3) built for x86_64-linux file `which perl` /sv/app/perx/third-party/bin/perl: ELF 64-bit LSB executable,x86-64,version 1 (SYSV),dynamically linked (uses shared libs),for GNU/Linux 2.6.18,not stripped 2.198696207 - 2.134326286: 0.0643699210000004 2.198696207 - 2.134326286: 0.047901175 PERL 5.8.7: – This is perl,v5.8.7 built for i686-linux-thread-multi-64int file `which perl` /sv/app/perx/third-party/bin/perl: ELF 32-bit LSB executable,Intel 80386,for GNU/Linux 2.2.5,not stripped 2.198696207 - 2.134326286: 0.0643699209999999 2.198696207 - 2.134326286: 0.047901175 我无法找到任何说明上述两个版本之间引入的浮点数精度/舍入差异的文档. 解决方法
编辑:感谢
Mark Dickinson指出我的初步答案中的不规范.由于他的侦探工作,结论发生了变化.非常感谢
ikegami对初步分析的怀疑.
总结:它因为字符串中的小差异而双重对话.看起来这些差异是由32位和64位运行时相同代码的不同行为引起的. 细节
这是用于32位架构的Perl
这适用于64位架构. 这意味着这些Perl版本是针对不同的CPU架构构建的,可能是不同的编译时选项.这可能会导致浮点运算的精度不同.但正如ikegami的评论所指出的那样,它也可能与字符串到双重对话有关. 有关架构之间的差异,请参阅Problem with floating-point precision when moving from i386 to x86_64或 x87 FPU vs. SSE2 on Wikipedia. 我在同一台计算机上使用相同版本的Ubuntu(15.10)在LXC容器内完成了以下测试,但一个用于32位,另一个用于64位. # on 32 bit bit $perl -v This is perl 5,version 20,subversion 2 (v5.20.2) built for i686-linux-gnu-thread-multi-64int $perl -V:nvsize $nvsize='8'; $perl -E 'say 2.198696207-2.134326286' 0.0643699209999999 # on 64 bit $perl -v This is perl 5,subversion 2 (v5.20.2) built for x86_64-linux-gnu-thread-multi $perl -V:nvsize $nvsize='8'; $perl -E 'say 2.198696207-2.134326286' 0.0643699210000004 这表明差异与Perl版本或使用的浮点大小无关.为了获得更多细节,我们使用unpack(‘H *’,pack(‘N’,$double)查看数字的内部表示. 32 bit: 2.198696207 -> 0xe*5*3b7709ee960140 64 bit: 2.198696207 -> 0xe*6*3b7709ee960140 这意味着数字的内部表示在64位和32位上是不同的.这可能是由于使用了不同的函数,因为对不同平台进行了优化,或者因为相同的函数在32位和64位上表现略有不同.使用libc函数atof进行检查表明,这也会在64位上返回0xe53b7709ee960140,因此看起来Perl正在使用不同的函数进行对话. 深入挖掘表明,我在两个平台上使用的Perl都设置了USE_PERL_ATOF,表明Perl正在使用自己的atof函数实现.可以在here找到该函数的一些当前实现的源代码. 看看这段代码,很难看出32位和64位的表现如何.但是有一个重要的平台相关值,它表示在将无符号整数添加到浮点的内部表示之前,实现将在unsigned int中累积多少数据: #define MAX_ACCUMULATE ( (UV) ((UV_MAX - 9)/10)) 显然,UV_MAX在32位和64位上是不同的,因此它将在32位中引起不同的累加步骤,这导致不同的浮点加法以及潜在的精度问题.我的猜测是,它以某种方式解释了32位和64位之间行为的微小差异. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |