C'était une question d'entrevue posée par un cadre supérieur.
Lequel est plus vite?
while(1) {
// Some code
}
ou
while(2) {
//Some code
}
J'ai dit que les deux ont la même vitesse d'exécution, car l'expression à l'intérieur while
devrait finalement être évaluée à true
ou false
. Dans ce cas, les deux évaluent true
et il n'y a pas d'instructions conditionnelles supplémentaires dans la while
condition. Ainsi, les deux auront la même vitesse d'exécution et je préfère while (1).
Mais l'intervieweur a dit avec confiance: "Vérifiez vos bases. while(1)
Est plus rapide que while(2)
." (Il ne testait pas ma confiance)
Est-ce vrai?
Voir aussi: "for (;;)" est-il plus rapide que "while (TRUE)"? Sinon, pourquoi les gens l'utilisent-ils?
c
performance
while-loop
Nikole
la source
la source
0x100000f90: jmp 0x100000f90
(l'adresse varie, évidemment) pour les deux extraits. L'intervieweur a probablement couvert un test de registre contre un simple saut signalé. La question et leur supposition sont toutes deux boiteuses.Réponses:
Les deux boucles sont infinies, mais nous pouvons voir laquelle prend plus d'instructions / ressources par itération.
En utilisant gcc, j'ai compilé les deux programmes suivants pour l'assemblage à différents niveaux d'optimisation:
Même sans optimisations (
-O0
), l'assembly généré était identique pour les deux programmes . Par conséquent, il n'y a pas de différence de vitesse entre les deux boucles.Pour référence, voici l'assembly généré (à l'aide
gcc main.c -S -masm=intel
d'un indicateur d'optimisation):Avec
-O0
:Avec
-O1
:Avec
-O2
et-O3
(même sortie):En effet, l'assembly généré pour la boucle est identique pour chaque niveau d'optimisation:
Les bits importants étant:
Je ne peux pas très bien lire l'assemblage, mais c'est évidemment une boucle inconditionnelle. L'
jmp
instruction réinitialise inconditionnellement le programme sur l'.L2
étiquette sans même comparer une valeur par rapport à true, et bien sûr le fait immédiatement à nouveau jusqu'à ce que le programme soit en quelque sorte terminé. Cela correspond directement au code C / C ++:Éditer:
Chose intéressante, même sans optimisation , les boucles suivantes ont toutes produit exactement la même sortie (inconditionnelle
jmp
) dans l'assemblage:Et même à mon grand étonnement:
Les choses deviennent un peu plus intéressantes avec les fonctions définies par l'utilisateur:
À
-O0
, ces deux exemples appellentx
et effectuent une comparaison pour chaque itération.Premier exemple (retour 1):
Deuxième exemple (retour
sqrt(7)
):Cependant, au niveau
-O1
et au -dessus, ils produisent tous les deux le même assemblage que les exemples précédents (unjmp
retour inconditionnel à l'étiquette précédente).TL; DR
Sous GCC, les différentes boucles sont compilées en assemblage identique. Le compilateur évalue les valeurs constantes et ne prend pas la peine d'effectuer une comparaison réelle.
La morale de l'histoire est:
la source
-O
niveaux.jmp
au début, soit supprimer la boucle complètement.break
instruction), mais je l'ai quand même testé et non, même avec du code à l'intérieur de la boucle, le saut est absolu et inconditionnel pourwhile(1)
etwhile(2)
. N'hésitez pas à tester les autres vous-même si vous êtes réellement concerné.Oui,
while(1)
c'est beaucoup plus rapide quewhile(2)
, pour un humain, de lire! Si je voiswhile(1)
dans une base de code inconnue, je sais immédiatement ce que l'auteur voulait, et mes globes oculaires peuvent continuer jusqu'à la ligne suivante.Si je vois
while(2)
, je vais probablement m'arrêter sur mes traces et essayer de comprendre pourquoi l'auteur n'a pas écritwhile(1)
. Le doigt de l'auteur a-t-il glissé sur le clavier? Les responsables de cette base de code utilisent-ilswhile(n)
comme un mécanisme de commentaire obscur pour rendre les boucles différentes? Est-ce une solution de contournement grossière pour un avertissement fallacieux dans un outil d'analyse statique cassé? Ou est-ce un indice que je lis le code généré? S'agit-il d'un bogue résultant d'une recherche et d'un remplacement non judicieux, d'une mauvaise fusion ou d'un rayon cosmique? Peut-être que cette ligne de code est censée faire quelque chose de radicalement différent. Peut-être que c'était censé lirewhile(w)
ouwhile(x2)
. Je ferais mieux de trouver l'auteur dans l'historique du fichier et de leur envoyer un e-mail "WTF" ... et maintenant j'ai rompu mon contexte mental.while(2)
while(1)
aurait pris une fraction de seconde!J'exagère, mais seulement un peu. La lisibilité du code est vraiment importante. Et cela mérite d'être mentionné dans une interview!
la source
svn-annotate
ougit blame
(ou autre) sera utilisé ici, et en général cela prend quelques minutes pour charger un historique de blâme de fichier. Puis juste pour finalement décider "ah je comprends, l'auteur a écrit cette ligne à la sortie du lycée", vient de perdre 10 minutes ...1
.while(2)
dans le code (jusqu'à considérer "Les responsables de cette base de code utilisent-ils alors que (n) comme un mécanisme de commentaire obscur pour rendre les boucles différentes?") ). Alors non, vous n'exagérez pas!Les réponses existantes montrant le code généré par un compilateur particulier pour une cible particulière avec un ensemble d'options particulier ne répondent pas entièrement à la question - à moins que la question n'ait été posée dans ce contexte spécifique ("qui est plus rapide en utilisant gcc 4.7.2 pour x86_64 avec les options par défaut? ", par exemple).
En ce qui concerne la définition du langage, la machine abstraite
while (1)
évalue la constante entière1
etwhile (2)
évalue la constante entière2
; dans les deux cas, le résultat est comparé à zéro. La norme de langage ne dit absolument rien sur les performances relatives des deux constructions.Je peux imaginer qu'un compilateur extrêmement naïf pourrait générer un code machine différent pour les deux formulaires, au moins lorsqu'il est compilé sans demander d'optimisation.
En revanche, les compilateurs C doivent absolument évaluer certaines expressions constantes au moment de la compilation, lorsqu'elles apparaissent dans des contextes qui nécessitent une expression constante. Par exemple, ceci:
nécessite un diagnostic; un compilateur paresseux n'a pas la possibilité de reporter l'évaluation
2+2
jusqu'au moment de l'exécution. Puisqu'un compilateur doit avoir la capacité d'évaluer des expressions constantes au moment de la compilation, il n'y a aucune bonne raison pour qu'il ne profite pas de cette capacité même si elle n'est pas requise.La norme C ( N1570 6.8.5p4) dit que
Ainsi, les expressions constantes pertinentes sont
1 == 0
et2 == 0
, toutes deux évaluées à laint
valeur0
. (Ces comparaisons sont implicites dans la sémantique de lawhile
boucle; elles n'existent pas en tant qu'expressions C réelles.)Un compilateur perversement naïf pourrait générer un code différent pour les deux constructions. Par exemple, pour le premier, il pourrait générer une boucle infinie inconditionnelle (traitée
1
comme un cas spécial), et pour le second, il pourrait générer une comparaison d'exécution explicite équivalente à2 != 0
. Mais je n'ai jamais rencontré de compilateur C qui se comporterait réellement de cette façon, et je doute sérieusement qu'un tel compilateur existe.La plupart des compilateurs (je suis tenté de dire que tous les compilateurs de qualité production) ont des options pour demander des optimisations supplémentaires. Avec une telle option, il est encore moins probable qu'un compilateur génère du code différent pour les deux formulaires.
Si votre compilateur génère un code différent pour les deux constructions, vérifiez d'abord si les séquences de code différentes ont réellement des performances différentes. Si tel est le cas, essayez à nouveau de compiler avec une option d'optimisation (si disponible). S'ils diffèrent toujours, soumettez un rapport de bogue au fournisseur du compilateur. Ce n'est pas (nécessairement) un bug dans le sens d'une non-conformité à la norme C, mais c'est presque certainement un problème qui devrait être corrigé.
Bottom line:
while (1)
et ontwhile(2)
presque certainement les mêmes performances. Ils ont exactement la même sémantique, et il n'y a aucune bonne raison pour qu'un compilateur ne génère pas de code identique.Et bien qu'il soit parfaitement légal pour un compilateur de générer du code plus rapide pour
while(1)
que pourwhile(2)
, il est tout aussi légal pour un compilateur de générer du code plus rapidewhile(1)
que pour une autre occurrence dewhile(1)
dans le même programme.(Il y a une autre question implicite dans celle que vous avez posée: comment gérez-vous un enquêteur qui insiste sur un point technique incorrect. Ce serait probablement une bonne question pour le site Workplace ).
la source
while
doit être de type scalaire et le corps de la boucle est répété jusqu'à ce que l'expression soit égale à 0. Elle ne dit pas qu'il y a un impliciteexpr != 0
qui est évalué ... qui nécessiterait le résultat de que - 0 ou 1 - soit à son tour comparé à 0, à l'infini. Non, l'expression est comparée à 0, mais cette comparaison ne produit pas de valeur. PS J'ai voté.<expr> == 0
; c'est ce que "compare égal à 0" signifie en C. Cette comparaison fait partie de la sémantique de lawhile
boucle. Il n'y a aucune implication, que ce soit dans la norme ou dans ma réponse, que le résultat doit être comparé à0
nouveau. (J'aurais dû écrire==
plutôt que!=
.) Mais cette partie de ma réponse n'était pas claire, et je vais la mettre à jour.while (2)
,while (pointer)
,while (9.67)
, par le plus naïf, compilateur unoptimized, vous ne verrez aucun code généré que les rendements0
ou1
. "J'aurais dû écrire == plutôt que! =" - non, cela n'aurait aucun sens.... == 0
expression C. Mon point est que les deux "compare égal à 0" requis par la description standard deswhile
boucles et unex == 0
expression explicite impliquent logiquement la même opération. Et je pense qu'un compilateur C douloureusement naïf pourrait générer du code qui génère uneint
valeur de0
ou1
pour n'importe quellewhile
boucle - bien que je ne pense pas qu'un véritable compilateur soit tout à fait naïf.Attends une minute. L'intervieweur, ressemblait-il à ce type?
Il est déjà assez grave que l'intervieweur lui-même n'ait pas réussi cette interview, et si d'autres programmeurs de cette entreprise ont "réussi" ce test?
Non. Évaluer les déclarations
1 == 0
et2 == 0
devrait être tout aussi rapide. Nous pourrions imaginer de mauvaises implémentations de compilateur où l'une pourrait être plus rapide que l'autre. Mais il n'y a aucune bonne raison pour que l'un soit plus rapide que l'autre.Même s'il y a une circonstance obscure où l'affirmation serait vraie, les programmeurs ne devraient pas être évalués sur la base de la connaissance de futilités obscures (et dans ce cas, effrayantes). Ne vous inquiétez pas de cette interview, la meilleure chose à faire ici est de vous éloigner.
Avertissement: Ce n'est PAS une bande dessinée originale de Dilbert. Ce n'est qu'un mashup .
la source
cmp
opérande fonctionnera-t-il en moins de cycles en comparant 1 à 0 à 2 à 0? combien de cycles faut-il pour exécuter cmp en général? est-il variable en fonction des motifs binaires? sont-ils des motifs binaires plus "complexes" qui ralentissentcmp
? Je ne sais pas personnellement. vous pourriez imaginer une implémentation super idiote vérifiant peu à peu le rang 0 à n (par exemple n = 31).cmp
opérande devrait être également rapide pour 1 et 200. Nous pourrions probablement imaginer des implémentations idiotes où ce n'est pas le cas. Mais peut-on imaginer une implémentation non idiote oùwhile(1)
est plus rapide quewhile(200)
? De même, si à une époque préhistorique, la seule implémentation disponible était idiote comme ça, devrions-nous nous en soucier aujourd'hui? Je ne pense pas, c'est un discours de patron aux cheveux pointus, et un vrai bijou à ça!Votre explication est correcte. Cela semble être une question qui teste votre confiance en vous en plus des connaissances techniques.
Au fait, si vous avez répondu
l'intervieweur dirait
Donc, en répondant comme vous l'avez fait, vous avez gagné du temps que vous perdriez autrement à discuter de cette mauvaise question.
Voici un exemple de code généré par le compilateur sur mon système (MS Visual Studio 2012), avec les optimisations désactivées:
Avec les optimisations activées:
Le code généré est donc exactement le même, au moins avec un compilateur d'optimisation.
la source
while
longtemps l'a précédé) et l'opérande dewhile
n'est pas booléen ou _Bool ou tout autre type spécifique. L'opérande dewhile
peut être n'importe quelle expression ... tandis que le temps s'arrête sur 0 et continue sur non-0.while (00000001) {}
àwhile (00000000) {}
. Plus vous avez de vrais bits, moins vous avez de chances que la valeur passe à faux. Malheureusement, 2 n'a également qu'un seul bit vrai. 3, cependant, durerait beaucoup plus longtemps. Cela ne s'applique également qu'à un compilateur qui n'optimise pas toujours cela (VC ++).L'explication la plus probable de la question est que l'intervieweur pense que le processeur vérifie les bits individuels des nombres, un par un, jusqu'à ce qu'il atteigne une valeur non nulle:
Si le "est zéro?" l'algorithme commence à droite du nombre et doit vérifier chaque bit jusqu'à ce qu'il atteigne un bit différent de zéro, la
while(1) { }
boucle devrait vérifier deux fois plus de bits par itération que lawhile(2) { }
boucle.Cela nécessite un modèle mental très erroné du fonctionnement des ordinateurs, mais il a sa propre logique interne. Une façon de vérifier serait de demander si
while(-1) { }
ouwhile(3) { }
serait tout aussi rapide, ou si cewhile(32) { }
serait encore plus lent .la source
cmp
algorithme d'un CPU est une vérification de bit linéaire avec sortie de boucle précoce sur la première différence.-O0
sortie de gcc ou clang n'est pas assez littérale." Je n'ai jamais dit une telle chose et je n'ai pas du tout pensé à gcc ou clang. Vous devez me mal interpréter. Je ne suis tout simplement pas d'avis que ce que MSVC produit est hilarant.while(1)
ne se casse pas avant la boucle, mais sur l'expression. Mais il s'effondre toujours à l'intérieur de la boucle lors de l'optimisation de l'expression. Prenez ce code avec beaucoup de pauses. En mode de débogage non optimisé, vous obtenez cela . Lors de l'optimisation, de nombreux points d'arrêt tombent ensemble ou débordent même dans la fonction suivante (l'EDI affiche les points d'arrêt résultants lors du débogage) - démontage correspondant .Bien sûr, je ne connais pas les véritables intentions de ce manager, mais je propose une vision complètement différente: Lors de l'embauche d'un nouveau membre dans une équipe, il est utile de savoir comment il réagit aux situations de conflit.
Ils vous ont conduit au conflit. Si c'est vrai, ils sont intelligents et la question était bonne. Pour certaines industries, comme la banque, la publication de votre problème dans Stack Overflow peut être une raison de rejet.
Mais bien sûr je ne sais pas, je propose juste une option.
la source
Je pense que l'indice se trouve dans "demandé par un cadre supérieur". Il est évident que cette personne a cessé de programmer lorsqu'elle est devenue gestionnaire, puis il lui a fallu plusieurs années pour devenir cadre supérieur. Je n'ai jamais perdu d'intérêt pour la programmation, mais je n'ai jamais écrit de ligne depuis ces jours. Donc, sa référence n'est pas "n'importe quel compilateur décent", comme le mentionnent certaines réponses, mais "le compilateur avec lequel cette personne a travaillé il y a 20-30 ans".
À cette époque, les programmeurs passaient un pourcentage considérable de leur temps à essayer diverses méthodes pour rendre leur code plus rapide et plus efficace, car le temps CPU du «mini-ordinateur central» était si précieux. Tout comme les gens qui écrivent des compilateurs. Je suppose que le seul et unique compilateur que sa société a rendu disponible à ce moment-là a été optimisé sur la base des `` déclarations fréquemment rencontrées qui peuvent être optimisées '' et a pris un peu de raccourci lors de la rencontre (1) et a tout évalué sinon, y compris un certain temps (2). Une telle expérience pourrait expliquer sa position et sa confiance en elle.
La meilleure approche pour vous embaucher est probablement celle qui permet au cadre supérieur de s'emballer et de vous faire une conférence de 2 à 3 minutes sur "le bon vieux temps de la programmation" avant de le conduire en douceur vers le sujet de l'entretien suivant. (Un bon timing est important ici - trop rapide et vous interrompez l'histoire - trop lent et vous êtes étiqueté comme quelqu'un avec une concentration insuffisante). Dites-lui à la fin de l'entretien que vous seriez très intéressé à en savoir plus sur ce sujet.
la source
Vous auriez dû lui demander comment il en est arrivé à cette conclusion. Sous n'importe quel compilateur décent, les deux compilent les mêmes instructions asm. Donc, il aurait aussi dû vous dire le compilateur pour commencer. Et même ainsi, vous devriez très bien connaître le compilateur et la plate-forme pour faire une supposition théorique. Et au final, cela n'a pas vraiment d'importance dans la pratique, car il existe d'autres facteurs externes comme la fragmentation de la mémoire ou la charge du système qui influenceront la boucle plus que ce détail.
la source
Pour cette question, je dois ajouter que je me souviens que Doug Gwyn du comité C avait écrit que certains des premiers compilateurs C sans la passe de l'optimiseur génèreraient un test en assemblage pour le
while(1)
(comparé à celuifor(;;)
qui ne l'aurait pas).Je répondrais à l'intervieweur en donnant cette note historique et en disant ensuite que même si je serais très surpris qu'un compilateur fasse cela, un compilateur pourrait avoir:
while(1)
etwhile(2)
while(1)
parce qu'ils sont considérés comme idiomatiques. Cela laisserait lewhile(2)
test et ferait donc une différence de performances entre les deux.J'ajouterais bien sûr à l'intervieweur que le fait de ne pas considérer
while(1)
etwhile(2)
la même construction est un signe d'optimisation de faible qualité car ce sont des constructions équivalentes.la source
Une autre prise sur une telle question serait de voir si vous avez le courage de dire à votre manager qu'il a tort! Et avec quelle douceur vous pouvez le communiquer.
Mon premier réflexe aurait été de générer une sortie d'assembly pour montrer au gestionnaire que tout compilateur décent devrait s'en occuper, et si ce n'est pas le cas, vous soumettrez le prochain patch pour cela :)
la source
Voir autant de personnes se plonger dans ce problème montre exactement pourquoi cela pourrait très bien être un test pour voir à quelle vitesse vous voulez micro-optimiser les choses.
Ma réponse serait; cela n'a pas beaucoup d'importance, je me concentre plutôt sur le problème commercial que nous résolvons. Après tout, c'est pour ça que je vais être payé.
De plus, j'opterais pour
while(1) {}
car c'est plus courant et les autres coéquipiers n'auraient pas besoin de passer du temps pour comprendre pourquoi quelqu'un irait pour un nombre supérieur à 1.Maintenant, écrivez du code. ;-)
la source
Si vous êtes préoccupé par l'optimisation, vous devez utiliser
car cela n'a pas de tests. (mode cynique)
la source
while(2)
, il laisse de la place pour l'optimisation, puis vous passez simplement aufor (;;)
moment où vous êtes prêt pour une amélioration des performances.Il me semble que c'est l'une de ces questions d'entrevue comportementale masquée comme une question technique. Certaines entreprises le font - elles poseront une question technique qui devrait être assez facile à répondre pour tout programmeur compétent, mais lorsque l'enquêté donne la bonne réponse, l'intervieweur leur dira qu'ils ont tort.
L'entreprise souhaite savoir comment vous allez réagir dans cette situation. Vous asseyez-vous tranquillement et n'insistez pas pour que votre réponse soit correcte, à cause du doute de soi ou de la peur de déranger l'intervieweur? Ou êtes-vous prêt à défier une personne en autorité dont vous savez qu'elle a tort? Ils veulent voir si vous êtes prêt à défendre vos convictions et si vous pouvez le faire avec tact et respect.
la source
J'avais l'habitude de programmer le code C et l'assembly lorsque ce genre de non-sens aurait pu faire une différence. Quand cela a fait une différence, nous l'avons écrit à l'Assemblée.
Si on m'avait posé cette question, j'aurais répété la célèbre citation de Donald Knuth de 1974 sur l'optimisation prématurée et je me serais promené si l'intervieweur ne riait pas et ne continuait pas.
la source
Peut-être que l'intervieweur a posé intentionnellement une question aussi stupide et voulait que vous fassiez trois remarques:
la source
Voici un problème: si vous écrivez réellement un programme et mesurez sa vitesse, la vitesse des deux boucles pourrait être différente! Pour une comparaison raisonnable:
avec du code ajouté qui imprime l'heure, un effet aléatoire comme la position de la boucle dans une ou deux lignes de cache pourrait faire la différence. Une boucle peut, par pur hasard, se trouver entièrement dans une ligne de cache, ou au début d'une ligne de cache, ou elle peut chevaucher deux lignes de cache. Et par conséquent, tout ce que l'enquêteur prétend être le plus rapide pourrait être le plus rapide - par coïncidence.
Pire scénario: un compilateur d'optimisation ne comprend pas ce que fait la boucle, mais détermine que les valeurs produites lorsque la deuxième boucle est exécutée sont les mêmes que celles produites par la première. Et générez du code complet pour la première boucle, mais pas pour la seconde.
la source
Ils sont tous deux égaux - les mêmes.
Selon les spécifications, tout ce qui n'est pas 0 est considéré comme vrai, donc même sans aucune optimisation, et un bon compilateur ne générera aucun code pour while (1) ou while (2). Le compilateur générerait une simple vérification
!= 0
.la source
À en juger par la quantité de temps et d'efforts que les gens ont passé à tester, prouver et répondre à cette question très simple, je dirais que les deux ont été très lents en posant la question.
Et donc pour y consacrer encore plus de temps ...
"while (2)" est ridicule, car,
"while (1)" et "while (true)" sont historiquement utilisés pour créer une boucle infinie qui s'attend à ce que "break" soit appelé à un certain stade à l'intérieur de la boucle en fonction d'une condition qui se produira certainement.
Le "1" est simplement là pour toujours être évalué comme vrai et donc, dire "while (2)" est à peu près aussi idiot que dire "while (1 + 1 == 2)" qui sera également évalué comme vrai.
Et si vous voulez être complètement idiot, utilisez simplement: -
J'aimerais penser que votre codeur a fait une faute de frappe qui n'a pas affecté le fonctionnement du code, mais s'il a intentionnellement utilisé le "2" juste pour être bizarre, limogez-le avant qu'il ne mette bizarre tout le long de votre code, ce qui le rend difficile à lire et travailler avec.
la source
Cela dépend du compilateur.
S'il optimise le code ou s'il évalue 1 et 2 à vrai avec le même nombre d'instructions pour un ensemble d'instructions particulier, la vitesse d'exécution sera la même.
Dans des cas réels, il sera toujours aussi rapide, mais il serait possible d'imaginer un compilateur particulier et un système particulier lorsque cela serait évalué différemment.
Je veux dire: ce n'est pas vraiment une question liée à la langue (C).
la source
Étant donné que les personnes cherchant à répondre à cette question souhaitent la boucle la plus rapide, j'aurais répondu que les deux se compilent également dans le même code d'assemblage, comme indiqué dans les autres réponses. Néanmoins, vous pouvez suggérer à l'intervieweur d'utiliser le «déroulement de boucle»; une boucle do {} while au lieu de la boucle while.
Attention: vous devez vous assurer que la boucle s'exécute au moins toujours une fois .
La boucle doit avoir une condition de rupture à l'intérieur.
Aussi pour ce type de boucle, je préférerais personnellement l'utilisation de do {} while (42) car n'importe quel entier, sauf 0, ferait le travail.
la source
La réponse évidente est: comme publié, les deux fragments exécuteraient une boucle infinie également occupée, ce qui rend le programme infiniment lent .
Bien que la redéfinition des mots clés C en tant que macros aurait techniquement un comportement indéfini, c'est la seule façon dont je puisse penser pour rendre l'un des fragments de code rapide: vous pouvez ajouter cette ligne au-dessus des 2 fragments:
il sera en effet
while(1)
deux fois plus rapide (ou moitié moins lent) quewhile(2)
.la source
La seule raison pour laquelle je peux penser que le
while(2)
serait plus lent est:Le code optimise la boucle pour
cmp eax, 2
Lorsque la soustraction se produit, vous soustrayez essentiellement
une.
00000000 - 00000010 cmp eax, 2
au lieu de
b.
00000000 - 00000001 cmp eax, 1
cmp
définit uniquement des indicateurs et ne définit pas de résultat. Donc, sur les bits les moins significatifs, nous savons si nous devons emprunter ou non avec b . Alors qu'avec un, vous devez effectuer deux soustractions avant d'obtenir un emprunt.la source