Quel est le moyen efficace d’obtenir le moins de résidus modulo n non négatif dans C?

Existe-t-il un moyen efficace d’obtenir le moins possible de résidus modulo n, où n est positif, en C?

C’est assez facile si le nombre est non négatif, alors c’est juste un% n (où a est l’entier non négatif).

Cependant, lorsque a est négatif, il apparaît que le comportement, en C89, est défini par la mise en œuvre (merci kennyTM). Ie -2% 11 = -2 ou 9.

De plus, en C99, le comportement est défini comme étant le problème: -2% 11 = -2.

En général (c.-à-d. n % m lorsque m n’est pas constant et que la plage de n n’est pas contrainte), vous ne pouvez probablement pas faire mieux que d’habitude

 res = ((n % m) + m) % m 

Il peut être intéressant de comparer cela à ce qui suit sur votre plate-forme. une twig pourrait gagner contre le modulo supplémentaire:

 res = n % m; if (res < 0) res += m; 

Vous pouvez simplement vérifier si le résultat est négatif et agir en conséquence:

 int mod(int n, int m) { int r = n % m; if (r < 0) return r + m; else return r; } 

Ou, sans if-then-else et comme une expression unique:

 r = ((n % m) + m) % m; 

Que diriez-vous

 if (a > 0) return a % n; if (a < 0) { r = n - (-a % n); if (r == n) return 0; return r; } 

Si a <0, alors r = -a % n est une valeur dans [0, n) telle que k * n + r = -a pour un entier k. Alors n - r est une valeur dans (0, n], et puisque -r = a + k * n, nous avons n - r = a + (k + 1) * n, ou a = (n - r) + (-k - 1) * N. Cela vous permet de voir que n - r est le module de a, et comme il est dans (0, n], il est non négatif.

Enfin, vous voulez que le résultat se situe dans la plage [0, n), pas dans (0, n]. Pour nous en assurer, nous vérifions si r est n, et si tel est le cas, nous renvoyons 0. (Ce qui est bien sûr modulus- n-équivalent à n)

Peu de processeurs implémentent le rest dans le matériel, il est plutôt synthétisé à partir d’une division et d’une multiplication. Donc, ce n’est pas vraiment une réimplémentation lourde du sharepoint vue de la machine:

 int qm = n / m * m; // a positive or negative multiple of m, rounded up or down if ( qm <= n ) return n - qm; // usual definition of % else return n - qm + m; // most common definition of -%, with adjustment 

La micro-optimisation du conditionnel + peut également être bénéfique. Cela pourrait être plus rapide ou plus lent sur votre machine, mais cela fonctionnera:

 int rem = n - n / m * m; return rem + m & -( rem < 0 ); 

Coût total: un modulo régulier plus un décalage à droite (pour générer -(rem<0) ), un bit et, et un ajout.