Domanda

Qual è il modo più semplice per verificare se due numeri interi hanno lo stesso segno?Esiste un breve trucco bit a bit per farlo?

È stato utile?

Soluzione

Ecco una versione che funziona in C/C++ che non si basa su dimensioni intere né presenta il problema dell'overflow (ad es.x*y>=0 non funziona)

bool SameSign(int x, int y)
{
    return (x >= 0) ^ (y < 0);
}

Naturalmente, puoi dare un'occhiata e creare un modello:

template <typename valueType>
bool SameSign(typename valueType x, typename valueType y)
{
    return (x >= 0) ^ (y < 0);
}

Nota:Dato che stiamo usando l'or esclusivo, vogliamo che LHS e RHS siano diversi quando i segni sono gli stessi, quindi la differenza viene controllata rispetto allo zero.

Altri suggerimenti

Cosa c'è che non va

return ((x<0) == (y<0));  

?

(a ^ b) >= 0

valuterà 1 se il segno è lo stesso, 0 altrimenti.

Sarei diffidente nei confronti di qualsiasi trucco bit a bit per determinare il segno dei numeri interi, poiché in tal caso è necessario fare ipotesi su come tali numeri sono rappresentati internamente.

Quasi il 100% delle volte, i numeri interi verranno archiviati come due complimenti, ma non è una buona pratica fare ipotesi sulle parti interne di un sistema a meno che non si utilizzi un tipo di dati che garantisce un particolare formato di archiviazione.

Nel complemento a due, puoi semplicemente controllare l'ultimo bit (quello più a sinistra) dell'intero per determinare se è negativo, in modo da poter confrontare solo questi due bit.Ciò significherebbe però che lo 0 avrebbe lo stesso segno di un numero positivo, il che è in contrasto con la funzione di segno implementata nella maggior parte delle lingue.

Personalmente, utilizzerei semplicemente la funzione dei segni della lingua prescelta.È improbabile che si verifichino problemi di prestazioni con un calcolo come questo.

Supponendo int a 32 bit:

bool same = ((x ^ y) >> 31) != 1;

Leggermente più conciso:

bool same = !((x ^ y) >> 31);

Non sono proprio sicuro di considerare "trucco bit a bit" e "più semplice" come sinonimi.Vedo molte risposte che presuppongono interi a 32 bit con segno (anche se it volevo essere sciocco a chiedere non firmato);Non sono sicuro che si applicherebbero ai valori in virgola mobile.

Sembra che il controllo "più semplice" sarebbe quello di confrontare il modo in cui entrambi i valori si confrontano con 0;questo è piuttosto generico presupponendo che i tipi possano essere confrontati:

bool compare(T left, T right)
{
    return (left < 0) == (right < 0);
}

Se i segni sono opposti, diventi falso.Se i segni sono gli stessi, diventi vero.

(intero1 * intero2) > 0

Perché quando due numeri interi condividono lo stesso segno, il risultato della moltiplicazione sarà sempre positivo.

Puoi anche renderlo >= 0 se vuoi trattare 0 come se fosse lo stesso segno, qualunque cosa accada.

Supponendo che il complemento aritmetico a due (http://en.wikipedia.org/wiki/Two_complement):

inline bool same_sign(int x, int y) {
    return (x^y) >= 0;
}

Ciò può richiedere solo due istruzioni e meno di 1 ns su un processore moderno con ottimizzazione.

Non presupponendo l'aritmetica del complemento a due:

inline bool same_sign(int x, int y) {
    return (x<0) == (y<0);
}

Ciò potrebbe richiedere una o due istruzioni aggiuntive e richiedere un po' più di tempo.

Usare la moltiplicazione è una cattiva idea perché è vulnerabile all'overflow.

se (x * y) > 0...

assumendo diverso da zero e simili.

Come nota tecnica, le soluzioni bit-twiddly saranno molto più efficienti della moltiplicazione, anche sulle architetture moderne.Stai risparmiando solo circa 3 cicli, ma sai cosa si dice di un "penny risparmiato"...

Proprio in cima alla mia testa...

int mask = 1 << 31;
(a & mask) ^ (b & mask) < 0;

versione C senza rami:

int sameSign(int a, int b) {
    return ~(a^b) & (1<<(sizeof(int)*8-1));
}

Modello C++ per tipi interi:

template <typename T> T sameSign(T a, T b) {
    return ~(a^b) & (1<<(sizeof(T)*8-1));
}

Per qualsiasi dimensione di int con aritmetica in complemento a due:

#define SIGNBIT (~((unsigned int)-1 >> 1))
if ((x & SIGNBIT) == (y & SIGNBIT))
    // signs are the same

presupponendo 32 bit

if(((x^y) & 0x80000000) == 0)

...la risposta if(x*y>0) è cattivo a causa del trabocco

se (a*b < 0) il segno è diverso, altrimenti il ​​segno è lo stesso (o aob è zero)

Ripensando ai miei giorni universitari, nella maggior parte delle rappresentazioni delle macchine, la parte più a sinistra di un intero non è un 1 quando il numero è negativo e 0 quando è positivo?

Immagino che questo dipenda piuttosto dalla macchina.

int stesso_segno = !( (x >> 31) ^ (y >> 31) );

se (stesso_segno) ...altro ...

Modo migliore di utilizzo std::signbit come segue:

std::signbit(firstNumber) == std::signbit(secondNumber);

Supporta anche altri tipi di base (double, float, char eccetera).

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top