Inteiros assinados versus números não assinados

395

Estou correto em dizer que a diferença entre um número inteiro assinado e não assinado é:

  1. Não assinado pode conter um valor positivo maior e nenhum valor negativo.
  2. Não assinado usa o bit inicial como parte do valor, enquanto a versão assinada usa o bit mais à esquerda para identificar se o número é positivo ou negativo.
  3. números inteiros assinados podem conter números positivos e negativos.

Alguma outra diferença?

Shimmy Weitzhandler
fonte
6
Como 0 não é positivo nem negativo , é mais apropriado usar o termo valor não negativo em vez de valor positivo para números inteiros não assinados.
Daniel

Respostas:

344

Não assinado pode conter um valor positivo maior e nenhum valor negativo.

Sim.

Não assinado usa o bit inicial como parte do valor, enquanto a versão assinada usa o bit mais à esquerda para identificar se o número é positivo ou negativo.

Existem diferentes maneiras de representar números inteiros assinados. O mais fácil de visualizar é usar o bit mais à esquerda como uma bandeira ( sinal e magnitude ), mas o mais comum é o complemento de dois . Ambos estão em uso na maioria dos microprocessadores modernos - o ponto flutuante usa sinal e magnitude, enquanto a aritmética inteira usa o complemento de dois.

números inteiros assinados podem conter números positivos e negativos.

sim

Greg
fonte
Não sei se é exatamente esse texto, mas encontrei outro link. Vá para a 9ª página do PDF (na verdade, é a 38ª página do livro) e você pode ver a seção chamada Representação de Dados (Seção 1.3). Tem a explicação de todas as coisas ditas acima. Você
usar o seguinte
92

Vou entrar em diferenças no nível do hardware, no x86. Isso é irrelevante, a menos que você esteja escrevendo um compilador ou usando a linguagem assembly. Mas é bom saber.

Primeiro, o x86 tem suporte nativo para a representação complementar de dois dos números assinados. Você pode usar outras representações, mas isso exigiria mais instruções e geralmente seria um desperdício de tempo do processador.

O que quero dizer com "suporte nativo"? Basicamente, quero dizer que há um conjunto de instruções que você usa para números não assinados e outro que você usa para números assinados. Os números não assinados podem ficar nos mesmos registros que os números assinados e, de fato, você pode misturar instruções assinadas e não assinadas sem preocupar o processador. Cabe ao compilador (ou programador de montagem) acompanhar se um número é assinado ou não e usar as instruções apropriadas.

Em primeiro lugar, os números de complemento de dois têm a propriedade de que adição e subtração são iguais às de números não assinados. Não faz diferença se os números são positivos ou negativos. (Então você só ir em frente e ADDe SUBseus números sem uma preocupação.)

As diferenças começam a aparecer quando se trata de comparações. O x86 tem uma maneira simples de diferenciá-los: acima / abaixo indica uma comparação não assinada e maior / menor que indica uma comparação assinada. (Por exemplo, JAEsignifica "Salte se for acima ou igual" e não está assinado.)

Existem também dois conjuntos de instruções de multiplicação e divisão para lidar com números inteiros assinados e não assinados.

Por fim: se você deseja verificar, digamos, estourar, faria de maneira diferente para números assinados e não assinados.

Artelius
fonte
O que você quer dizer com números não assinados e assinados, o que eu quero perguntar é se eu escrevo unsigned int a = 2 e assinado int b = 2, para que ambos sejam assinados ou não assinados, um número sendo assinado ou não assinado depende do tipo nós atribuímos a, ou depende se tem sinal negativo ou não? Isso tem me incomodado por algum tempo.
Suraj Jain
@SurajJain assinado e não assinado referem-se a tipos. Eles indicam se é possível que uma variável ou expressão tenha um valor negativo.
Artelius
Eu tenho a seguinte dúvida, eu fiz a pergunta, nenhuma resposta satisfatória ainda, dê uma olhada aqui, stackoverflow.com/questions/41399092/…
Suraj Jain
62

