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

时间:2016-03-31 16:49:18

标签: matlab floating-point rounding

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

代码示例:

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

结果:

  

a:-0.00。四舍五入:-0.00。零:0.00

预期结果:

  

a:-0.00。圆形:0.00。零:0.00

2 个答案:

答案 0 :(得分:3)

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

  

根据section 6.3ANSI/IEEE Std. 754-1985,MATLAB表示符号位"即使操作数或结果为零或无限。"

因此,当使用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

答案 1 :(得分:2)

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

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

  

主要文章:签名零

     

在IEEE 754标准中,零已签名,这意味着存在   “正零”(+0)和“负零”(-0)。多数情况   运行时环境,正零通常打印为“0”和   负零为“-0”。这两个值在数值上表现相同   比较,但有些操作会为+0和+返回不同的结果   -0。例如,1 /( - 0)返回负无穷大,而1 / + 0返回   正无穷大(保持1 /(1 /±∞)=±∞的同一性)。   其他在x = 0处具有不连续性的常见函数可能会对待   对于任何负数y,+ 0和-0不同地包括log(x),signum(x)和y + xi的主平方根。和任何一样   近似方案,涉及“负零”的操作可以   偶尔会造成混乱。例如,在IEEE 754中,x = y不是   总是暗示1 / x = 1 / y,因为0 = -0但是1/0≠1 / -0。

来源:Wikipedia Floating_point Signed_zero

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

如果让Matlab选择最佳的显示方式,Matlab将会很聪明并放弃零:

>> disp(ar)
     0

此外,Matlab知道值为0,如果您查询值的符号,则会返回正确的值:

>> sign(ar)
ans =
     0

Matlab将返回-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

在此处,舍入操作被评估两次,因为我在内联函数中使用了它,但如果将其放在具有多行的函数中,则只评估舍入一次,然后使用相同的方法更正符号。