web-dev-qa-db-fra.com

Existe-t-il une fonction / opération de module (pas de reste)?

Dans Rust (comme la plupart des langages de programmation), le % L'opérateur effectue l'opération reste, pas l'opération module. Ces les opérations ont des résultats différents pour les nombres négatifs :

-21 modulus 4 => 3
-21 remainder 4 => -1
println!("{}", -21 % 4); // -1

Cependant, je veux le module.

J'ai trouvé une solution de contournement ((a % b) + b) % b, mais je ne veux pas réinventer la roue s'il y a déjà une fonction pour ça!

40
Kapichu

Existe-t-il une fonction/opération de module (pas de reste!) Dans Rust?

Pour autant que je sache, il n'y a pas de fonction arithmétique modulaire .

Cela se produit également en C, où il est courant d'utiliser la solution de contournement que vous avez mentionnée: (a % b) + b.

En C, C++, D, C #, F # et Java, % est en fait le reste. En Perl, Python ou Ruby, % est le module.

Les développeurs de langage ne suivent pas toujours la "bonne voie mathématique", donc les langages informatiques peuvent sembler étranges du point de vue strict des mathématiciens. Le fait est que le module et le reste sont corrects pour différentes utilisations.

Le module est plus mathématique si vous le souhaitez, tandis que le reste (dans la famille C) est cohérent avec une division entière commune satisfaisant: (a / b) * b + a % b = a; c'est adopté du vieux Fortran. Donc % est mieux appelé le reste, et je suppose que Rust est compatible avec C.

Vous n'êtes pas le premier à noter ceci:

20
JosEduSol

Non, Rust n'a pas de module intégré, voir cette discussion pour quelques raisons).

Voici un exemple qui pourrait être utile:

///
/// Modulo that handles negative numbers, works the same as Python's `%`.
///
/// eg: `(a + b).modulo(c)`
///
pub trait ModuloSignedExt {
    fn modulo(&self, n: Self) -> Self;
}
macro_rules! modulo_signed_ext_impl {
    ($($t:ty)*) => ($(
        impl ModuloSignedExt for $t {
            #[inline]
            fn modulo(&self, n: Self) -> Self {
                (self % n + n) % n
            }
        }
    )*)
}
modulo_signed_ext_impl! { i8 i16 i32 i64 }
6
ideasman42

RFC 2196 ajoute quelques méthodes entières liées à la division euclidienne. Plus précisément, le rem_euclid méthode ( exemple de lien pour i32 ) est ce que vous recherchez:

println!("{}", -1i32 % 4);                // -1
println!("{}", (-21i32).rem_euclid(4));   // 3

Cette méthode est disponible en rustc 1.38.0 (publié le 27/09/2019) et au-dessus.

0
Lukas Kalbertodt