Ele só perguntou sobre assinado e não assinado. Não sei por que as pessoas estão adicionando coisas extras nisso. Deixe-me dizer a resposta.

  1. Não assinado: Consiste apenas em valores não negativos, ou seja, de 0 a 255.

  2. Assinado: Consiste em valores negativos e positivos, mas em diferentes formatos, como

    • 0 a +127
    • -1 a -128

E essa explicação é sobre o sistema numérico de 8 bits.

Ashish Kumar
fonte
17

Apenas alguns pontos para completar:

  • esta resposta está discutindo apenas representações inteiras. Pode haver outras respostas para o ponto flutuante;

  • a representação de um número negativo pode variar. O mais comum (de longe - hoje é quase universal hoje) em uso hoje é o complemento de dois . Outras representações incluem o complemento (bastante raro) e a magnitude assinada (extremamente rara - provavelmente usada apenas em peças de museu), que está simplesmente usando o bit alto como um indicador de sinal, com os bits restantes representando o valor absoluto do número.

  • Ao usar o complemento de dois, a variável pode representar um intervalo maior (em um) de números negativos do que números positivos. Isso ocorre porque o zero é incluído nos números 'positivos' (já que o bit de sinal não está definido para zero), mas não os números negativos. Isso significa que o valor absoluto do menor número negativo não pode ser representado.

  • ao usar o complemento ou a magnitude assinada, você pode ter zero representado como um número positivo ou negativo (que é um dos dois motivos pelos quais essas representações geralmente não são usadas).

Michael Burr
fonte
Se eu escrever unsigned int a = -2 e assinado int b = -2, seria a representação subjacente igual, eu sei que não é bom ter um número não assinado com um valor negativo, mas ainda assim, se eu der, qual será o representação subjacente?
Suraj Jain
11
Pequenas imperfeições: sinal e magnitude são usados ​​no ponto flutuante do IEEE, portanto, é bastante comum. :-)
alastair
14

De acordo com o que aprendemos na aula, números inteiros assinados podem representar números positivos e negativos, enquanto números inteiros não assinados são apenas não negativos.

Por exemplo, olhando para um número de 8 bits :

valores não assinados0 para255

valores assinados variam de -128a127

Ying Xiong
fonte
11

Tudo, exceto o ponto 2, está correto. Existem muitas notações diferentes para entradas assinadas, algumas implementações usam a primeira, outras usam a última e outras ainda usam algo completamente diferente. Tudo depende da plataforma com a qual você está trabalhando.

Jasper Bekkers
fonte
Essa é a coisa do pequeno endian e do big endian?
VIceBerg 29/10/08
little vs. big endian tem a ver com a ordem dos bytes na plataforma. O little endian pode executar 0xFF 0xFE 0x7F enquanto o big endian fará 0x7F 0xFE 0xFF.
Jasper Bekkers 29/10/08
10

Outra diferença é quando você está convertendo entre números inteiros de tamanhos diferentes.

Por exemplo, se você estiver extraindo um número inteiro de um fluxo de bytes (digamos 16 bits por simplicidade), com valores não assinados, você poderá:

i = ((int) b[j]) << 8 | b[j+1]

(provavelmente deve lançar os 2 nd byte, mas eu estou supondo que o compilador vai fazer a coisa certa)

Com valores assinados, você teria que se preocupar com a extensão de sinal e fazer:

i = (((int) b[i]) & 0xFF) << 8 | ((int) b[i+1]) & 0xFF
Mike Gleen
fonte
5

De um modo geral, isso está correto. Sem saber mais nada sobre por que você está procurando as diferenças, não consigo pensar em nenhum outro diferencial entre assinado e não assinado.

toddk
fonte
4

Além do que outros disseram, em C, você não pode estourar um número inteiro não assinado; o comportamento é definido como aritmético de módulo. Você pode estourar um número inteiro assinado e, em teoria (embora não na prática nos sistemas atuais atuais), o estouro pode disparar uma falha (talvez semelhante a uma divisão por falha zero).

