Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/perl/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
perl不一致负零结果_Perl_Floating Point - Fatal编程技术网

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;