如何修复此代码以便1.1 + 2.2 == 3.3?这里发生了什么导致这种行为?我模糊地熟悉舍入问题和浮点数学,但我认为这仅适用于除法和乘法,并且在输出中可见.
[me@unixbox1:~/perltests]> cat testmathsimple.pl
#!/usr/bin/perl
use strict;
use warnings;
check_math(1, 2, 3);
check_math(1.1, 2.2, 3.3);
sub check_math {
my $one = shift;
my $two = shift;
my $three = shift;
if ($one + $two == $three) {
print "$one + $two == $three\n";
} else {
print "$one + $two != $three\n";
}
}
[me@unixbox1:~/perltests]> perl testmathsimple.pl
1 + 2 == 3
1.1 + 2.2 != 3.3
Run Code Online (Sandbox Code Playgroud)
编辑:
到目前为止,大多数答案都是"它是一个浮点问题,duh",并为它提供了解决方法.我已经怀疑是问题所在.我该如何演示?如何让Perl输出长形式的变量?将$ one + $ 2计算存储在临时变量中并打印它并不能证明问题.
编辑:
使用aschepler演示的sprintf技术,我现在能够"看到"问题.此外,根据mscha和rafl的建议,使用bignum可以解决比较不相等的问题.但是,sprintf输出仍然表示数字不正确.这对这个解决方案留下了一点疑问.
bignum是解决这个问题的好方法吗?是否有任何可能的副作用,我们在将其整合到一个更大的,现有的程序时应该注意什么?
以下perl代码将浮点数转换为错误的整数
use strict;
my $zahl =297607.22000;
$zahl=$zahl * 100;
print "$zahl\n";
my $text=sprintf ("%017d",$zahl);
print $text;
Run Code Online (Sandbox Code Playgroud)
这个输出是:
29760722
00000000029760721
Run Code Online (Sandbox Code Playgroud)
问题是,您可以将给定的数字更改为其他数字,它可以正常工作.
知道这里有什么问题或者Perl做错了吗?
谢谢你的帮助!
我在Perl中遇到了一个奇怪的行为.以下减法应该得到零作为结果(它在Python中):
print 7.6178E-01 - 0.76178
-1.11022302462516e-16
Run Code Online (Sandbox Code Playgroud)
它为什么会发生以及如何避免它?
PS Effect出现在"为x86_64-linux-gnu-thread-multi构建的v5.10.0"(Ubuntu 9.04)和"为darwin-2level构建的v5.8.9"(Mac OS 10.6)
我将输出写入文件,而不是printf,但它仍然将output1作为2.
my $ramount = 2.01;
$ramount = int($ramount*100)/100;
printf "output1: $ramount";
Run Code Online (Sandbox Code Playgroud)
我的脚本应该做以下.它需要一个旧的标量列表,并创建一个新的,相应的数字列表.旧列表称为@oldMarkers,新列表称为@newMarkers.
示例输入如下: chr1, chr2, IMP, chr3, IMP, IMP, IMP, chr4
示例输出如下: 1, 2, 2.1, 3, 3.1, 3.2, 3.3, 4
脚本的要点是读取@oldMarkers列表并输出一个列表,其中对于包含字母"chr"的元素的每个实例,一个整数被推入数组@newMarkers.对于@oldMarkers中IMP的每个实例,都会向@newMarkers添加一个十进制数.新的十进制数与前面的数字具有相同的"基本整数",但添加了.1.换句话说,"IMP"的多个后续实例应该具有与最近读取的"chr"条目相同的整数,其上加上小数值,计算与最近"chr"对应的IMP的数量.条目.
下面的脚本几乎100%工作.它甚至通常在以下实例中工作.在@oldMarkers的一些地方,IMP有很多条目.当一行中有超过10个IMP时,代码应该将值推送到@newMarkers,以便该条目块的所有"IMP"具有相同的整数,这也与最近对应的数字相匹配.在@oldMarkers中读取"chr"的实例.对于整数,添加0.1.当小数的值达到.9时,小数"重新开始"回到.1并从那里上升,直到IMP条目的延伸结束.
例如,如果@oldMarkers有一个13"IMP"的块,并且是:
chr1, chr2, IMP, IMP, IMP, IMP, IMP, IMP, IMP, IMP, IMP, IMP, IMP, IMP, IMP, chr2
然后@newMarkers应该是:
1, 2, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 2.1, 2.2, 2.3, 2.4, 3
脚本摘要:
原始文件包含多行两个元素.第一个元素并不重要,因此在代码中跳过了.每行的第二个元素是一个ID,可以是"chr4"或"IMP".甲while循环读取每一行,将第二元件到阵列@oldMarkers.
然后,按条目读取此数组.该脚本首先询问@newMarkers中的条目是否与原始@oldMarker列表中的"chr"或"IMP"相对应.这是通过第一个if和第一个完成的else.
接下来,对于这两个条件,进一步询问该条目是否跟随对应于"chr"或"IMP"条目的数字本身.这是通过在第一个这样的集合中嵌入if和else设置来完成的.
然后定义新元素并将其推送到@newMarker,具体取决于条件.
就像我说的,这主要是有效的.但是,有时,当IMP的延伸超过10时,脚本不会"回收"小数.相反,它将.1添加到前一个值并输入一个新的整数整数.但对于超过10的其他延伸,它工作正常.它与这个"错误"不一致.
你能发现问题吗?
my @oldMarkers = ();
my @newMarkers = (); …Run Code Online (Sandbox Code Playgroud) #!/usr/bin/perl
$l1 = "0+0.590580+0.583742+0.579787+0.564928+0.504538+0.459805+0.433273+0.384211+0.3035810";
$l2 = "0+0.590580+0.583742+0.579788+0.564928+0.504538+0.459805+0.433272+0.384211+0.3035810";
$val1 = eval ($l1);
$val2 = eval ($l2);
$diff = (($val1 - $val2)/$val1)*100;
print " (($val1 - $val2)/$val1)*100 ==> $diff\n";
Run Code Online (Sandbox Code Playgroud)
令人惊讶的是,输出最终结果是
((4.404445 - 4.404445)/4.404445)*100 ==> -2.01655014354845e-14.
Run Code Online (Sandbox Code Playgroud)
它不应该是一个零吗???? 请任何人解释一下......
#include<stdio.h>
int main()
{
double fract=0;
int tmp;
//scanf("%lf",&fract);
fract=0.312;
printf("%lf",fract);
printf("\n\n");
while(fract>0){
fract*=(double)10;
printf("%d ",(int)fract);
fract-=(int)fract;
}
getch();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这段代码的输出为:312
但是somehing不对..我正在使用devcpp 4.9.9.2编译器......