C ++: différence de deux entiers 64 bits non signés dans un entier 64 bits signé

StackOverflow https://stackoverflow.com/questions/8886014

  •  29-10-2019
  •  | 
  •  

Question

J'essaie d'écrire une fonction en C ++ qui prend deux entiers non signés 64 bits et renvoie leur différence dans un entier 64 bits signé. Cela semble un peu compliqué en raison de la situation de débordement - car les entrées sont deux entiers positifs non signés, si la différence absolue entre ces deux est supérieure à la valeur signée maximale (int64_max), alors la différence ne peut pas être transmise via un entier signé. J'ai donc écrit l'implémentation suivante, et je me demandais, d'abord, si c'est correct fonctionnellement, et deuxièmement, y a-t-il une implémentation plus simple. Toutes les suggestions seraient grandement appréciées. Merci! (Je vais remplacer l'affirmation par une exception, elle est juste là pour le moment!)

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;
}
Était-ce utile?

La solution

Pour moi, cela semble une implémentation plus simple et plus lisible.

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;
}

Autres conseils

Trois nitpicks:

  • sizeof(abs_diff)*8 - 1 peut être remplacé par le littéral 63 sans perte de portabilité (en fait, ce sera Suite portable en raison de plates-formes où un char n'est pas de 8 bits de large)
  • & 1 n'est pas nécessaire, car le résultat du changement est toujours un bit
  • Vous pouvez dériver diff de abs_diff sans répéter la soustraction.

Sinon, cela me semble parfaitement correct.

C'est plus court et probablement plus rapide.

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 bon compilateur d'optimisation devrait remarquer que diff < 0 est le drapeau négatif et first < second est le drapeau de transport de l'expression antérieure. La comparaison de ces deux drapeaux est le test classique pour le débordement.

Même s'il ne détecte pas cela, il y a moins d'opérations requises.

Mais la plus grande raison pour laquelle je préfère cela Il n'y a pas de chiffres magiques.

Que dis-tu de ça:

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;
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top