Gibt es einen Ausdruck, der Modulo verwendet, um einen Rückwärtsumlauf (umgekehrter Überlauf) durchzuführen?

Gibt es einen Ausdruck, der Modulo verwendet, um einen Rückwärtsumlauf (umgekehrter Überlauf) durchzuführen?

Ihr Ausdruck sollte ((x-1) + k) % k sein . Dadurch wird x=0 ordnungsgemäß auf 11 umgebrochen. Wenn Sie um mehr als 1 zurückgehen möchten, müssen Sie im Allgemeinen sicherstellen, dass Sie so viel hinzufügen, dass der erste Operand der Modulo-Operation>=0 ist.

Hier ist eine Implementierung in C++:

int wrapAround(int v, int delta, int minval, int maxval)
{
  const int mod = maxval + 1 - minval;
  if (delta >= 0) {return  (v + delta                - minval) % mod + minval;}
  else            {return ((v + delta) - delta * mod - minval) % mod + minval;}
}

Dies ermöglicht auch die Verwendung von Monaten, die von 0 bis 11 oder von 1 bis 12 beschriftet sind, indem Sie min_val einstellen und max_val entsprechend.

Da diese Antwort so sehr geschätzt wird, hier eine verbesserte Version ohne Verzweigung, die auch den Fall behandelt, in dem der Anfangswert v ist kleiner als minval . Ich behalte das andere Beispiel, weil es einfacher zu verstehen ist:

int wrapAround(int v, int delta, int minval, int maxval)
{
  const int mod = maxval + 1 - minval;
  v += delta - minval;
  v += (1 - v / mod) * mod;
  return v % mod + minval;
}

Das einzige verbleibende Problem ist, wenn minval ist größer als maxval . Fühlen Sie sich frei, eine Behauptung hinzuzufügen, wenn Sie sie brauchen.


k %k wird immer 0 sein. Ich bin mir nicht 100 % sicher, was Sie versuchen, aber es scheint, dass Sie möchten, dass der letzte Monat zwischen 0 und 11 einschließlich geklemmt wird.

(this_month + 11) % 12

Sollte reichen.


Die allgemeine Lösung besteht darin, eine Funktion zu schreiben, die den gewünschten Wert berechnet:

//Returns floor(a/n) (with the division done exactly).
//Let ÷ be mathematical division, and / be C++ division.
//We know
//    a÷b = a/b + f (f is the remainder, not all 
//                   divisions have exact Integral results)
//and
//    (a/b)*b + a%b == a (from the standard).
//Together, these imply (through algebraic manipulation):
//    sign(f) == sign(a%b)*sign(b)
//We want the remainder (f) to always be >=0 (by definition of flooredDivision),
//so when sign(f) < 0, we subtract 1 from a/n to make f > 0.
template<typename Integral>
Integral flooredDivision(Integral a, Integral n) {
    Integral q(a/n);
    if ((a%n < 0 && n > 0) || (a%n > 0 && n < 0)) --q;
    return q;
}

//flooredModulo: Modulo function for use in the construction
//looping topologies. The result will always be between 0 and the
//denominator, and will loop in a natural fashion (rather than swapping
//the looping direction over the zero point (as in C++11),
//or being unspecified (as in earlier C++)).
//Returns x such that:
//
//Real a = Real(numerator)
//Real n = Real(denominator)
//Real r = a - n*floor(n/d)
//x = Integral(r)
template<typename Integral>
Integral flooredModulo(Integral a, Integral n) {
    return a - n * flooredDivision(a, n);
}