Numeri interi firmati e non firmati


395

Ho ragione a dire che la differenza tra un intero con segno e senza segno è:

  1. Unsigned può contenere un valore positivo più grande e nessun valore negativo.
  2. Unsigned utilizza il bit iniziale come parte del valore, mentre la versione firmata utilizza il bit più a sinistra per identificare se il numero è positivo o negativo.
  3. numeri interi con segno possono contenere sia numeri positivi che negativi.

Altre differenze?


6
Poiché 0 non è né positivo né negativo , è più appropriato utilizzare il termine valore non negativo anziché valore positivo per numeri interi senza segno.
Daniel,

Risposte:


344

Unsigned può contenere un valore positivo più grande e nessun valore negativo.

Sì.

Unsigned utilizza il bit iniziale come parte del valore, mentre la versione firmata utilizza il bit più a sinistra per identificare se il numero è positivo o negativo.

Esistono diversi modi di rappresentare numeri interi con segno. Il più facile da visualizzare è usare il bit più a sinistra come bandiera ( segno e magnitudine ), ma più comune è il complemento a due . Entrambi sono in uso nella maggior parte dei moderni microprocessori: la virgola mobile utilizza segno e magnitudine, mentre l'aritmetica intera utilizza il complemento a due.

numeri interi con segno possono contenere sia numeri positivi che negativi.


Non sono sicuro se questo è esattamente quel testo, ma ho trovato un altro link. Vai alla nona pagina del PDF (in realtà è la 38a pagina del libro) e puoi vedere la sezione chiamata Rappresentazione dei dati (Sezione 1.3). Ha la spiegazione di tutte le cose sopra dette. lms.uop.edu.jo/lms/pluginfile.php/2420/mod_resource/content/1/…
WeirdElfB0y

92

Andrò in differenze a livello hardware, su x86. Ciò è in gran parte irrilevante a meno che non si stia scrivendo un compilatore o utilizzando il linguaggio assembly. Ma è bello saperlo.

In primo luogo, x86 ha il supporto nativo per la rappresentazione a complemento dei due numeri firmati. È possibile utilizzare altre rappresentazioni ma ciò richiederebbe più istruzioni e in genere sarebbe una perdita di tempo per il processore.

Cosa intendo per "supporto nativo"? Fondamentalmente intendo che ci sono un set di istruzioni che usi per i numeri senza segno e un altro set che usi per i numeri con segno. I numeri non firmati possono trovarsi negli stessi registri dei numeri firmati e in effetti è possibile mescolare istruzioni firmate e non firmate senza preoccupare il processore. Spetta al compilatore (o programmatore di assembly) tenere traccia del fatto che un numero sia firmato o meno e utilizzare le istruzioni appropriate.

In primo luogo, i numeri di complemento a due hanno la proprietà che l'addizione e la sottrazione sono le stesse dei numeri senza segno. Non fa alcuna differenza se i numeri sono positivi o negativi. (Quindi vai avanti ADDe con i SUBtuoi numeri senza preoccupazioni.)

Le differenze iniziano a mostrare quando si tratta di confronti. x86 ha un modo semplice di differenziarli: sopra / sotto indica un confronto senza segno e maggiore / minore di indica un confronto con segno. (Ad esempio JAEsignifica "Salta se superiore o uguale" ed è senza segno.)

Esistono anche due serie di istruzioni di moltiplicazione e divisione per gestire numeri interi con o senza segno.

Infine: se si desidera verificare, per esempio, l'overflow, lo si farebbe diversamente per i numeri firmati e quelli non firmati.


Cosa intendi con numeri non firmati e firmati, quello che voglio chiedere è se scrivo unsigned int a = 2 e firmato int b = 2, quindi sono entrambi firmati o non firmati, un numero che viene firmato o non firmato dipende dal tipo lo assegniamo o dipende dal fatto che abbia o meno un segno negativo? Questo mi ha infastidito per un po '.
Suraj Jain,

@SurajJain firmati e non firmati si riferiscono ai tipi. Indicano se è possibile che una variabile o un'espressione abbia un valore negativo.
Artelius

