小负数四舍五入后保持符号

Small negative number maintains sign after rounding

即使四舍五入的结果为零,MATLAB 似乎也能记住原始符号。该信号不再有意义,因为小的负值四舍五入为零。

代码示例:

a = - 0.001;
ar = round(a,2);
fprintf('a: %.2f. a rounded: %.2f. Zero: %.2f\n', a,ar,0);

结果:

a: -0.00. a rounded: -0.00. Zero: 0.00

预期结果:

a: -0.00. a rounded: 0.00. Zero: 0.00

根据the post by Bob Gilmore (from The MathWorks) on the MATLAB forums,MATLAB 在执行由ANSI/IEEE 浮点标准指定的各种运算时尊重符号位。

As per section 6.3 of ANSI/IEEE Std. 754-1985, MATLAB honors the sign bit "even when operands or results are zero or infinite."

因此,当使用 round 时,即使所有指数和小数位都设置为 0,sign bit 仍然与输入相同(在您的情况下,这是 1表示负数)。 fprintf 在显示您的值时遵守此符号位,因此添加明确的负号。

您也可以通过显式指定您想要 -0:

来获得相同的行为
fprintf('%0.2f\n', -0);
%// -0.00

这也可以用其他东西观察到,例如除以 0:

1/0   %// Inf

1/-0  %// -Inf

我们也可以通过将显示格式更改为 hex:

来观察这一点
format hex

disp(0)

    0000000000000000

disp(-0)

    8000000000000000

注意第一个条目中的不同表示符号位的不同。

As @zeeMonkeez noted in the comments,一个简单的解决方法是将 0 添加到您的结果中,在 -0 的情况下,似乎翻转了符号位:

fprintf('%0.2f\n', -0 + 0);
%// 0.00

这根本不是 Matlab 特有的。事实上,所有使用 IEEE754 进行浮点表示的程序都可能具有这种特殊性。

在 IEEE-754 格式中,有一个符号位。在舍入操作期间,该位可能保持不变。所以即使最后结果是纯 0 ,符号位仍然存在。对于这种格式的浮点数,这是完全正常的行为:

Main article: Signed zero

In the IEEE 754 standard, zero is signed, meaning that there exist both a "positive zero" (+0) and a "negative zero" (−0). In most run-time environments, positive zero is usually printed as "0" and the negative zero as "-0". The two values behave as equal in numerical comparisons, but some operations return different results for +0 and −0. For instance, 1/(−0) returns negative infinity, while 1/+0 returns positive infinity (so that the identity 1/(1/±∞) = ±∞ is maintained). Other common functions with a discontinuity at x=0 which might treat +0 and −0 differently include log(x), signum(x), and the principal square root of y + xi for any negative number y. As with any approximation scheme, operations involving "negative zero" can occasionally cause confusion. For example, in IEEE 754, x = y does not always imply 1/x = 1/y, as 0 = −0 but 1/0 ≠ 1/−0.

来源:Wikipedia Floating_point Signed_zero


现在 Matlab 在零前面显示一个符号,因为你要求以浮点格式显示它 (%.2f),所以 Matlab 尊重规范并显示符号。

如果你让 Matlab 选择最好的显示方式,Matlab 会很聪明地去掉零:

>> disp(ar)
     0

此外,Matlab 知道该值为 0,如果您查询该值的符号,它将 return 为正确的值:

>> sign(ar)
ans =
     0

Matlab 会 return -1 如果它被认为是消极的,+1 如果它被认为是积极的。 所以尽管尊重显示时IEEE-754规范,Matlab不混淆,知道这个值没有有意义的符号。

总之,不用担心。它不会带来任何编程问题或计算问题。

如果您唯一的烦恼是显示,另一种解决方法可能是将绝对值乘以 Matlab 检测到的 sign(因为它检测到正确的符号)。 您可以制作一个自定义舍入函数,如果真的很重要,它可以解决这个问题:

mround = @(x,n) abs(round(x,n))*sign(round(x,n)) ;
arm = mround(a,2) ;
fprintf('a: %.2f. a rounded: %.2f. Zero: %.2f\n', a,arm,0);

a: -0.00. a rounded: 0.00. Zero: 0.00

这里允许舍入运算被计算两次,因为我在内联函数中使用了它,但是如果你把它放在一个有多行的函数中,你只计算一次舍入然后用相同的方法更正符号。