Comment puis-je m'assurer qu'une division d'entiers est toujours arrondie?
243
Je veux m'assurer qu'une division d'entiers est toujours arrondie si nécessaire. Y a-t-il une meilleure façon que cela? Il y a beaucoup de casting en cours. :-)
Pouvez-vous définir plus clairement ce que vous considérez comme «meilleur»? Plus rapide? Plus court? Plus précise? Plus robuste? Plus évidemment correct?
Eric Lippert
6
Vous avez toujours beaucoup de casting avec des mathématiques en C # - c'est pourquoi ce n'est pas un excellent langage pour ce genre de chose. Voulez-vous que les valeurs soient arrondies vers le haut ou loin de zéro - devrait -3,1 passer à -3 (haut) ou -4 (loin de zéro)
Keith
9
Eric: Que voulez-vous dire par "Plus précis? Plus robuste? Plus évidemment correct?" En fait, ce que je voulais dire était simplement "mieux", je laisserais le lecteur mieux comprendre le sens. Donc, si quelqu'un avait un morceau de code plus court, super, si un autre en avait un plus rapide, aussi super :-) Et vous, avez-vous des suggestions?
Karsten
1
Suis-je le seul qui, à la lecture du titre, "Oh, c'est une sorte de rafle de C #?"
Matt Ball
6
C'est vraiment incroyable de voir à quel point cette question s'est avérée subtilement difficile et à quel point la discussion a été instructive.
Il est difficile d'obtenir une arithmétique entière correcte. Comme cela a été amplement démontré jusqu'à présent, au moment où vous essayez de faire un tour "intelligent", les chances sont bonnes que vous ayez fait une erreur. Et quand une faille est trouvée, changer le code pour corriger la faille sans se demander si la correction rompt autre chose n'est pas une bonne technique de résolution de problème. Jusqu'à présent, nous avons eu, je pense, cinq solutions arithmétiques entières incorrectes différentes à ce problème complètement pas particulièrement difficile.
La bonne façon d'aborder les problèmes arithmétiques entiers - c'est-à-dire la façon qui augmente la probabilité d'obtenir la bonne réponse la première fois - est d'aborder le problème avec soin, de le résoudre étape par étape et d'utiliser de bons principes d'ingénierie pour le faire. alors.
Commencez par lire les spécifications de ce que vous essayez de remplacer. La spécification pour la division entière indique clairement:
La division arrondit le résultat vers zéro
Le résultat est zéro ou positif lorsque les deux opérandes ont le même signe et zéro ou négatif lorsque les deux opérandes ont des signes opposés
Si l'opérande gauche est le plus petit entier représentable et l'opérande droit est –1, un débordement se produit. [...] il est défini par l'implémentation si [une ArithmeticException] est levée ou si le débordement n'est pas signalé, la valeur résultante étant celle de l'opérande de gauche.
Si la valeur de l'opérande de droite est zéro, une System.DivideByZeroException est levée.
Ce que nous voulons, c'est une fonction de division entière qui calcule le quotient mais arrondit toujours le résultat vers le haut , pas toujours vers zéro .
Écrivez donc une spécification pour cette fonction. Notre fonction int DivRoundUp(int dividend, int divisor)doit avoir un comportement défini pour chaque entrée possible. Ce comportement indéfini est profondément préoccupant, alors éliminons-le. Nous dirons que notre opération a cette spécification:
opération lance si le diviseur est nul
opération lance si le dividende est int.minval et le diviseur est -1
s'il n'y a pas de reste - la division est 'paire' - alors la valeur de retour est le quotient intégral
Sinon, il renvoie le plus petit entier supérieur au quotient, c'est-à-dire qu'il arrondit toujours.
Nous avons maintenant une spécification, nous savons donc que nous pouvons proposer une conception testable . Supposons que nous ajoutions un critère de conception supplémentaire pour que le problème soit résolu uniquement avec une arithmétique entière, plutôt que de calculer le quotient comme un double, car la solution "double" a été explicitement rejetée dans l'énoncé du problème.
Alors, que devons-nous calculer? De toute évidence, pour répondre à nos spécifications tout en restant uniquement en arithmétique entière, nous devons connaître trois faits. Tout d'abord, quel était le quotient entier? Deuxièmement, la division était-elle exempte de reste? Et troisièmement, sinon, le quotient entier a-t-il été calculé en arrondissant vers le haut ou vers le bas?
Maintenant que nous avons une spécification et une conception, nous pouvons commencer à écrire du code.
publicstaticintDivRoundUp(int dividend,int divisor){if(divisor ==0)throw...if(divisor ==-1&& dividend ==Int32.MinValue)throw...int roundedTowardsZeroQuotient = dividend / divisor;bool dividedEvenly =(dividend % divisor)==0;if(dividedEvenly)return roundedTowardsZeroQuotient;// At this point we know that divisor was not zero // (because we would have thrown) and we know that // dividend was not zero (because there would have been no remainder)// Therefore both are non-zero. Either they are of the same sign, // or opposite signs. If they're of opposite sign then we rounded // UP towards zero so we're done. If they're of the same sign then // we rounded DOWN towards zero, so we need to add one.bool wasRoundedDown =((divisor >0)==(dividend >0));if(wasRoundedDown)return roundedTowardsZeroQuotient +1;elsereturn roundedTowardsZeroQuotient;}
Est-ce intelligent? Pas beau? Non. Court? Non. Correct selon la spécification? Je le crois, mais je ne l'ai pas entièrement testé. Cela semble assez bon cependant.
Nous sommes des professionnels ici; utiliser de bonnes pratiques d'ingénierie. Recherchez vos outils, spécifiez le comportement souhaité, examinez d'abord les cas d'erreur et écrivez le code pour souligner son exactitude évidente. Et lorsque vous trouvez un bogue, demandez-vous si votre algorithme est profondément défectueux pour commencer avant de commencer à échanger au hasard les directions des comparaisons et à casser des choses qui fonctionnent déjà.
Ce qui m'importe, ce n'est pas le comportement; l'un ou l'autre comportement semble justifiable. Ce qui m'importe, c'est qu'il n'est pas spécifié , ce qui signifie qu'il ne peut pas être facilement testé. Dans ce cas, nous définissons notre propre opérateur, afin que nous puissions spécifier le comportement que nous voulons. peu m'importe si ce comportement est "lancer" ou "ne pas lancer", mais je tiens à ce qu'il soit indiqué.
Eric Lippert
69
Darn it, pedantry fail :(
Jon Skeet
33
Homme - Pourriez-vous écrire un livre à ce sujet, s'il vous plaît?
xtofl
77
@finnw: Que je l'ai testé ou non n'a pas d'importance. Résoudre ce problème arithmétique entier n'est pas mon problème commercial; si c'était le cas, je le testerais. Si quelqu'un veut prendre le code des étrangers sur internet pour résoudre leur problème d'entreprise , alors il incombe à les tester à fond il.
Eric Lippert
49
Jusqu'à présent, toutes les réponses semblent assez compliquées.
En C # et Java, pour un dividende et un diviseur positifs, il vous suffit de faire:
Impressionnant. Bien que vous auriez dû ajouter les parenthèses pour supprimer les ambiguïtés, la preuve était un peu longue, mais vous pouvez le sentir dans l'intestin, que c'est juste, juste en le regardant.
Jörgen Sigvardsson
1
Hmmm ... qu'en est-il du dividende = 4, diviseur = (- 2) ??? 4 / (-2) = (-2) = (-2) après avoir été arrondi. mais l'algorithme que vous avez fourni (4 + (-2) - 1) / (-2) = 1 / (-2) = (-0,5) = 0 après avoir été arrondi.
Scott
1
@Scott - désolé, j'ai omis de mentionner que cette solution ne s'applique qu'aux dividendes et diviseurs positifs. J'ai mis à jour ma réponse pour mentionner clarifier cela.
Ian Nelson
1
je l'aime bien sûr, vous pourriez avoir un débordement quelque peu artificiel dans le numérateur comme sous-produit de cette approche ...
TCC
2
@PIntag: L'idée est bonne, mais l'utilisation de modulo est mauvaise. Prenez 13 et 3. Résultat attendu 5, mais ((13-1)%3)+1)donne 1 comme résultat. Prendre le bon type de division 1+(dividend - 1)/divisordonne le même résultat que la réponse pour un dividende et un diviseur positifs. De plus, aucun problème de débordement, aussi artificiel soit-il.
Lutz Lehmann
48
La réponse finale basée sur int
Pour les entiers signés:
int div = a / b;if(((a ^ b)>=0)&&(a % b !=0))
div++;
Pour les entiers non signés:
int div = a / b;if(a % b !=0)
div++;
Le raisonnement de cette réponse
La division entière ' /' est définie pour arrondir vers zéro (7.7.2 de la spécification), mais nous voulons arrondir. Cela signifie que les réponses négatives sont déjà arrondies correctement, mais les réponses positives doivent être ajustées.
Les réponses positives non nulles sont faciles à détecter, mais la réponse zéro est un peu plus délicate, car cela peut être l'arrondi d'une valeur négative ou l'arrondi d'une valeur positive.
Le pari le plus sûr est de détecter quand la réponse doit être positive en vérifiant que les signes des deux entiers sont identiques. Opérateur xor entier '^ ' sur les deux valeurs se traduira par un bit de signe 0 dans ce cas, ce qui signifie un résultat non négatif, de sorte que la vérification (a ^ b) >= 0détermine que le résultat aurait dû être positif avant l'arrondi. Notez également que pour les entiers non signés, chaque réponse est évidemment positive, donc cette vérification peut être omise.
La seule vérification qui reste est alors de savoir si des arrondis ont eu lieu, pour lesquels a % b != 0 fera le travail.
Leçons apprises
L'arithmétique (entier ou autre) n'est pas aussi simple qu'il y paraît. Penser soigneusement à tout moment.
De plus, bien que ma réponse finale ne soit peut-être pas aussi «simple» ou «évidente» ou peut-être même «rapide» que les réponses en virgule flottante, elle a une très forte qualité de rachat pour moi; J'ai maintenant raisonné à travers la réponse, donc je suis en fait certain que c'est correct (jusqu'à ce que quelqu'un plus intelligent me dise le contraire - regard furtif dans la direction d'Eric -).
Pour obtenir le même sentiment de certitude à propos de la réponse en virgule flottante, je devrais faire plus (et peut-être plus compliqué) en réfléchissant à l'existence de conditions dans lesquelles la précision en virgule flottante pourrait gêner, et si Math.Ceiling peut-être quelque chose d'indésirable sur les entrées «juste à droite».
Le chemin parcouru
Remplacer (notez que j'ai remplacé le second myInt1par myInt2, en supposant que c'était ce que vous vouliez dire):
(int)Math.Ceiling((double)myInt1 / myInt2)
avec:
(myInt1 -1+ myInt2)/ myInt2
La seule mise en garde étant que si vous myInt1 - 1 + myInt2débordez du type entier que vous utilisez, vous n'obtiendrez peut-être pas ce que vous attendez.
Raison pour laquelle c'est faux : -1000000 et 3999 devraient donner -250, cela donne -249
EDIT:
Considérant que cela a la même erreur que l'autre solution entière pour les myInt1valeurs négatives , il pourrait être plus facile de faire quelque chose comme:
int rem;int div =Math.DivRem(myInt1, myInt2,out rem);if(rem >0)
div++;
Cela devrait donner le résultat correct en divutilisant uniquement des opérations entières.
Raison pour laquelle c'est faux : -1 et -5 devraient donner 1, cela donne 0
EDIT (encore une fois, avec sensation):
L'opérateur de division arrondit vers zéro; pour les résultats négatifs, c'est tout à fait exact, donc seuls les résultats non négatifs doivent être ajustés. Considérant également que DivRemne fait que a /et a de %toute façon, sautons l'appel (et commençons par la comparaison facile pour éviter le calcul de modulo quand il n'est pas nécessaire):
int div = myInt1 / myInt2;if((div >=0)&&(myInt1 % myInt2 !=0))
div++;
Raison pour laquelle c'est faux : -1 et 5 devraient donner 0, cela donne 1
(Pour ma propre défense de la dernière tentative, je n'aurais jamais dû tenter une réponse motivée alors que mon esprit me disait que j'avais 2 heures de retard pour dormir)
Euh, quoi? Votre code s'appellerait myInt.DivideByAndRoundUp () et retournerait toujours 1 sauf pour une entrée de 0 qui provoquerait une exception ...
Ce code est évidemment erroné de deux manières. Tout d'abord, il y a une erreur mineure dans la syntaxe; vous avez besoin de plus de parenthèses. Mais plus important encore, il ne calcule pas le résultat souhaité. Par exemple, essayez de tester avec a = -1000000 et b = 3999. Le résultat de la division entière régulière est -250. La double division est -250.0625 ... Le comportement souhaité est d'arrondir. Il est clair que l'arrondi correct de -250,0625 est arrondi à -250, mais votre code arrondit à -249.
Eric Lippert
36
Je suis désolé de devoir continuer à le dire, mais votre code est TOUJOURS MAUVAIS Daniel. 1/2 devrait arrondir à 1, mais votre code l'arrondit à 0. Chaque fois que je trouve un bogue, vous le "corrigez" en introduisant un autre bogue. Mon conseil: arrêtez de faire ça. Quand quelqu'un trouve un bogue dans votre code, ne vous contentez pas de gifler un correctif sans réfléchir clairement à la cause du bogue en premier lieu. Utiliser de bonnes pratiques d'ingénierie; trouver la faille dans l'algorithme et la corriger. L'inconvénient des trois versions incorrectes de votre algorithme est que vous ne déterminez pas correctement quand l'arrondi a été "baissé".
Eric Lippert
8
Incroyable combien de bogues peuvent être dans ce petit morceau de code. Je n'ai jamais eu beaucoup de temps pour y penser - le résultat se manifeste dans les commentaires. (1) a * b> 0 serait correct s'il ne débordait pas. Il y a 9 combinaisons pour le signe de a et b - [-1, 0, +1] x [-1, 0, +1]. On peut ignorer le cas b == 0 en laissant les 6 cas [-1, 0, +1] x [-1, +1]. a / b arrondit vers zéro, c'est-à-dire arrondit pour des résultats négatifs et arrondit vers le bas pour des résultats positifs. Par conséquent, l'ajustement doit être effectué si a et b ont le même signe et ne sont pas tous les deux nuls.
Daniel Brückner
5
Cette réponse est probablement la pire chose que j'ai écrite sur SO ... et elle est maintenant liée par le blog d'Eric ... Eh bien, mon intention n'était pas de donner une solution lisible; J'étais vraiment en train de verrouiller pour un hack court et rapide. Et pour défendre à nouveau ma solution, j'ai eu la bonne idée la première fois, mais je n'ai pas pensé aux débordements. C'était évidemment mon erreur de poster le code sans l'écrire et le tester dans VisualStudio. Les "correctifs" sont encore pires - je ne savais pas que c'était un problème de débordement et pensais avoir fait une erreur logique. En conséquence, les premiers «correctifs» n'ont rien changé; Je viens d'inverser le
Daniel Brückner
10
logique et poussé le bug autour. Ici, j'ai fait les prochaines erreurs; comme Eric l'a déjà mentionné, je n'ai pas vraiment analysé le bug et j'ai juste fait la première chose qui semblait correcte. Et je n'ai toujours pas utilisé VisualStudio. D'accord, j'étais pressé et je n'ai pas passé plus de cinq minutes sur le "correctif", mais cela ne devrait pas être une excuse. Après avoir signalé le bug à plusieurs reprises, Eric a déclenché VisualStudio et trouvé le vrai problème. Le correctif utilisant Sign () rend la chose encore plus illisible et la transforme en code que vous ne voulez pas vraiment conserver. J'ai appris ma leçon et je ne sous-estimerai plus la difficulté
Daniel Brückner
-2
Certaines des réponses ci-dessus utilisent des flotteurs, c'est inefficace et vraiment pas nécessaire. Pour les entrées non signées, c'est une réponse efficace pour int1 / int2:
Ce n'est pas ce que le PO a demandé en premier lieu, n'ajoute pas vraiment aux autres réponses.
santamanno
-4
Le problème avec toutes les solutions ici est soit qu'elles ont besoin d'un plâtre, soit un problème numérique. Casting pour flotter ou doubler est toujours une option, mais nous pouvons faire mieux.
Lorsque vous utilisez le code de la réponse de @jerryjvl
int div = myInt1 / myInt2;if((div >=0)&&(myInt1 % myInt2 !=0))
div++;
il y a une erreur d'arrondi. 1/5 serait arrondi, car 1% 5! = 0. Mais c'est faux, car l'arrondi ne se produira que si vous remplacez le 1 par un 3, donc le résultat est 0,6. Nous devons trouver un moyen d'arrondir lorsque le calcul nous donne une valeur supérieure ou égale à 0,5. Le résultat de l'opérateur modulo dans l'exemple supérieur a une plage de 0 à myInt2-1. L'arrondi n'aura lieu que si le reste est supérieur à 50% du diviseur. Ainsi, le code ajusté ressemble à ceci:
int div = myInt1 / myInt2;if(myInt1 % myInt2 >= myInt2 /2)
div++;
Bien sûr, nous avons aussi un problème d'arrondi dans myInt2 / 2, mais ce résultat vous donnera une meilleure solution d'arrondi que les autres sur ce site.
"Nous devons trouver un moyen d'arrondir lorsque le calcul nous donne une valeur supérieure ou égale à 0,5" - vous avez manqué le point de cette question - ou toujours arrondir, c'est-à-dire que l'OP veut arrondir 0,001 à 1.
Réponses:
MISE À JOUR: Cette question a fait l'objet de mon blog en janvier 2013 . Merci pour la grande question!
Il est difficile d'obtenir une arithmétique entière correcte. Comme cela a été amplement démontré jusqu'à présent, au moment où vous essayez de faire un tour "intelligent", les chances sont bonnes que vous ayez fait une erreur. Et quand une faille est trouvée, changer le code pour corriger la faille sans se demander si la correction rompt autre chose n'est pas une bonne technique de résolution de problème. Jusqu'à présent, nous avons eu, je pense, cinq solutions arithmétiques entières incorrectes différentes à ce problème complètement pas particulièrement difficile.
La bonne façon d'aborder les problèmes arithmétiques entiers - c'est-à-dire la façon qui augmente la probabilité d'obtenir la bonne réponse la première fois - est d'aborder le problème avec soin, de le résoudre étape par étape et d'utiliser de bons principes d'ingénierie pour le faire. alors.
Commencez par lire les spécifications de ce que vous essayez de remplacer. La spécification pour la division entière indique clairement:
La division arrondit le résultat vers zéro
Le résultat est zéro ou positif lorsque les deux opérandes ont le même signe et zéro ou négatif lorsque les deux opérandes ont des signes opposés
Si l'opérande gauche est le plus petit entier représentable et l'opérande droit est –1, un débordement se produit. [...] il est défini par l'implémentation si [une ArithmeticException] est levée ou si le débordement n'est pas signalé, la valeur résultante étant celle de l'opérande de gauche.
Si la valeur de l'opérande de droite est zéro, une System.DivideByZeroException est levée.
Ce que nous voulons, c'est une fonction de division entière qui calcule le quotient mais arrondit toujours le résultat vers le haut , pas toujours vers zéro .
Écrivez donc une spécification pour cette fonction. Notre fonction
int DivRoundUp(int dividend, int divisor)
doit avoir un comportement défini pour chaque entrée possible. Ce comportement indéfini est profondément préoccupant, alors éliminons-le. Nous dirons que notre opération a cette spécification:opération lance si le diviseur est nul
opération lance si le dividende est int.minval et le diviseur est -1
s'il n'y a pas de reste - la division est 'paire' - alors la valeur de retour est le quotient intégral
Sinon, il renvoie le plus petit entier supérieur au quotient, c'est-à-dire qu'il arrondit toujours.
Nous avons maintenant une spécification, nous savons donc que nous pouvons proposer une conception testable . Supposons que nous ajoutions un critère de conception supplémentaire pour que le problème soit résolu uniquement avec une arithmétique entière, plutôt que de calculer le quotient comme un double, car la solution "double" a été explicitement rejetée dans l'énoncé du problème.
Alors, que devons-nous calculer? De toute évidence, pour répondre à nos spécifications tout en restant uniquement en arithmétique entière, nous devons connaître trois faits. Tout d'abord, quel était le quotient entier? Deuxièmement, la division était-elle exempte de reste? Et troisièmement, sinon, le quotient entier a-t-il été calculé en arrondissant vers le haut ou vers le bas?
Maintenant que nous avons une spécification et une conception, nous pouvons commencer à écrire du code.
Est-ce intelligent? Pas beau? Non. Court? Non. Correct selon la spécification? Je le crois, mais je ne l'ai pas entièrement testé. Cela semble assez bon cependant.
Nous sommes des professionnels ici; utiliser de bonnes pratiques d'ingénierie. Recherchez vos outils, spécifiez le comportement souhaité, examinez d'abord les cas d'erreur et écrivez le code pour souligner son exactitude évidente. Et lorsque vous trouvez un bogue, demandez-vous si votre algorithme est profondément défectueux pour commencer avant de commencer à échanger au hasard les directions des comparaisons et à casser des choses qui fonctionnent déjà.
la source
Jusqu'à présent, toutes les réponses semblent assez compliquées.
En C # et Java, pour un dividende et un diviseur positifs, il vous suffit de faire:
Source: Conversion de nombres, Roland Backhouse, 2001
la source
((13-1)%3)+1)
donne 1 comme résultat. Prendre le bon type de division1+(dividend - 1)/divisor
donne le même résultat que la réponse pour un dividende et un diviseur positifs. De plus, aucun problème de débordement, aussi artificiel soit-il.La réponse finale basée sur int
Pour les entiers signés:
Pour les entiers non signés:
Le raisonnement de cette réponse
La division entière '
/
' est définie pour arrondir vers zéro (7.7.2 de la spécification), mais nous voulons arrondir. Cela signifie que les réponses négatives sont déjà arrondies correctement, mais les réponses positives doivent être ajustées.Les réponses positives non nulles sont faciles à détecter, mais la réponse zéro est un peu plus délicate, car cela peut être l'arrondi d'une valeur négative ou l'arrondi d'une valeur positive.
Le pari le plus sûr est de détecter quand la réponse doit être positive en vérifiant que les signes des deux entiers sont identiques. Opérateur xor entier '
^
' sur les deux valeurs se traduira par un bit de signe 0 dans ce cas, ce qui signifie un résultat non négatif, de sorte que la vérification(a ^ b) >= 0
détermine que le résultat aurait dû être positif avant l'arrondi. Notez également que pour les entiers non signés, chaque réponse est évidemment positive, donc cette vérification peut être omise.La seule vérification qui reste est alors de savoir si des arrondis ont eu lieu, pour lesquels
a % b != 0
fera le travail.Leçons apprises
L'arithmétique (entier ou autre) n'est pas aussi simple qu'il y paraît. Penser soigneusement à tout moment.
De plus, bien que ma réponse finale ne soit peut-être pas aussi «simple» ou «évidente» ou peut-être même «rapide» que les réponses en virgule flottante, elle a une très forte qualité de rachat pour moi; J'ai maintenant raisonné à travers la réponse, donc je suis en fait certain que c'est correct (jusqu'à ce que quelqu'un plus intelligent me dise le contraire - regard furtif dans la direction d'Eric -).
Pour obtenir le même sentiment de certitude à propos de la réponse en virgule flottante, je devrais faire plus (et peut-être plus compliqué) en réfléchissant à l'existence de conditions dans lesquelles la précision en virgule flottante pourrait gêner, et si
Math.Ceiling
peut-être quelque chose d'indésirable sur les entrées «juste à droite».Le chemin parcouru
Remplacer (notez que j'ai remplacé le second
myInt1
parmyInt2
, en supposant que c'était ce que vous vouliez dire):avec:
La seule mise en garde étant que si vous
myInt1 - 1 + myInt2
débordez du type entier que vous utilisez, vous n'obtiendrez peut-être pas ce que vous attendez.Raison pour laquelle c'est faux : -1000000 et 3999 devraient donner -250, cela donne -249
EDIT:
Considérant que cela a la même erreur que l'autre solution entière pour les
myInt1
valeurs négatives , il pourrait être plus facile de faire quelque chose comme:Cela devrait donner le résultat correct en
div
utilisant uniquement des opérations entières.Raison pour laquelle c'est faux : -1 et -5 devraient donner 1, cela donne 0
EDIT (encore une fois, avec sensation):
L'opérateur de division arrondit vers zéro; pour les résultats négatifs, c'est tout à fait exact, donc seuls les résultats non négatifs doivent être ajustés. Considérant également que
DivRem
ne fait que a/
et a de%
toute façon, sautons l'appel (et commençons par la comparaison facile pour éviter le calcul de modulo quand il n'est pas nécessaire):Raison pour laquelle c'est faux : -1 et 5 devraient donner 0, cela donne 1
(Pour ma propre défense de la dernière tentative, je n'aurais jamais dû tenter une réponse motivée alors que mon esprit me disait que j'avais 2 heures de retard pour dormir)
la source
Occasion parfaite d'utiliser une méthode d'extension:
Cela rend votre code aussi lisible:
la source
Vous pourriez écrire un assistant.
la source
Vous pouvez utiliser quelque chose comme ce qui suit.
la source
Certaines des réponses ci-dessus utilisent des flotteurs, c'est inefficace et vraiment pas nécessaire. Pour les entrées non signées, c'est une réponse efficace pour int1 / int2:
Pour les entrées signées, ce ne sera pas correct
la source
Le problème avec toutes les solutions ici est soit qu'elles ont besoin d'un plâtre, soit un problème numérique. Casting pour flotter ou doubler est toujours une option, mais nous pouvons faire mieux.
Lorsque vous utilisez le code de la réponse de @jerryjvl
il y a une erreur d'arrondi. 1/5 serait arrondi, car 1% 5! = 0. Mais c'est faux, car l'arrondi ne se produira que si vous remplacez le 1 par un 3, donc le résultat est 0,6. Nous devons trouver un moyen d'arrondir lorsque le calcul nous donne une valeur supérieure ou égale à 0,5. Le résultat de l'opérateur modulo dans l'exemple supérieur a une plage de 0 à myInt2-1. L'arrondi n'aura lieu que si le reste est supérieur à 50% du diviseur. Ainsi, le code ajusté ressemble à ceci:
Bien sûr, nous avons aussi un problème d'arrondi dans myInt2 / 2, mais ce résultat vous donnera une meilleure solution d'arrondi que les autres sur ce site.
la source