Ho il seguente dubbio, ho posto la domanda, non ho ancora una risposta soddisfacente, dai un'occhiata qui, stackoverflow.com/questions/41399092/…
Suraj Jain,

62

Ha solo chiesto di firmato e non firmato. Non so perché le persone aggiungano cose extra in questo. Lascia che ti dica la risposta.

  1. Unsigned: consiste solo di valori non negativi, cioè da 0 a 255.

  2. Firmato: consiste in valori sia negativi che positivi ma in diversi formati come

    • Da 0 a +127
    • Da -1 a -128

E questa spiegazione riguarda il sistema numerico a 8 bit.


17

Solo alcuni punti per completezza:

  • questa risposta sta discutendo solo rappresentazioni intere. Potrebbero esserci altre risposte per il virgola mobile;

  • la rappresentazione di un numero negativo può variare. Il più comune (di gran lunga - oggi è quasi universale) in uso oggi è il complemento a due . Altre rappresentazioni includono il proprio complemento (piuttosto raro) e la grandezza firmata (raramente rara - probabilmente usata solo su pezzi da museo) che sta semplicemente usando il bit alto come indicatore di segno con i bit rimanenti che rappresentano il valore assoluto del numero.

  • Quando si usa il complemento a due, la variabile può rappresentare un intervallo più ampio (di uno) di numeri negativi rispetto ai numeri positivi. Questo perché zero è incluso nei numeri 'positivi' (poiché il bit del segno non è impostato per zero), ma non i numeri negativi. Ciò significa che non è possibile rappresentare il valore assoluto del numero negativo più piccolo.

  • quando usi il complemento o la grandezza firmata puoi avere zero rappresentato come un numero positivo o negativo (che è uno dei due motivi per cui queste rappresentazioni non sono in genere utilizzate).


Se scrivo unsigned int a = -2, e firmato int b = -2, la stessa rappresentazione sottostante sarebbe la stessa, so che non è bene avere un numero unsigned dato un valore negativo, ma comunque se lo do, quale sarà il rappresentazione sottostante?
Suraj Jain,

1
Niggle minore: segno e magnitudo sono usati in virgola mobile IEEE, quindi in realtà è abbastanza comune. :-)
alastair,

14

Secondo quanto appreso in classe, gli interi con segno possono rappresentare sia numeri positivi che negativi, mentre gli interi senza segno sono solo non negativi.

Ad esempio, guardando un numero a 8 bit :

valori non firmati0 a255

i valori firmati vanno da -128a127


11

Tutto tranne il punto 2 è corretto. Esistono molte notazioni diverse per gli integ firmati, alcune implementazioni usano la prima, altre usano l'ultima e altre ancora usano qualcosa di completamente diverso. Tutto dipende dalla piattaforma con cui stai lavorando.


È questa la cosa del piccolo endian e del big endian?
vIceBerg,

little vs. big endian ha a che fare con l'ordine dei byte sulla piattaforma. Il piccolo endian potrebbe fare 0xFF 0xFE 0x7F mentre il big endian farà 0x7F 0xFE 0xFF.
Jasper Bekkers,

10

Un'altra differenza è quando si esegue la conversione tra numeri interi di dimensioni diverse.

Ad esempio, se stai estraendo un numero intero da un flusso di byte (diciamo 16 bit per semplicità), con valori senza segno, potresti fare:

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

(probabilmente dovrebbe lanciare il 2 ° di byte, ma sto cercando di indovinare il compilatore farà la cosa giusta)

Con i valori firmati dovresti preoccuparti dell'estensione dei segni e fare:

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

5

In generale è corretto. Senza sapere altro sul perché stai cercando le differenze, non riesco a pensare a nessun altro elemento di differenziazione tra firmato e non firmato.


4

Oltre a ciò che altri hanno detto, in C, non è possibile traboccare un numero intero senza segno; il comportamento è definito come modulo aritmetico. È possibile overflow di un numero intero con segno e, in teoria (sebbene non in pratica sugli attuali sistemi tradizionali), l'overflow potrebbe innescare un errore (forse simile a una divisione per errore zero).


