是否有可能区分0和-0?

Fil*_*inx 92 c++ int zero negative-number

我知道整数值0-0基本相同.但是,我想知道是否有可能区分它们.

例如,我如何知道是否分配了变量-0

bool IsNegative(int num)
{
    // How ?
}

int num = -0;
int additinon = 5;

num += (IsNegative(num)) ? -addition : addition;
Run Code Online (Sandbox Code Playgroud)

-0保存在内存中的值与完全相同0吗?

Mar*_* A. 111

这取决于您要定位的机器.

在一个使用一台机器2的补码表示的整数有在位级无差异之间0-0(他们有相同的表示)

如果你的机器使用了一个补充,你绝对可以

0000 0000   -> signed?  0?
1111 1111   -> signed   ?0
Run Code Online (Sandbox Code Playgroud)

显然我们正在谈论使用原生支持,x86系列处理器本身支持签名数字的二进制补码表示.使用其他表示肯定是可能的,但可能效率较低,需要更多指令.

(正如JerryCoffin所指出的那样:即使一个人的补充主要是出于历史原因而被考虑,签名的量级表示仍然相当普遍,并且确实有一个单独的表示负数和正数零)

  • @Hurkly:不,即使存在负零表示,标准也不保证使用表达式`-0`进行赋值或初始化,也就是说将一元`-`运算符应用于整数常量的结果` 0`,是负零表示.无论表示如何,标准从不说"0"和"-0"在数学上是不同的值,只是可能存在负零位模式.如果有,它仍然代表相同的数值,0. (8认同)
  • @TobiMcNamobi:不太可能永远不会担心.如果有人一直想要移植C++编译器来为这样的机器生成输出,我会感到惊讶. (6认同)
  • @TobiMcNamobi的补充仍然在UNISYS 2200系统中使用http://stackoverflow.com/a/12277974/995714 http://stackoverflow.com/q/6971886/995714 (4认同)
  • 我从来没有看过一个补码要求 - 标准实际上是否保证`0`和`-0`*不同*?老实说,我希望它的行为更像是允许相同值的两位表示,并且您的程序可以使用它感觉到的任何一种. (2认同)

Ric*_*dle 14

对于int(在几乎通用的"2的补码"表示中)的表示0-0相同.(对于其他数字表示,它们可以不同,例如IEEE 754浮点数.)

  • >>假设2的补码表示 (9认同)

Mar*_*oun 12

让我们从2的补码中表示0开始(当然存在许多其他系统和表示,这里我指的是这个特定的),假设8位,零是:

0000 0000
Run Code Online (Sandbox Code Playgroud)

现在让我们翻转所有位并加1以获得2的补码:

1111 1111 (flip)
0000 0001 (add one)
---------
0000 0000
Run Code Online (Sandbox Code Playgroud)

我们得到了0000 0000,这也是-0的代表.

但请注意,在1的补码中,带符号0为0000 0000,但-0为1111 1111.

  • 我可以知道为什么为了改进我的答案而投反对票吗? (2认同)

Ran*_*832 9

我决定放弃这个答案,因为C和C++实现通常是密切相关的,但事实上它并不像我想的那样遵循C标准.关键在于C++标准没有规定像这样的情况会发生什么.同样重要的是,非二重补充表示在现实世界中极为罕见,即使它们确实存在,它们通常在许多情况下隐藏差异,而不是将其暴露为某人可能容易期望发现的东西.


在它们存在的整数表示中,负零的行为在C++标准中并不像在C标准中那样严格定义.然而,它确实引用了C标准(ISO/IEC 9899:1999)作为顶级[1.2]的规范性参考.

在C标准[6.2.6.2]中,负零只能是按位运算的结果,或者已经存在负零的运算(例如,将负零乘以或除以负值,或者将负零加到零) - 将一元减运算符应用于正常零的值,如在您的示例中,因此保证导致正常零.

即使在可以产生负零的情况下,无法保证它们即使在支持负零的系统上也是如此:

未指定这些情况是否实际产生负零或正常零,以及当存储在对象中时负零是否变为正常零.

因此,我们可以得出结论:不,没有可靠的方法来检测这种情况.即使不是因为非二进制补码表示在现代计算机系统中非常罕见.

就其本身而言,C++标准没有提及"负零"这一术语,除了注意到[3.9.1第7段]允许它们之外,很少讨论有符号量和一个补码表示的细节.


Ben*_*igt 8

如果你的机器有不同的表述-0+0,然后memcmp就可以区分它们.

如果存在填充位,则实际上可能存在多个除零以外的值的表示.


Pau*_*per 5

在C++语言规范中,没有像负零那样的int .

这两个词有唯一意义是单目运算符-应用到0,就像三加5只是二进制运算符+适用于35.

如果存在明显的负零,则两个补码(整数类型的最常见表示)将是C++实现的不充分表示,因为无法表示两种形式的零.


相反,浮点(遵循IEEE)具有单独的正负零.例如,当将它们除以1时,可以区分它们.正零产生正无穷大; 负零产生负无穷大.


但是,如果碰巧有int 0(或任何int或任何其他类型的任何其他值)的不同内存表示,您可以memcmp用来发现:

#include <string>

int main() {
    int a = ...
    int b = ...
    if (memcmp(&a, &b, sizeof(int))) {
        // a and b have different representations in memory
    }
}
Run Code Online (Sandbox Code Playgroud)

当然,如果确实发生了这种情况,在直接内存操作之外,这两个值仍将以完全相同的方式工作.

  • 实际上,不强制存在的语言并不意味着它要求它的缺席.提示:它既不强制要求. (3认同)
  • @Deduplicator,有点儿."在C++语言中",我的意思是"用C++语言*规范*".由于规范中没有提到froobinators,我可以说"C++没有froobinators"而没有太多歧义.我认为这很清楚,但我会改进它. (2认同)