Multiplication de deux entiers en C++
J'ai plutôt une question de base, mais je ne suis pas sûr si je comprends le concept ou pas. Supposons que l'on ait:
int a = 1000000;
int b = 1000000;
long long c = a * b;
Lorsque je l'exécute, c
montre la valeur est négative, alors j'ai changé aussi a
et b
à long long
et puis tout s'était bien passé. Alors, pourquoi dois-je changer de a
et b
, lorsque leurs valeurs sont dans la gamme de int
et leur produit est affecté à c
(qui est long long
)?
Je suis à l'aide de C/C++
- Les services de renseignements ne sont pas promus à long avant de multiplication, ils restent entiers et le produit ainsi. Ensuite, le produit est jeté à long long, mais trop tard, le débordement a frappé. Avoir un de a ou b long devrait fonctionner aussi bien, que les autres seraient encouragées.
- Vous devriez tag de la programmation de la langue à l'aide de causer des langues différentes peuvent présenter des comportements différents 😉
- En fonction de la machine et la version de C vous êtes à l'aide de la taille d'un int peut changer.
- vous devriez faire tous les officiels et des trucs et copier/coller dans une réponse plutôt qu'il s'encanailler comme un commentaire. 🙂
- pourquoi pas ?:-)
- long long c = ((long long)a*(long long)b);
- long long c=(long long)a*b
- D'habitude, je préfère ne pas ajouter des balises dans les titres, mais c'est discutable
- C'est une réplique de l'une de mes premières questions stackoverflow.com/questions/29579112/...
Vous devez vous connecter pour publier un commentaire.
La
int
s ne sont pas promus àlong long
avant de multiplication, ils restentint
s et le produit ainsi. Ensuite, le produit est jeté à l'long long
, mais trop tard, le débordement a frappé.D'avoir l'une des
a
oub
long long
devrait fonctionner aussi bien, que les autres seraient encouragées.Pour les opérateurs arithmétiques le type de résultat ne dépend pas de ce que vous attribuant le résultat à mais les types des opérandes. Pour les opérateurs arithmétiques les d'habitude arithmétique des conversions sont effectuées sur les opérandes. Ce est utilisé pour amener les opérandes à un type commun, ce qui signifie pour les types plus petits que unsigned/signé int si les valeurs peuvent ajustement qu'ils sont promus à la unsigned/signé int, dans ce cas, ils sont déjà à la fois int donc aucune conversion n'est nécessaire. Voir Pourquoi faut-il un court-être converti en int avant que des opérations arithmétiques en C et C++? pour plus de détails sur le pourquoi.
Ce que nous avons maintenant est un comportement indéfini depuis signé débordement d'entier est un comportement indéfini, ce qui est couvert dans le projet de norme C++ section
5
[Expr] qui dit:Maintenant-a-jours, nous avons désinfectants pour attraper ces types de comportement indéfini et à l'aide de
-fsanitize=undefined
avec les deux clang et gcc va attraper cette lors de l'exécution avec le message d'erreur suivant (voir en direct):Pour la section de référence
5.6
[expr.mul] dit:et de l'article
5
dit:C'est un peu absurde, parce que l'instruction assembleur n'a toujours calculer
int * int -> 64 bits
donc, si vous regardez le code de l'ordinateur, vous pouvez voir :
imul
ce magasin 64bits dans edx, eax
alors
cdq
que le bit de signe de eax dans edx (et donc de perdre la totalité de la 64bits suite)
et puis eax edx sont stockés dans le 64bits variable
et si vous convertissez le 32bits valeurs en 64bits avant la multiplication, vous obtenez un appel à la 64bits multiplication de la fonction pour aucune raison
(J'ai vérifié : ce n'est pas le cas lorsque le code est optimisé)