1
Si noti che l'overflow di numeri interi con segno provoca comportamenti indefiniti e i compilatori moderni sono ultra-aggressivi nell'individuare questo e sfruttarlo per modificare il programma in modi inaspettati ma tecnicamente legittimi perché possono assumere un comportamento indefinito, in termini approssimativi. Questo è un problema molto più di quanto non fosse 7 anni fa.
Jonathan Leffler,

4
  1. Sì, numeri interi senza segno possono memorizzare valori di grandi dimensioni.
  2. No, ci sono diversi modi per mostrare valori positivi e negativi.
  3. Sì, l'intero con segno può contenere sia valori positivi che negativi.

4

(in risposta alla seconda domanda) Usando solo un bit di segno (e non il complemento di 2), puoi finire con -0. Non molto carina


Solo per aggiungere a questa risposta, in pratica significa che 10 == 00 dove entrambi quei numeri sono base 2.

4

Gli interi con segno in C rappresentano i numeri. Se ae bsono variabili di tipi interi con segno, lo standard non richiederà mai che un compilatore a+=bmemorizzi l'espressione in aqualcosa di diverso dalla somma aritmetica dei rispettivi valori. A dire il vero, se la somma aritmetica non rientrasse a, il processore potrebbe non essere in grado di inserirlo lì, ma lo standard non richiederebbe al compilatore di troncare o racchiudere il valore, o fare qualsiasi altra cosa se i valori che superano i limiti per i loro tipi. Si noti che sebbene lo standard non lo richieda, le implementazioni C possono intercettare overflow aritmetici con valori con segno.

I numeri interi senza segno in C si comportano come anelli algebrici astratti di numeri interi che sono congruenti con una potenza di due, tranne in scenari che comportano conversioni o operazioni con tipi più grandi. La conversione di un numero intero di qualsiasi dimensione in un tipo senza segno a 32 bit produrrà il membro corrispondente a cose che sono congruenti a quel numero intero 4.294.967.296. Il motivo della sottrazione di 3 da 2 produce 4.294.967.295 è che l'aggiunta di qualcosa di congruo a 3 a qualcosa di congruo a 4.294.967.295 produrrà qualcosa di congruente a 2.

I tipi di anelli algebrici astratti sono spesso cose utili da avere; sfortunatamente, C usa la firma come fattore decisivo per decidere se un tipo dovrebbe comportarsi come un anello. I valori peggiori e senza segno vengono trattati come numeri anziché come membri dell'anello quando convertiti in tipi più grandi e i valori senza segno più piccoli che intvengono convertiti in numeri quando viene eseguita qualsiasi aritmetica su di essi. Se vè un uint32_tche è uguale 4,294,967,294, allora v*=v;dovrebbe fare v=4. Sfortunatamente, se intè 64 bit, allora non si può dire cosa v*=v;potrebbe fare.

Dato lo standard così com'è, suggerirei l'uso di tipi senza segno in situazioni in cui si desidera il comportamento associato agli anelli algebrici e tipi con segno quando si desidera rappresentare i numeri. È un peccato che C abbia tracciato le distinzioni come ha fatto, ma sono quello che sono.


3

Gli interi senza segno hanno molte più probabilità di catturarti in una particolare trappola rispetto agli interi con segno. La trappola deriva dal fatto che mentre 1 e 3 sopra sono corretti, a entrambi i tipi di numeri interi può essere assegnato un valore al di fuori dei limiti di ciò che può "contenere" e verrà convertito silenziosamente.

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 esegui questo, otterrai il seguente output anche se entrambi i valori sono stati assegnati a -1 e sono stati dichiarati in modo diverso.

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

0

L'unica differenza garantita tra un valore con segno e un senza segno in C è che il valore con segno può essere negativo, 0 o positivo, mentre un segno senza segno può essere solo 0 o positivo. Il problema è che C non definisce il formato dei tipi (quindi non sai che i tuoi numeri interi sono nel complemento a due). A rigor di termini i primi due punti che hai citato sono errati.


0

È necessario utilizzare numeri interi senza segno durante la programmazione su sistemi integrati. Nei loop, quando non sono necessari numeri interi con segno, l'utilizzo di numeri interi senza segno salverà la sicurezza necessaria per progettare tali sistemi.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.