Jonathan Leffler
fonte
11
Observe que o excesso de número inteiro assinado desencadeia um comportamento indefinido, e os compiladores modernos são ultra-agressivos ao descobrir isso e explorá-lo para modificar seu programa de maneiras inesperadas, mas tecnicamente legítimas, porque eles podem assumir que um comportamento indefinido não ocorrerá - grosso modo. Isso é muito mais problemático agora do que há 7 anos.
Jonathan Leffler
4
  1. Sim, um número inteiro não assinado pode armazenar um valor grande.
  2. Não, existem diferentes maneiras de mostrar valores positivos e negativos.
  3. Sim, um número inteiro assinado pode conter valores positivos e negativos.
bhavesh
fonte
4

(em resposta à segunda pergunta) Usando apenas um bit de sinal (e não o complemento de 2), você pode acabar com -0. Não é muito bonito.

Ryan Rodemoyer
fonte
Só para acrescentar a esta resposta, basicamente, isso significa que 10 == 00, onde ambos os números são base 2.
4

Inteiros assinados em C representam números. Se ae bsão variáveis ​​de tipos inteiros assinados, o padrão nunca exigirá que um compilador transforme a expressão a+=bem aalgo que não seja a soma aritmética de seus respectivos valores. Para ter certeza, se a soma aritmética não couber a, o processador pode não ser capaz de colocá-la lá, mas o padrão não exige que o compilador trunque ou agrupe o valor, ou faça qualquer outra coisa se os valores excederem os limites para seus tipos. Observe que, embora o padrão não exija, as implementações de C podem capturar estouros aritméticos com valores assinados.

Inteiros não assinados em C se comportam como anéis algébricos abstratos de números inteiros, que são módulos congruentes com alguma potência de dois, exceto em cenários que envolvem conversões ou operações com tipos maiores. Convertendo um número inteiro de qualquer tamanho para um tipo não assinado de 32 bits produzirá o membro correspondente a coisas que são congruentes com esse número inteiro mod 4.294.967.296. A razão de subtrair 3 de 2 produz 4.294.967.295 é que adicionar algo congruente a 3 a algo congruente a 4.294.967.295 produzirá algo congruente a 2.

Os tipos abstratos de anéis algébricos costumam ser úteis; infelizmente, C usa a assinatura como o fator decisivo para se um tipo deve se comportar como um anel. Pior, os valores não assinados são tratados como números em vez de membros do anel quando convertidos para tipos maiores, e valores não assinados menores que intsão convertidos em números quando qualquer aritmética é executada sobre eles. Se vé uint32_tigual a 4,294,967,294, então v*=v;deve fazer v=4. Infelizmente, se inttiver 64 bits, não há como dizer o que v*=v;poderia fazer.

Dado o padrão atual, eu sugeriria o uso de tipos não assinados em situações em que se deseja o comportamento associado a anéis algébricos e tipos assinados quando se deseja representar números. É lamentável que C tenha feito as distinções do jeito que fez, mas elas são o que são.

supercat
fonte
3

Números inteiros não assinados são muito mais propensos a capturá-lo em uma armadilha específica do que os números inteiros assinados. A armadilha vem do fato de que, enquanto 1 e 3 acima estão corretas, os dois tipos de inteiros pode ser atribuído um valor fora dos limites do que pode "hold" e será silenciosamente convertido.

unsigned int ui = -1;
signed int si = -1;

if (ui < 0) {
    printf("unsigned < 0\n");
}
if (si < 0) {
    printf("signed < 0\n");
}
if (ui == si) {
    printf("%d == %d\n", ui, si);
    printf("%ud == %ud\n", ui, si);
}

Quando você executa isso, você obtém a seguinte saída, mesmo que os dois valores tenham sido atribuídos a -1 e declarados de maneira diferente.

signed < 0
-1 == -1
4294967295d == 4294967295d
Mateus
fonte
0

A única diferença garantida entre um valor assinado e um não assinado em C é que o valor assinado pode ser negativo, 0 ou positivo, enquanto um não assinado pode ser apenas 0 ou positivo. O problema é que C não define o formato dos tipos (para que você não saiba que seus números inteiros estão no complemento de dois). A rigor, os dois primeiros pontos mencionados estão incorretos.

Mais claro
fonte
0

Você deve usar números inteiros não assinados ao programar em sistemas embarcados. Nos loops, quando não há necessidade de números inteiros assinados, o uso de números inteiros não assinados economizará o necessário para projetar esses sistemas.

Fahad Naeem
fonte