perl 不一致的负零结果
我有以下代码:
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。
I have the following code :
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;
when I run the script the result is -0.0 and not 0.0 could someone explain why and how i can change it to be 0.0.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
首先,这与 Perl 无关。返回 -0.0 的是您的处理器。您会在其他语言中看到相同的行为。
你问为什么,大概是在问为什么这有用。老实说,我不知道。一些科学家和工程师可能会利用它。
+0.0 表示“零或正值稍大一些”。
-0.0 表示“零或负值稍大一些”。
您还询问如何摆脱该标志。
负零为假,所以
$x || 0
就可以了。First, this has nothing to do with Perl. It's your processor that's returning -0.0. You'll see this same behaviour in other languages.
You ask why, presumably asking why this is useful. Honestly, I don't know. Some scientists and engineers probably take advantage of it.
+0.0 would indicate "zero or something very slightly larger on the positive side".
-0.0 would indicate "zero or something very slightly larger on the negative side."
You also ask how to get rid of the sign.
Negative zero is false, so
$x || 0
does the trick.你遇到了一些非常奇怪的事情。我的第一个想法是,您看到了一些非常小的负数,
sprintf
四舍五入为 -0.0,但实际上表达式的结果是实际的负零。这是一个表现出相同问题的更简单的程序:
以及输出:
我最好的猜测是编辑:删除;用函数调用替换所有常量的程序的修改版本具有相同的行为。-1.0 * 0.0
是在编译时计算的,但是-1.5 * 0.0
code> 正在执行时计算,并且计算产生不同的结果。我可以通过在 printf 调用之前添加这些行来避免负零显示:
但这很丑陋。
(顺便说一句,大约一个月前,我使用 Perl 5.15.2 的“尖端”版本得到了相同的结果。)
类似的 C 程序为 x 和 y 打印
-0.000000
。编辑:进一步的实验表明,负整数值乘以 0.0 得到 0.0,但负非整数值乘以 0.0 得到 -0.0。我已经提交了 Perl 错误报告。
You've run into something very strange. My first thought was that you were seeing some very small negative number that
sprintf
rounds to -0.0, but in fact the result of the expression is an actual negative zero.Here's a simpler program that exhibits the same issue:
and the output:
My best guess is thatEDIT: Strike that; a modified version of the program that replaces all the constants with function calls has the same behavior.-1.0 * 0.0
is being computed at compile time, but-1.5 * 0.0
is being computed at execution time, and the computations are yielding different results.I can avoid the negative zero display by adding these lines before the
printf
calls:but that's ugly.
(Incidentally, I get the same results with the "bleading-edge" version of Perl 5.15.2 from about a month ago.)
A similar C program prints
-0.000000
for both x and y.EDIT: Further experiment shows that multiplying a negative integral value by 0.0 yields 0.0, but multiplying a negative non-integral value by 0.0 yields -0.0. I've submitted a Perl bug report.
这里没什么可看的,继续走吧……
http://download.oracle.com/docs/cd /E19957-01/806-3568/ncg_goldberg.html
Nothing to see here, move along...
http://download.oracle.com/docs/cd/E19957-01/806-3568/ncg_goldberg.html
Data::Float 有一些有用的信息以及检查浮点值是否为例程为零。
简而言之,在处理浮点时,您不能假设代数恒等式将被保留。
Data::Float has some useful information as well as routines to check if a floating point value is zero.
The short answer is, when dealing with floating point, you cannot assume algebraic identities will be preserved.
这并没有直接解决这篇文章,但它确实解决了 perl 中存在的“奇怪”行为。
(我相信)导致此问题的原因是 Perl 将数字转换为整数,然后使用 INTEGER/ALU 数学而不是 FP/FPU 数学。然而,没有 -0 整数[以二进制补码表示]——只有一个 -0 整数,它实际上是一个浮点值——所以浮点值 -0.0 被转换为整数 0 < em>在乘法之前:-)
这是我的“演示”:
我的“结果/推理”是:
快乐的沉思。
Python 不会表现出这些怪癖,因为它具有强类型数字:它不会在数学运算之前将整型浮点值转换为整数。 (Python 仍将执行标准类型加宽。)尝试在 perl 中除以 0.0(FP,而不是 INTEGER 数学!);-)
This doesn't address the post directly, but it does address the "odd" behavior that exists in perl.
(I believe) This issue is caused because perl is converting the numbers to integers and then using INTEGER/ALU math instead of FP/FPU math. However, there is no -0 integer [in two's complement] -- only an -0 integral which is really a floating point value -- so the floating point value -0.0 is converted to the integer 0 before the multiplication :-)
Here is my "demonstration":
And my "result/reasoning" is:
Happy musings.
Python does not exhibit these quirks because it has strongly-typed numbers: it will not convert an integral floating point value to an integer prior to a math operation. (Python will still perform standard type-widening.) Try divide by 0.0 (FP, not INTEGER math!) in perl ;-)
很奇怪。我注意到,如果将
1.5
替换为负整数,问题就会消失:我能想到的就是将 -0.0 视为特殊情况:(
编辑:这是一个愚蠢的建议,因为
-0.0 == 0.0
。)我还检查了 Python 的行为,它始终保留符号,这表明负号实际上并不是 Perl 中的错误,只是有点奇怪(尽管我会这么说以不同方式对待整数和非整数是一个错误):
Very strange. I note that the problem disappears if you replace
1.5
with a negative integer:All I can think of is to treat -0.0 as a special case:
(EDIT: This was a dumb suggestion, since
-0.0 == 0.0
.)I also checked Python's behaviour, which consistently retains the sign, which suggests that the negative sign is not really a bug in Perl, just a little strange (though I'd say that treating integers and non-integers differently is a bug):
答案:使用绝对值函数,
abs()
Code
Perl 5.10.1
Perl 5.12.1
Perl 6 (rakudo-2010.08)
IEEE 754 标准
编辑(解决Justin的反馈):
Answer: use the absolute value function,
abs()
Code
Perl 5.10.1
Perl 5.12.1
Perl 6 (rakudo-2010.08)
IEEE 754 standard
EDIT (addressing Justin's feedback):