web-dev-qa-db-fra.com

Comportement étrange de mod Objective-C pour les nombres négatifs

J'ai donc pensé que les nombres négatifs, lorsqu'ils sont modifiés, devraient être placés dans un espace positif ... Je ne peux pas que cela se produise dans objective-c

J'attends ceci:

-1 % 3 = 2
 0 % 3 = 0
 1 % 3 = 1
 2 % 3 = 2

Mais obtenez ceci

-1 % 3 = -1
 0 % 3 = 0
 1 % 3 = 1
 2 % 3 = 2

Pourquoi est-ce et y at-il une solution de contournement?

42
coneybeare
result = n % 3;
if( result < 0 ) result += 3;

N'effectuez pas d'opérations supplémentaires comme suggéré dans les autres réponses. Ils sont très coûteux et inutiles.

53
UncleO

En C et en Objective-C, les opérateurs de division et de module effectuent une troncature vers zéro. a / b est floor(a / b) si a / b > 0, sinon c'est ceiling(a / b) si a / b < 0. Il est toujours vrai que a == (a / b) * b + (a % b), à moins bien sûr que b soit égal à 0. En conséquence, positive % positive == positive, positive % negative == positive, negative % positive == negative et negative % negative == negative (vous pouvez élaborer la logique pour les 4 cas, bien que ce soit un peu délicat).

14
Adam Rosenfield

Si n a une plage limitée, vous pouvez obtenir le résultat souhaité en ajoutant simplement une constante multiple de 3 supérieure à la valeur absolue du minimum.

Par exemple, si n est limité à -1000..2000, vous pouvez utiliser l'expression:

result = (n+1002) % 3;

Assurez-vous que le maximum plus votre constante ne débordera pas une fois sommé.

8
Peter N Lewis

Nous avons un problème de langue:

 math-er-dit: je prends ce numéro plus ce numéro mod autre-numéro 
 code-er-entend: J'ajoute deux nombres et divise ensuite le résultat par autre-numéro 
 code-er-dit : qu'en est-il des nombres négatifs? 
 math-er-dit: QUOI? les champs mod autre-nombre n'ont pas de concept de nombres négatifs? 
 code-er-dit: champ quoi? ...
  • la personne en maths dans cette conversation parle de faire les maths avec une droite numérique. Si vous soustrayez le bas, vous vous dirigez vers le haut.
  • la personne en charge du code parle d'un opérateur qui calcule le reste. 

Dans ce cas, vous voulez l'opérateur mod du mathématicien et disposez du reste des fonctions. vous pouvez convertir l'opérateur restant en opérateur mod du mathématicien en vérifiant si vous êtes tombé du fond à chaque fois que vous effectuez une soustraction. 

7
Arthur Ulfeldt

Je me serais attendu à un nombre positif également, mais je l’ai trouvé dans ISO/IEC 14882: 2003: Langages de programmation - C++, 5.6.4 (trouvé dans l’article de Wikipedia sur l’opération de module ):

L'opérateur% binaire renvoie le reste de la division de la première expression par la seconde. .... Si les deux opérandes sont non négatifs, le reste est non négatif. sinon, le signe du reste est défini par l'implémentation

4
e.James

Si tel est le comportement et que vous savez que ce sera le cas, utilisez m % n = r pour r = n + r Si vous ne savez pas ce qui se passera ici, utilisez alors r = r % n.

Edit: Pour résumer, utilisez r = ( n + ( m % n ) ) % n

4
maxwellb

JavaScript le fait aussi. Je me suis fait prendre à deux reprises. Pensez-y comme une réflexion autour de zéro plutôt que comme une continuation.

1
Nosredna

La réponse de UncleO est probablement plus robuste, mais si vous voulez le faire sur une seule ligne et que vous êtes certain que la valeur négative ne sera pas plus négative qu'une seule itération du mod (par exemple si vous êtes ne soustrayant jamais au maximum la valeur mod à tout moment), vous pouvez le simplifier en une seule expression:

int result = (n + 3) % 3;

De toute façon, puisque vous faites le mod, ajouter 3 à la valeur initiale n'a pas d'effet sauf si n est négatif (mais pas inférieur à -3), auquel cas le résultat est le module positif attendu.

1
devios1

Pourquoi: parce que c'est la manière dont l'opérateur mod est spécifié dans le standard C (rappelez-vous qu'Objective-C est une extension de C). Cela déroute la plupart des gens que je connais (comme moi) parce que c'est surprenant et qu'il faut s'en souvenir.

En ce qui concerne une solution de contournement: j'utiliserais celui d'oncleo.

1
Tobias

Non seulement le script Java, mais presque toutes les langues donnent la mauvaise réponse ' Ce qui est dit, c’est correct, quand on est en mode, il faut obtenir le reste. nombre entier positif ....

Si vous vérifiez la ligne de numéro, vous pouvez comprendre que

Je suis également confronté au même problème dans VB et cela m'a obligé à ajouter de force un contrôle supplémentaire comme Si le résultat est négatif, nous devons ajouter le diviseur au résultat

0
Anish Chandran

Il y a deux choix pour le reste et le signe dépend de la langue. ANSI C choisit le signe du dividende. Je soupçonne que c'est la raison pour laquelle vous voyez également Objective-C Voir aussi l’entrée wikipedia .

0
user122376