Opérations signées et non signées en C

Question très simple:

J’ai un programme qui effectue de nombreux calculs mathématiques sur des in et des longs longs. Pour faire bonne figure, j’ai fait les longs longs non signés, car je ne traitais que des nombres positifs et je pouvais maintenant obtenir un peu plus de valeurs.

Curieusement, cela m’a donné un gain de performance de 15%, ce que j’ai confirmé être simplement en rendant tout le long long non signé.

Est-ce possible? Les opérations mathématiques sont-elles vraiment plus rapides avec des nombres non signés? Je me souviens avoir lu qu’il n’y aurait aucune différence et que le compilateur choisit automatiquement le moyen le plus rapide de procéder, qu’il soit signé ou non. Cette augmentation de 15% provient-elle réellement de la non-signature des vars, ou est-ce que cela pourrait être quelque chose d’autre affecté dans mon code?

Et, s’il s’agit vraiment de rendre les vars non signés, devrais-je essayer de tout supprimer (même les ints), car je n’ai jamais besoin de nombres négatifs, et chaque seconde est importante si je peux le sauvegarder.

Dans certaines opérations, les entiers signés sont plus rapides, dans d’autres, les non-signés sont plus rapides:

  • En C, on peut supposer que les opérations sur les entiers signés ne sont pas encapsulées. Le compilateur en tirera parti, par exemple, en optimisation de boucle. Les comparaisons peuvent être optimisées de manière similaire. (Cela peut également conduire à des bugs subtils si vous ne vous attendez pas à cela).

  • D’autre part, les entiers non signés n’ont pas cette hypothèse. Cependant, le fait de ne pas avoir à composer avec une enseigne constitue un avantage considérable pour certaines opérations, par exemple: la division. La division non signée par une puissance constante de deux correspond à un simple décalage, mais (en fonction de vos règles d’arrondi), il existe une conditionnel off-by-1 pour les nombres négatifs.

Personnellement, je prends l’habitude de n’utiliser que des entiers non signés, à moins que ma valeur ne soit vraiment signée. Ce n’est pas tant pour la performance que l’exactitude.

Vous pouvez voir l’effet amplifié avec long long, ce qui (je suppose) est de 64 bits dans votre cas. Le processeur ne dispose généralement pas d’instructions uniques traitant de ces types (en mode 32 bits), de sorte que la légère complexité ajoutée pour les opérations signées sera plus perceptible.

Sur un processeur 32 bits, les opérations entières de 64 bits sont émulées; utiliser unsigned au lieu de signed signifie que la bibliothèque d’émulation n’a pas à faire de travail supplémentaire pour propager des bits de report, etc.

Il existe trois cas où un compilateur se soucie de savoir si une variable est signée ou non signée:

  1. Lorsque la variable est convertie en un type plus long
  2. Lorsque les opérateurs de comparaison (supérieur à, etc.) sont appliqués
  3. Quand des débordements peuvent se produire

Sur certaines machines, la conversion des variables signées en types plus longs nécessite un code supplémentaire. sur d’autres machines, une conversion peut être effectuée dans le cadre d’une instruction “load” ou “move”.

Certaines machines (principalement de petits microcontrôleurs intégrés) requièrent davantage d’instructions pour effectuer une comparaison signature contre signature que signature non signée, mais la plupart des machines disposent d’une gamme complète d’instructions de comparaison signées et non signées.

Lorsque des dépassements surviennent avec des types non signés, le compilateur peut avoir à append du code pour s’assurer que le comportement défini se produit réellement. Aucun code de ce type n’est requirejs pour les types signés, car tout ce qui pourrait arriver en l’absence de ce code serait autorisé par la norme.

Le compilateur ne choisit pas s’il doit être non signé ou signé. Mais, oui, en théorie, unsigned with unsigned est plus rapide que signed with signed . Si vous voulez vraiment ralentir les choses, vous irez avec signed with unsigned . Et pire encore: floats with integers .

Cela dépend du processeur, bien sûr.