Parfois on cherche à faire un modulo entre deux valeurs personnalisées. C’est mon cas pour décoder des messages encodés avec un chiffre Vigenere, car nos permutations de lettres ont pour valeur minimum « A », soit « 1 », et non « 0 ».
25 % 26; // ✔ 25
26 % 26; // ⨯ 0 instead of 26
27 % 26; // ✔ 1
0 % 26; // ⨯ 0 instead of 26
Le premier problème des modulos en JavaScript est la possibilité d’obtenir des résultats négatifs, ce sujet a été résolu dans un article précédent et nous utiliserons le solution ici.
/**
* Returns a value between a minimum and a maximum, using modulo to handle the overflows
*
* @param {number} number
* @param {number} min - the minimum value
* @param {number} max - the maximum value
* @return {number} clamped value
*/
function moduloClamp(number, min, max) {
return positiveModulo(number - min, max + 1 - min) + min;
}
// See https://tzi.fr/js/modulos-positifs
function positiveModulo(number, divisor) {
return ((number % divisor) + divisor) % divisor;
}
L’astuce ici est d’enlever la valeur minimum avant de réaliser son modulo puis de la rajouter au résultat obtenu.
Il y a aussi une petite finesse sur la calcul du diviseur qui doit être max + 1 - min
.
moduloClamp(25, 1, 26); // ✔ 25
moduloClamp(26, 1, 26); // ✔ 26
moduloClamp(27, 1, 26); // ✔ 1
moduloClamp(0, 1, 26); // ✔ 26
moduloClamp(29, 30, 35); // ✔ 35
moduloClamp(36, 30, 35); // ✔ 30
console.log(0 % 26);
console.log(positiveModulo(0, 26));
console.log(moduloClamp(0, 1, 26));