perl不一致负零结果
我有以下代码:perl不一致负零结果,perl,floating-point,Perl,Floating Point,我有以下代码: my $m=0; my $e =0 ; my $g=0; my $x= sprintf( "%0.1f", (0.6*$m+ 0.7 * $e-1.5)*$g); print $x; 当我运行脚本时,结果是-0.0而不是0.0。有人能解释一下为什么以及如何将其更改为0.0 你遇到了非常奇怪的事情。我的第一个想法是,你看到一些非常小的负数,sprintf四舍五入到-0.0,但实际上表达式的结果是一个实际的负零 下面是一个更简单的程序,展示了相同的问题: #!/usr/bi
my $m=0;
my $e =0 ;
my $g=0;
my $x= sprintf( "%0.1f", (0.6*$m+ 0.7 * $e-1.5)*$g);
print $x;
当我运行脚本时,结果是-0.0而不是0.0。有人能解释一下为什么以及如何将其更改为0.0 你遇到了非常奇怪的事情。我的第一个想法是,你看到一些非常小的负数,
sprintf
四舍五入到-0.0,但实际上表达式的结果是一个实际的负零
下面是一个更简单的程序,展示了相同的问题:
#!/usr/bin/perl
use strict;
use warnings;
my $x = -1.0 * 0.0;
my $y = -1.5 * 0.0;
printf "x = %f\n", $x;
printf "y = %f\n", $y;
以及输出:
x = 0.000000
y = -0.000000
我最好的猜测是-1.0*0.0
是在编译时计算的,而-1.5*0.0
是在执行时计算的,并且计算会产生不同的结果编辑:点击该按钮;用函数调用替换所有常量的程序的修改版本具有相同的行为
我可以通过在printf
调用之前添加以下行来避免负零显示:
$x += 0.0;
$y += 0.0;
但这很难看
(顺便说一句,我从大约一个月前的Perl 5.15.2“bleading edge”版本中得到了相同的结果。)
类似的C程序为x和y打印-0.000000
编辑:进一步的实验表明,将负整数值乘以0.0得到0.0,但将负非整数值乘以0.0得到-0.0。我提交了一份报告。非常奇怪。我注意到,如果将
1.5
替换为负整数,问题就会消失:
$ perl -e '
my @a=(-9.0, -3.0, -2.0, -1.5, -1.2, -1.0, -0.8, -0.5);
for my $a (@a) {
$bin = join("", map {sprintf("%02x", ord($_))} split(//, pack("d>", $a*0)));
printf("%4.1f * 0 = %4.1f %s\n", $a, $a*0, $bin);
}'
-9.0 * 0 = 0.0 0000000000000000
-3.0 * 0 = 0.0 0000000000000000
-2.0 * 0 = 0.0 0000000000000000
-1.5 * 0 = -0.0 8000000000000000
-1.2 * 0 = -0.0 8000000000000000
-1.0 * 0 = 0.0 0000000000000000
-0.8 * 0 = -0.0 8000000000000000
-0.5 * 0 = -0.0 8000000000000000
我所能想到的就是将-0.0作为一个特例:
my $ans = (0.6*$m+ 0.7 * $e-1.5)*$g;
my $x= sprintf("%0.1f", $ans == -0.0 ? 0.0 : $ans)
(编辑:这是一个愚蠢的建议,因为-0.0==0.0
)
我还检查了Python的行为,它始终保留符号,这表明负号在Perl中并不是一个真正的bug,只是有点奇怪(尽管我认为以不同的方式对待整数和非整数是一个bug):
首先,这与Perl无关。是您的处理器返回-0.0。在其他语言中也会看到同样的行为
你会问为什么,大概会问为什么这是有用的。老实说,我不知道。一些科学家和工程师可能会利用它 +0.0表示“零或正极稍大的值” -0.0表示“0或负值稍大的值。”
你也会问如何摆脱这个标志
负零为假,因此
$x | | 0
起作用。此处无任何内容,请继续
零由指数emin-1和零有效位表示。
由于符号位可以具有两个不同的值,因此有两个
零、+0和-0
这并没有直接处理post,但它确实解决了perl中存在的“奇怪”行为
(我认为)这个问题是因为perl将数字转换为整数,然后使用INTEGER/ALU数学而不是FP/FPU数学。但是,没有-0整数[在二的补码中]——只有一个-0整数,它实际上是一个浮点值——因此浮点值-0.0在乘法之前被转换为整数0:-) 这是我的“示范”: 我的“结果/推理”是: 快乐的沉思
Python没有表现出这些怪癖,因为它有强类型的数字:在进行数学运算之前,它不会将整数浮点值转换为整数。(Python仍将执行标准类型加宽。)在perl中尝试除以0.0(FP,而不是整数数学!);-) 提供了一些有用的信息以及检查浮点值是否为零的例程 简而言之,在处理浮点时,不能假设代数恒等式将被保留
use strict;
use warnings;
use Data::Float qw(float_is_zero);
my $m = 0;
my $e = 0;
my $g = 0;
my $result = (0.6 * $m + 0.7 * $e - 1.5) * $g;
$result = 0.0 if float_is_zero($result);
my $x = sprintf( "%0.1f", $result);
print $x;
回答:使用绝对值函数,
abs()
代码
Perl 5.10.1
-0.000000
0.000000
Perl 5.12.1
-0.000000
0.000000
Perl 6(rakudo-2010.08)
IEEE 754标准
abs(x)将浮点操作数x复制到同一行中的目标
格式化,将符号位设置为0(正)
编辑(处理反馈):
my $result = possible_negative_zero();
$result = abs($result) if $result == 0.0; # because -0.0 == 0.0
printf "%f\n", $result;
我想减去-0.0不是你想要的[那是个笑话]我删除了标签(因为这不是问题的原因)并添加了.FWIW,我在使用各种perl
s的Windows上看不到这一点。还有,你找到一个可接受的解决方案了吗?是的,但问题是为什么有些计算产生-0.0,而另一些计算产生+0.0。你试过了吗?至少在我的系统上my$f=0.0;如果$f==-0.0,则打印“负零\n”
打印neg zero
。当期望的结果可能是负数时,这可能会导致问题。
printf "%f\n", -0.0;
printf "%f\n", abs(-0.0);
-0.000000
0.000000
-0.000000
0.000000
0.000000
0.000000
my $result = possible_negative_zero();
$result = abs($result) if $result == 0.0; # because -0.0 == 0.0
printf "%f\n", $result;