Ich versuche, eine Ganzzahl zu modifizieren, um eine Array-Position zu erhalten, damit sie sich um eine Schleife dreht. Das i %
arrayLength
funktioniert gut für positive Zahlen, aber für negative Zahlen geht alles schief.
4 % 3 == 1
3 % 3 == 0
2 % 3 == 2
1 % 3 == 1
0 % 3 == 0
-1 % 3 == -1
-2 % 3 == -2
-3 % 3 == 0
-4 % 3 == -1
Also brauche ich eine Implementierung von
int GetArrayIndex(int i, int arrayLength)
so dass
GetArrayIndex( 4, 3) == 1
GetArrayIndex( 3, 3) == 0
GetArrayIndex( 2, 3) == 2
GetArrayIndex( 1, 3) == 1
GetArrayIndex( 0, 3) == 0
GetArrayIndex(-1, 3) == 2
GetArrayIndex(-2, 3) == 1
GetArrayIndex(-3, 3) == 0
GetArrayIndex(-4, 3) == 2
Ich habe das schon einmal gemacht, aber aus irgendeinem Grund schmilzt es heute mein Gehirn :(
Antworten:
Ich benutze immer meine eigene
mod
Funktion, definiert alsWenn Sie sich die Mühe machen, zwei Aufrufe der Moduloperation zu haben, können Sie diese natürlich als schreiben
oder Varianten davon.
Der Grund dafür ist, dass "x% m" immer im Bereich [-m + 1, m-1] liegt. Wenn es also überhaupt negativ ist, wird es durch Hinzufügen von m in den positiven Bereich gebracht, ohne seinen Wert modulo m zu ändern.
quelle
r = x%m
ist-1
, danachr+m
ist1
. Die while-Schleife wird nicht benötigt. Der Punkt ist, dass (wie ich in der Antwort geschrieben habe)x%m
immer streng größer ist als-m
, also müssen Siem
höchstens einmal hinzufügen , um es positiv zu machen.r
füra
Modulo auswählenb
, ist dies so, dass 0 ≤ r <| b |.Bitte beachten Sie, dass der% -Operator von C # und C ++ eigentlich KEIN Modulo ist, sondern der Rest. Die Formel für Modulo, die Sie in Ihrem Fall möchten, lautet:
Sie müssen dies in C # (oder C ++) neu codieren, aber auf diese Weise erhalten Sie Modulo und keinen Rest.
quelle
-21 mod 4 is 3 because -21 + 4 x 6 is 3.
Aber-21 divided by 4 gives -5
mit aremainder of -1
. Bei positiven Werten gibt es keinen Unterschied. Bitte informieren Sie sich über diese Unterschiede. Und vertraue Wikipedia nicht die ganze Zeit :)%
Rest gemacht?Einzeilige Implementierung mit
%
nur einmal:quelle
mod(-10, 6)
von Hand zu finden , addieren oder subtrahieren Sie 6 wiederholt, bis die Antwort im Bereich liegt[0, 6)
. Diese Notation bedeutet "links inklusive und rechts exklusiv". In unserem Fall addieren wir 6 zweimal, was 2 ergibt. Der Code ist recht einfach und es ist leicht zu erkennen, dass er richtig ist: Erstens entspricht er dem Addieren / Subtrahierenn
wie oben, außer dass er einenn
Kurzschluss stoppt , wenn er sich nähert die negative Seite. In diesem Fall beheben wir es. Dort: Kommentare :)%
eine gute Idee sein könnte. Weitere Informationen finden Sie in der Tabelle Welche Kosten in verwaltetem Code im Artikel Schreiben von schneller verwaltetem Code: Wissen, was Dinge kosten . Die Verwendung%
ist ähnlich teuer wieint div
in der Tabelle aufgeführt: etwa 36-mal teurer als das Addieren oder Subtrahieren und etwa 13-mal teurer als das Multiplizieren. Natürlich keine große Sache, es sei denn, dies ist der Kern dessen, was Ihr Code tut.%
teurer als ein Test und ein Sprung, besonders wenn es nicht leicht vorherzusagen ist?Die Antwort von ShreevatsaR funktioniert nicht in allen Fällen, selbst wenn Sie "if (m <0) m = -m;" hinzufügen, wenn Sie negative Dividenden / Teiler berücksichtigen.
Zum Beispiel ist -12 mod -10 8 und sollte -2 sein.
Die folgende Implementierung funktioniert sowohl für positive als auch für negative Dividenden / Teiler und entspricht anderen Implementierungen (nämlich Java, Python, Ruby, Scala, Schema, Javascript und Googles Rechner):
Testsuite mit xUnit:
quelle
mod
Funktion normalerweise mit positivem Modul aufgerufen (beachten Sie die VariablearrayLength
in der ursprünglichen Frage, die hier beantwortet wird, die vermutlich nie negativ ist), sodass die Funktion nicht wirklich für den negativen Modul ausgeführt werden muss. (Deshalb erwähne ich die Behandlung des negativen Moduls in einem Kommentar zu meiner Antwort, nicht in der Antwort selbst.) (Fortsetzung ...)r = a - b floor(a/b)
ist es immer positiv). Selbst unter Computersystemen definieren Pascal und Maple dies als immer positiv.Verständnis hinzufügen.
Nach euklidischer Definition muss das Mod-Ergebnis immer positiv sein.
Ex:
Ausgabe:
quelle
-1
?the positive remainder is always chosen
aber Programmiersprachen wählen in Abhängigkeit von der Sprache und den Vorzeichen von a und / oder n. [5] Standard Pascal und Algol68 geben selbst für negative Teiler einen positiven Rest (oder 0), und einige Programmiersprachen wie C90 überlassen es der Implementierung, wenn entweder n oder a negativ ist. "Addieren Sie einfach Ihren Modul (arrayLength) zum negativen Ergebnis von% und Sie werden in Ordnung sein.
quelle
Für leistungsorientiertere Entwickler
Ein kleiner Leistungsvergleich
Informationen zu den Leistungskosten von Cast to Uint finden Sie hier
quelle
-3 % 10
entweder -3 oder 7 sein sollte. Da ein nicht negatives Ergebnis gewünscht wird, wäre 7 die Antwort. Ihre Implementierung gibt 3 zurück. Sie sollten beide Parameter ändernuint
und die Umwandlung entfernen.n
es sich um eine Zweierpotenz handelt. In diesem Fall können Sie einfach ein logisches und ((uint)k & (n - 1)
) verwenden, wenn der Compiler dies nicht bereits für Sie erledigt (Compiler sind oft klug genug, um dies herauszufinden).Vergleich zweier vorherrschender Antworten
und
Niemand erwähnte tatsächlich die Tatsache, dass der erste eine
OverflowException
Weile werfen kann, der zweite nicht. Schlimmer noch, wenn der Standardkontext nicht aktiviert ist, gibt die erste Antwort möglicherweise die falsche Antwort zurück (siehemod(int.MaxValue - 1, int.MaxValue)
zum Beispiel). Die zweite Antwort scheint also nicht nur schneller, sondern auch korrekter zu sein.quelle
Ich mag den Trick, den Peter N Lewis in diesem Thread vorgestellt hat : "Wenn n einen begrenzten Bereich hat, können Sie das gewünschte Ergebnis erzielen, indem Sie einfach ein bekanntes konstantes Vielfaches von [dem Divisor] hinzufügen, das größer ist als der absolute Wert von Minimum."
Wenn ich also einen Wert d habe , der in Grad angegeben ist und den ich nehmen möchte
und ich möchte die Probleme vermeiden, wenn d negativ ist, dann mache ich stattdessen einfach Folgendes:
Dies setzt voraus, dass d zwar negativ sein kann, es jedoch bekannt ist, dass es niemals negativer als -720 sein wird.
quelle
%
.Sie erwarten ein Verhalten, das dem dokumentierten Verhalten des Operators% in c # widerspricht - möglicherweise, weil Sie erwarten, dass es so funktioniert, wie es in einer anderen Sprache funktioniert, an die Sie eher gewöhnt sind. Die Dokumentation zu c # besagt (Schwerpunkt Mine):
Der gewünschte Wert kann mit einem zusätzlichen Schritt berechnet werden:
quelle
Alle Antworten hier funktionieren hervorragend, wenn Ihr Divisor positiv ist, aber nicht ganz vollständig. Hier ist meine Implementierung, die immer in einem Bereich von zurückgibt
[0, b)
, sodass das Vorzeichen der Ausgabe mit dem Vorzeichen des Divisors übereinstimmt und negative Divisoren als Endpunkt für den Ausgabebereich berücksichtigt werden.PosMod(5, 3)
return2
PosMod(-5, 3)
return1
PosMod(5, -3)
return-1
PosMod(-5, -3)
return-2
(wo
real_t
kann ein beliebiger Nummerntyp sein)quelle
Eine einzeilige Implementierung der Antwort von dcastro (die mit anderen Sprachen am kompatibelsten ist):
Wenn Sie die Verwendung des
%
Operators beibehalten möchten (Sie können native Operatoren in C # nicht überladen):Anwendungsfall, beide Werke:
quelle