C ++: differenza di due interi non firmati a 64 bit in un numero intero firmato a 64 bit
-
29-10-2019 - |
Domanda
Sto cercando di scrivere una funzione in C ++ che richiede due numeri interi senza segno a 64 bit e restituisce la loro differenza in un numero intero firmato a 64 bit. Sembra essere un po 'complicato a causa della situazione di overflow - poiché gli input sono due numeri interi positivi non firmati, se la differenza assoluta tra questi due è maggiore del valore firmato massimo (int64_max), la differenza non può essere trasmessa attraverso un numero intero firmato. Quindi ho scritto la seguente implementazione e mi chiedevo, in primo luogo, se questo è corretto funzionalmente e in secondo luogo, esiste un'implementazione più semplice. Ogni suggerimento sarà molto apprezzato. Grazie! (Sostituirò l'affermazione con un'eccezione, è proprio lì per ora!)
int64_t GetDifference(uint64_t first, uint64_t second) {
uint64_t abs_diff = (first > second) ? (first - second): (second - first);
uint64_t msb_abs_diff = (abs_diff >> (sizeof(abs_diff)*8 - 1)) & 1;
assert(msb_abs_diff == 0);
int64_t diff = first - second;
return diff;
}
Soluzione
Per me questo sembra un'implementazione più semplice e leggibile.
int64_t GetDifference(uint64_t first, uint64_t second) {
uint64_t abs_diff = (first > second) ? (first - second): (second - first);
assert(abs_diff<=INT64_MAX);
return (first > second) ? (int64_t)abs_diff : -(int64_t)abs_diff;
}
Altri suggerimenti
Tre Nit Picks:
sizeof(abs_diff)*8 - 1
può essere sostituito dal letterale63
senza perdita di portabilità (in effetti, lo sarà Di più portatile a causa di piattaforme in cui achar
non è largo 8 bit)& 1
non è necessario, poiché il risultato del turno è sempre un bit- Puoi derivare
diff
daabs_diff
senza ripetere la sottrazione.
Altrimenti, questo mi sembra perfettamente corretto.
Questo è più breve e probabilmente più veloce.
int64_t GetDifference(uint64_t first, uint64_t second)
{
int64_t diff = first - second;
bool overflowed = (diff < 0) ^ (first < second);
assert(!overflowed);
return diff;
}
Un buon compilatore ottimizzante dovrebbe notarlo diff < 0
è la bandiera negativa e first < second
è la bandiera di trasporto dall'espressione precedente. Confrontare queste due bandiere è il test classico per Overflow.
Anche se non lo rileva, ci sono meno operazioni richieste.
Ma il motivo principale per cui preferisco questo è quello Non ci sono numeri magici.
Cosa ne pensi di questo:
int64_t GetDifference(uint64_t first, uint64_t second) {
int64_t diff = (int64_t)(first - second);
assert first >= second && diff >= 0 || first < second && diff < 0;
return diff;
}