É possível diferenciar entre 0 e -0?

94

Eu sei que os valores inteiros 0e -0são essencialmente os mesmos. Mas, estou me perguntando se é possível diferenciá-los.

Por exemplo, como posso saber se uma variável foi atribuída -0?

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

int num = -0;
int additinon = 5;

num += (IsNegative(num)) ? -addition : addition;

O valor -0salvo na memória é exatamente da mesma forma que 0?

Filip Minx
fonte
9
Para inteiros, não há diferença.
Maroun
14
Isso depende da implementação, mas para implementações onde inté representado no complemento de 2 (de longe o mais comumente encontrado) 0e -0têm representações bit a bit idênticas.
Mankarse
11
Em uma máquina de complemento de 2, não há diferença no nível de bits.
Marco A.
17
@VirtualSnake: O que significa "em binário"? Há, de fato, codificações binárias para as quais não é uma distinção entre -0 e 0. Sinal e magnitude, por exemplo.
Benjamin Lindley
8
@VirtualSnake É isso mesmo, estamos falando int. Veja a codificação complementar de Um .
CiaPan

Respostas:

112

Depende da máquina que você está almejando.

Em uma máquina que usa uma representação de complemento de 2 para inteiros, não há diferença no nível de bits entre 0e -0(eles têm a mesma representação)

Se sua máquina usasse um complemento , você definitivamente poderia

0000 0000   -> signed0
1111 1111   -> signed   0

Obviamente, estamos falando sobre o uso de suporte nativo , os processadores da série x86 têm suporte nativo para a representação de complemento de dois números com sinal. Usar outras representações é definitivamente possível, mas provavelmente seria menos eficiente e exigiria mais instruções.

(Como JerryCoffin também observou: mesmo que o complemento de alguém tenha sido considerado principalmente por razões históricas, as representações de magnitude assinada ainda são bastante comuns e têm uma representação separada para zero negativo e positivo)

Marco A.
fonte
6
@TobiMcNamobi: Provavelmente não o suficiente para se preocupar. Eu ficaria surpreso se alguém já se preocupou em portar um compilador C ++ para produzir saída para tal máquina.
Benjamin Lindley
1
Concordo com Benjamin, historicamente houve máquinas que o utilizaram, mas hoje em dia não conheço máquinas de produção que o utilizem. No entanto, é sempre bom saber e ter em mente.
Marco A.
4
@TobiMcNamobi um complemento ainda está em uso no sistema UNISYS 2200 stackoverflow.com/a/12277974/995714 stackoverflow.com/q/6971886/995714
phuclv
2
Nunca olhei para os requisitos de complemento de um - o padrão realmente garante isso 0e -0são diferentes ? Sinceramente, esperava que ele se comportasse mais como permitindo representações de dois bits do mesmo valor, e seu programa pode usar o que quiser.
8
@Hurkly: não, mesmo que exista uma representação zero negativa, o padrão não garante que a atribuição ou inicialização usando a expressão -0, ou seja, o resultado da aplicação do -operador unário à constante inteira 0, seja uma representação zero negativa. Independentemente da representação, o padrão nunca diz 0e -0são valores matematicamente diferentes, apenas que pode haver um padrão de bit negativo-zero. Se houver, ainda representa o mesmo valor numérico, 0.
Steve Jessop
14

Para uma int(na representação quase universal de "complemento de 2") as representações de 0e -0são iguais. (Eles podem ser diferentes para outras representações de número, por exemplo. IEEE 754 ponto flutuante.)

RichieHindle
fonte
9
>> Assumindo uma representação de complemento de 2
Marco A.
12

Vamos começar representando 0 no complemento de 2 (claro que existem muitos outros sistemas e representações, aqui estou me referindo a este específico), assumindo 8 bits, zero é:

0000 0000

Agora vamos inverter todos os bits e adicionar 1 para obter o complemento de 2:

1111 1111 (flip)
0000 0001 (add one)
---------
0000 0000

temos 0000 0000, e essa é a representação de -0 também.

Mas note que no complemento de 1, 0 com sinal é 0000 0000, mas -0 é 1111 1111.

Maroun
fonte
1
Posso saber porque os votos negativos para melhorar a minha resposta, por favor?
Maroun
1
Embora a maioria das outras respostas seja tecnicamente correta, sua resposta é prática e fornece uma implementação. Boa.
umlcat
9

Decidi deixar essa resposta aberta, pois as implementações de C e C ++ costumam estar intimamente relacionadas, mas na verdade ela não segue o padrão C como pensei. A questão é que o padrão C ++ não especifica o que acontece em casos como esses. Também é relevante que representações que não sejam de complemento de dois sejam extremamente raras no mundo real e que, mesmo onde existem, muitas vezes escondem a diferença em muitos casos, em vez de expô-la como algo que alguém poderia facilmente esperar descobrir.


O comportamento dos zeros negativos nas representações de inteiros em que existem não é definido com tanto rigor no padrão C ++ como no padrão C. No entanto, ele cita o padrão C (ISO / IEC 9899: 1999) como uma referência normativa no nível superior [1.2].

