Gibt es eine Modulfunktion (nicht Restfunktion)?

71

In Rust (wie in den meisten Programmiersprachen) führt der %Operator die Restoperation aus , nicht die Moduloperation . Diese Operationen haben unterschiedliche Ergebnisse für negative Zahlen :

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

Ich möchte jedoch den Modul.

Ich habe eine Problemumgehung gefunden ((a % b) + b) % b, aber ich möchte das Rad nicht neu erfinden, wenn es dafür bereits eine Funktion gibt!

Kapichu
quelle
1
Jeder Grund, den Begriff modulusanstelle von modulo(was häufiger AFAICS ist) zu verwenden.
ideasman42
1
Sie haben möglicherweise irgendwo studiert, wo der Begriff Modul verwendet wird, ohne zu wissen, dass sich verschiedene Institutionen im Wortschatz unterscheiden.
OliverUv
Für Zweierpotenzen können Sie etwas wie -21 & (4 - 1) tun, vorausgesetzt, es ist eine ganze Zahl.
AldaronLau

Antworten:

35

Gibt es in Rust eine Modulfunktion (nicht Rest!)?

Soweit ich das beurteilen kann, gibt es keine modulare Rechenfunktion .

Dies geschieht auch in C, wo häufig die von Ihnen erwähnte Problemumgehung verwendet wird : ((a % b) + b) % b.

In C, C ++, D, C #, F # und Java %ist tatsächlich der Rest. In Perl ist Python oder Ruby %der Modul.

Sprachentwickler gehen nicht immer den "richtigen mathematischen Weg", daher scheinen Computersprachen aus der strengen Sicht des Mathematikers seltsam zu sein. Die Sache ist, dass sowohl der Modul als auch der Rest für verschiedene Verwendungszwecke korrekt sind.

Der Modul ist mathematischer, wenn Sie möchten, während der Rest (in der C-Familie) mit der gemeinsamen Ganzzahldivision übereinstimmt, die Folgendes erfüllt : (a / b) * b + a % b = a; Dies wird aus dem alten Fortran übernommen. Damit% heißt der Rest besser, und ich nehme an, Rust stimmt mit C überein.

Sie sind nicht der Erste, der dies bemerkt:

JosEduSol
quelle
3
Ich als C / C ++ - Programmierer %
schäme
3
Ist das nicht eine Lücke in Rust?
Kapichu
1
Nun, wie Sie erwarten, ist dies nicht etwas, was Mathematiker genießen. Und ich würde nicht sagen, dass es eine Lücke ist, denn all diese Sprachfamilie %ist nur der Rest.
JosEduSol
2
Ich werde mit %dem Rest gehen, aber keine Unterstützung für Modul saugt ...
Kapichu
6
@JosEduSol Während ich dies schreibe, zeigt die obige Antwort (a % b) + beine Möglichkeit, den Modul zu berechnen, aber ich bin mir ziemlich sicher, was Sie schreiben wollten : ((a % b) + b) % b.
David J.
31

RFC 2196 fügt einige ganzzahlige Methoden hinzu, die sich auf die euklidische Division beziehen. Insbesondere suchen Sie nach der rem_euclidMethode ( Beispiellink füri32 ):

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

Diese Methode ist in rustc 1.38.0(veröffentlicht am 27.09.2019) und höher verfügbar .

Lukas Kalbertodt
quelle
2
Sie werden auch für nicht signierte Varianten implementiert, obwohl aus dieser Dokumentation nicht herausgefunden werden kann, was sie tun. Der div_euclid()Vollständigkeit halber möchte ich auch erwähnen . Dies sollte aber trotzdem die ausgewählte Antwort sein.
Am
10

Nein, Rust hat keinen eingebauten Modul, siehe diese Diskussion aus bestimmten Gründen an.

Hier ist ein Beispiel, das nützlich sein könnte:

///
/// 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 }
ideasman42
quelle
Wäre modulo_signed_ext_impl! { i8 i16 i32 i64 isize u8 u16 u32 u64 usize }besser?
Alexx Roche
-1

Aus den anderen Antworten, die ich konstruiert habe:

fn n_mod_m <T: std::ops::Rem<Output = T> + std::ops::Add<Output = T> + Copy>
  (n: T, m: T) -> T {
    ((n % m) + m) % m
}

assert_eq!(n_mod_m(-21, 4), 3);
Alexx Roche
quelle
1
Wenn Sie das für ganze Zahlen verwenden rem_euclidmöchten , wie ist es dann besser als das in Lukas Kalbertodts Antwort erwähnte integrierte Element ?
Mcarton
Ich finde diese explizite Funktion leichter mental zu analysieren als die undurchsichtige .rem_euclid ()
Alexx Roche