J'essaie de modifier un entier pour obtenir une position de tableau afin qu'il boucle autour. Faire i %
arrayLength
fonctionne bien pour les nombres positifs, mais pour les nombres négatifs, tout va mal.
4 % 3 == 1
3 % 3 == 0
2 % 3 == 2
1 % 3 == 1
0 % 3 == 0
-1 % 3 == -1
-2 % 3 == -2
-3 % 3 == 0
-4 % 3 == -1
donc j'ai besoin d'une implémentation de
int GetArrayIndex(int i, int arrayLength)
tel que
GetArrayIndex( 4, 3) == 1
GetArrayIndex( 3, 3) == 0
GetArrayIndex( 2, 3) == 2
GetArrayIndex( 1, 3) == 1
GetArrayIndex( 0, 3) == 0
GetArrayIndex(-1, 3) == 2
GetArrayIndex(-2, 3) == 1
GetArrayIndex(-3, 3) == 0
GetArrayIndex(-4, 3) == 2
Je l'ai déjà fait mais pour une raison quelconque, cela fait fondre mon cerveau aujourd'hui :(
Réponses:
J'utilise toujours ma propre
mod
fonction, définie commeBien sûr, si vous êtes dérangé d'avoir deux appels à l'opération de module, vous pouvez l'écrire comme
ou leurs variantes.
La raison pour laquelle cela fonctionne est que "x% m" est toujours dans la plage [-m + 1, m-1]. Donc, s'il est négatif, ajouter m le mettra dans la plage positive sans changer sa valeur modulo m.
la source
r = x%m
est-1
, après quoir+m
est1
. La boucle while n'est pas nécessaire. Le fait est que (comme je l'ai écrit dans la réponse),x%m
est toujours strictement supérieur à-m
, vous devez donc ajouterm
au plus une fois pour le rendre positif.r
poura
modulob
, alors il est tel que 0 ≤ r <| b |.Veuillez noter que l'opérateur% de C # et C ++ n'est en fait PAS un modulo, c'est le reste. La formule du modulo que vous souhaitez, dans votre cas, est:
Vous devez recoder ceci en C # (ou C ++) mais c'est ainsi que vous obtenez modulo et non un reste.
la source
-21 mod 4 is 3 because -21 + 4 x 6 is 3.
mais-21 divided by 4 gives -5
avec unremainder of -1
. Pour les valeurs positives, il n'y a pas de différence. Veuillez donc vous informer de ces différences. Et ne faites pas confiance à Wikipédia tout le temps :)%
reste?Implémentation sur
%
une seule ligne en utilisant une seule fois:la source
mod(-10, 6)
à la main, vous ajoutez ou soustrayez 6 répétitivement jusqu'à ce que la réponse soit dans la fourchette[0, 6)
. Cette notation signifie «inclusif à gauche et exclusif à droite». Dans notre cas, nous ajoutons 6 deux fois, ce qui donne 2. Le code est assez simple, et il est facile de voir qu'il est juste: d'abord, il fait l'équivalent d'ajouter / soustrairen
comme ci-dessus, sauf qu'il arrête unn
court, s'il s'approche de le côté négatif. Dans ce cas, nous le réparons. Là: commentaires :)%
pourrait être une bonne idée. Consultez le tableau Combien coûtent les choses en code managé dans l'article Rédaction de code managé plus rapide: Know What Things Cost . L'utilisation%
est tout aussi coûteuse que celleint div
indiquée dans le tableau: environ 36 fois plus cher que d'ajouter ou de soustraire, et environ 13 fois plus cher que de multiplier. Bien sûr, pas de problème à moins que ce ne soit au cœur de ce que fait votre code.%
plus cher qu'un test et un saut, surtout s'il ne peut pas être facilement prédit?La réponse de ShreevatsaR ne fonctionnera pas dans tous les cas, même si vous ajoutez "si (m <0) m = -m;", si vous tenez compte des dividendes / diviseurs négatifs.
Par exemple, -12 mod -10 sera 8 et il devrait être -2.
L'implémentation suivante fonctionnera pour les dividendes / diviseurs positifs et négatifs et est conforme à d'autres implémentations (à savoir, Java, Python, Ruby, Scala, Scheme, Javascript et Google's Calculator):
Suite de tests utilisant xUnit:
la source
mod
fonction est généralement appelée avec un module positif (notez la variablearrayLength
dans la question d'origine à laquelle on répond ici, qui n'est probablement jamais négative), donc la fonction n'a pas vraiment besoin d'être conçue pour fonctionner pour un module négatif. (C'est pourquoi je mentionne le traitement du module négatif dans un commentaire sur ma réponse, pas dans la réponse elle-même.) (Suite ...)r = a - b floor(a/b)
est toujours positif). Même parmi les systèmes informatiques, Pascal et Maple par exemple, le définissent comme toujours positif.Ajout d'un peu de compréhension.
Par définition euclidienne, le résultat du mod doit être toujours positif.
Ex:
Production:
la source
-1
?the positive remainder is always chosen
mais les langages de programmation choisissent en fonction de la langue et des signes de a et / ou n. [5] Le Pascal standard et Algol68 donnent un reste positif (ou 0) même pour les diviseurs négatifs, et certains langages de programmation, tels que C90, laissent le soin à l'implémentation lorsque n ou a est négatif. »Comparaison de deux réponses prédominantes
et
Personne n'a en fait mentionné le fait que le premier peut lancer un
OverflowException
certain temps tandis que le second ne le fera pas. Pire encore, avec un contexte non coché par défaut, la première réponse peut renvoyer la mauvaise réponse (voirmod(int.MaxValue - 1, int.MaxValue)
par exemple). La deuxième réponse semble donc non seulement plus rapide, mais aussi plus correcte.la source
Ajoutez simplement votre module (arrayLength) au résultat négatif de% et tout ira bien.
la source
Pour les développeurs plus sensibles aux performances
Une petite comparaison des performances
En ce qui concerne le coût des performances du casting, jetez un œil ici
la source
-3 % 10
devrait être de -3 ou 7. Puisqu'un résultat non négatif est souhaité, 7 serait la réponse. Votre implémentation renvoie 3. Vous devez modifier les deux paramètresuint
et supprimer la distribution.n
est une puissance de deux, auquel cas vous pouvez simplement utiliser un and ((uint)k & (n - 1)
) logique à la place, si le compilateur ne le fait pas déjà pour vous (les compilateurs sont souvent assez intelligents pour comprendre cela).J'aime le truc présenté par Peter N Lewis sur ce fil : «Si n a une plage limitée, alors vous pouvez obtenir le résultat que vous voulez simplement en ajoutant un multiple constant connu de [le diviseur] qui est supérieur à la valeur absolue du le minimum."
Donc si j'ai une valeur d qui est en degrés et que je veux prendre
et je veux éviter les problèmes si d est négatif, alors je fais simplement ceci:
Cela suppose que bien que d puisse être négatif, on sait qu'il ne sera jamais plus négatif que -720.
la source
%
.Vous vous attendez à un comportement contraire au comportement documenté de l'opérateur% dans c # - peut-être parce que vous vous attendez à ce qu'il fonctionne de manière à fonctionner dans un autre langage auquel vous êtes plus habitué. La documentation sur les états c # (c'est moi qui souligne):
La valeur souhaitée peut être calculée avec une étape supplémentaire:
la source
Une implémentation en ligne unique de la réponse de dcastro (la plus compatible avec les autres langages):
Si vous souhaitez conserver l'utilisation d'
%
opérateur (vous ne pouvez pas surcharger les opérateurs natifs en C #):Cas d'utilisation, les deux fonctionnent:
la source
Toutes les réponses ici fonctionnent très bien si votre diviseur est positif, mais ce n'est pas tout à fait complet. Voici mon implémentation qui retourne toujours sur une plage de
[0, b)
, telle que le signe de la sortie est le même que le signe du diviseur, ce qui permet des diviseurs négatifs comme point final de la plage de sortie.PosMod(5, 3)
retourne2
PosMod(-5, 3)
retourne1
PosMod(5, -3)
retourne-1
PosMod(-5, -3)
retourne-2
(où
real_t
peut être n'importe quel type de nombre)la source