No padrão C [6.2.6.2], um zero negativo só pode ser o resultado de operações bit a bit, ou operações onde um zero negativo já está presente (por exemplo, multiplicar ou dividir zero negativo por um valor, ou adicionar um zero negativo a zero) - a aplicação do operador menos unário a um valor de zero normal, como em seu exemplo, garante, portanto, um zero normal.

Mesmo nos casos que podem gerar um zero negativo, não há garantia de que o farão, mesmo em um sistema que suporta zero negativo:

Não é especificado se esses casos realmente geram um zero negativo ou um zero normal e se um zero negativo se torna um zero normal quando armazenado em um objeto.

Portanto, podemos concluir: não, não existe uma maneira confiável de detectar este caso. Mesmo que não seja pelo fato de que representações que não sejam de complemento de dois são muito incomuns em sistemas de computador modernos.

O padrão C ++, por sua vez, não faz menção ao termo "zero negativo", e tem muito pouca discussão sobre os detalhes de magnitude sinalizada e representações de complemento de alguém, exceto para observar [3.9.1 para 7] que eles são permitidos.

Random832
fonte
Em geral, não, o fato de algo ser verdadeiro / obrigatório em C não significa necessariamente que seja verdadeiro / obrigatório em C ++. O fato de C ser uma referência normativa significa que C ++ se refere ao padrão C para várias coisas (principalmente o conteúdo dos cabeçalhos padrão), mas a definição de tipos inteiros não é uma dessas coisas. No entanto, a ausência de uma maneira garantida de produzir um zero negativo significa que o que você concluiu ainda é verdade, não há uma maneira segura de gerar um usando aritmética, mesmo se a representação existir.
Steve Jessop
Então, por que o padrão C ++ dá muito menos detalhes sobre coisas como essa?
Random832
1
Gosto pessoal, eu acho, se o número de pessoas votando no padrão C ++ pode ser considerado "pessoal" :-) Se fosse adiar para o padrão C para as definições, entretanto, então ele poderia fazer um bom trabalho e não contém detalhes, como em alguns outros casos.
Steve Jessop
O "C ++ é uma linguagem de programação de propósito geral baseada na linguagem de programação C, conforme descrito em ISO / IEC 9899: 1999 Programming languages ​​- C (doravante referido como o padrão C)." [1.1 parágrafo 2] tem algum significado normativo? Achei que a intenção era geralmente incorporar o padrão C para qualquer coisa que não fosse especificamente substituída pelo padrão C ++.
Random832
@ Random832 Não. É apenas uma nota histórica (há, por exemplo, nenhum _Boolou _Complexou inicializadores designados ou literais compostos em C ++). O padrão C ++ sabe como incorporar o padrão C quando quiser - por exemplo, [basic.fundamental] / p3: "Os tipos inteiros com e sem sinal devem satisfazer as restrições fornecidas no padrão C, seção 5.2.4.2.1."
TC
8

Se a sua máquina tiver representações distintas para -0e +0, memcmpserá capaz de distingui-los.

Se bits de preenchimento estiverem presentes, pode haver várias representações para valores diferentes de zero também.

Ben Voigt
fonte
5

Na especificação da linguagem C ++, não existe um int como zero negativo .

O único significado que essas duas palavras têm é o operador unário -aplicado a 0, assim como três mais cinco é apenas o operador binário +aplicado a 3e 5.

Se houvesse um zero negativo distinto , o complemento de dois (a representação mais comum de tipos inteiros) seria uma representação insuficiente para implementações em C ++, pois não há como representar duas formas de zero.


Em contraste, os pontos flutuantes (seguindo o IEEE) têm zeros positivos e negativos separados. Eles podem ser distinguidos, por exemplo, ao dividir 1 por eles. O zero positivo produz infinito positivo; zero negativo produz infinito negativo.


No entanto, se houver diferentes representações de memória do int 0 (ou de qualquer int ou de qualquer outro valor de qualquer outro tipo), você pode usar memcmppara descobrir que:

#include <string>

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

Claro, se isso acontecesse, fora das operações diretas de memória, os dois valores ainda funcionariam exatamente da mesma maneira.

Paul Draper
fonte
3
Na verdade, a linguagem que não exige sua existência não significa que exige sua ausência. Dica: não exige nenhum.
Deduplicator
2
@Deduplicator, mais ou menos. Por "na linguagem C ++", quero dizer "na especificação da linguagem C ++ ". Como também não há menção a froobinators na especificação, eu poderia dizer "C ++ não tem froobinators" sem muita ambigüidade. Achei que estava claro, mas vou melhorar.
Paul Draper
1
A especificação do idioma também não menciona unicórnios.
ypercubeᵀᴹ
2

Para simplificar, achei mais fácil visualizar.

O tipo int (_32) é armazenado com 32 bits . 32 bits significa 2 ^ 32 = 4294967296 valores exclusivos . Portanto :

intervalo de dados int sem sinal é de 0 a 4.294.967.295

No caso de valores negativos, depende de como eles são armazenados. Em caso

No caso do complemento de Um, o valor -0 existe.

Margus
fonte
2
Eu não votei contra, mas as plataformas para as quais intnão é armazenado em 32 bits são mais populares do que plataformas com um complemento hoje em dia.
Maciej Piechotka