webentwicklung-frage-antwort-db.com.de

Ungewöhnliches Objective-C-Mod-Verhalten für negative Zahlen

Also dachte ich, dass negative Zahlen, wenn mod'ed, in einen positiven Raum gesetzt werden sollten ... ich kann das nicht in Ziel-c bekommen

Ich erwarte das:

-1 % 3 = 2
 0 % 3 = 0
 1 % 3 = 1
 2 % 3 = 2

Aber krieg das

-1 % 3 = -1
 0 % 3 = 0
 1 % 3 = 1
 2 % 3 = 2

Warum ist das so und gibt es eine Problemumgehung?

42
coneybeare
result = n % 3;
if( result < 0 ) result += 3;

Führen Sie keine zusätzlichen Mod-Operationen aus, wie in den anderen Antworten vorgeschlagen. Sie sind sehr teuer und unnötig.

53
UncleO

In C und Objective-C führen die Divisions- und Modulusoperatoren eine Verkürzung gegen Null durch. a / b ist floor(a / b) wenn a / b > 0, ansonsten ist ceiling(a / b) wenn a / b < 0. Es ist immer der Fall, dass a == (a / b) * b + (a % b), es sei denn natürlich b, 0 ist. Infolgedessen positive % positive == positive, positive % negative == positive, negative % positive == negative und negative % negative == negative (Sie können die Logik für alle 4 Fälle ermitteln, obwohl dies ein bisschen schwierig ist).

14
Adam Rosenfield

Wenn n einen begrenzten Bereich hat, können Sie das gewünschte Ergebnis erhalten, indem Sie einfach ein bekanntes konstantes Vielfaches von 3 hinzufügen, das größer als der absolute Wert des Minimums ist.

Wenn n beispielsweise auf -1000..2000 beschränkt ist, können Sie den Ausdruck verwenden:

result = (n+1002) % 3;

Stellen Sie sicher, dass das Maximum plus Ihre Konstante beim Summieren nicht überläuft.

8
Peter N Lewis

Wir haben ein Sprachproblem:

 math-er-sagt: Ich nehme diese Zahl plus diese Zahl mod andere Nummer 
 Code-er-hört: Ich addiere zwei Zahlen und teile das Ergebnis durch andere Nummer 
 Code-er-sagt : Was ist mit negativen Zahlen? 
 math-er-sagt: WAS? Felder Mod andere Nummer haben kein Konzept von negativen Zahlen? 
 Code-er-sagt: Feld was? ...
  • die mathematische Person in diesen Gesprächen spricht davon, dass Mathematik in einer kreisförmigen Zahlenzeile ausgeführt wird. Wenn Sie von der Unterseite abziehen, wickeln Sie sie nach oben um.
  • Die Code-Person spricht von einem Operator, der den Rest berechnet. 

In diesem Fall möchten Sie den Mod-Operator des Mathematikers und die Restfunktion zur Verfügung haben. Sie können den Restoperator in den Mod-Operator des Mathematikers umwandeln, indem Sie prüfen, ob Sie bei jeder Subtraktion vom Boden gefallen sind. 

7
Arthur Ulfeldt

Ich hätte auch eine positive Zahl erwartet, aber ich fand diese aus ISO/IEC 14882: 2003: Programmiersprachen - C++, 5.6.4 (gefunden in der Wikipedia-Artikel über die Moduloperation ):

Der binäre Operator% ergibt den Rest aus der Division des ersten Ausdrucks durch den zweiten. .... Wenn beide Operanden nicht negativ sind, ist der Rest nicht negativ. Wenn nicht, ist das Vorzeichen des Restes durch die Implementierung definiert

4
e.James

Wenn dies das Verhalten ist und Sie wissen, dass dies der Fall ist, verwenden Sie für m % n = r einfach r = n + r. Wenn Sie nicht sicher sind, was hier passiert, verwenden Sie r = r % n.

Bearbeiten: Um es zusammenzufassen, verwenden Sie r = ( n + ( m % n ) ) % n

4
maxwellb

JavaScript tut dies auch. Ich bin ein paar Mal davon erwischt worden. Betrachten Sie es als Reflexion um Null und nicht als Fortsetzung.

1
Nosredna

Die Antwort von UncleO ist wahrscheinlich robuster, aber wenn Sie es in einer einzelnen Zeile machen wollen und Sie sicher sind, dass der negative Wert nicht negativer ist als eine einzelne Iteration des Mods (zum Beispiel, wenn Sie es sind) Sie können immer nur den Mod-Wert abziehen.) Sie können ihn jedoch zu einem einzigen Ausdruck vereinfachen:

int result = (n + 3) % 3;

Da Sie den Mod trotzdem ausführen, hat das Hinzufügen von 3 zum Anfangswert keine Auswirkung , es sei denn, n ist negativ (aber nicht kleiner als -3). In diesem Fall führt das zu dem erwarteten positiven Modul.

1
devios1

Warum: denn so ist der Mod-Operator im C-Standard festgelegt (Denken Sie daran, dass Objective-C eine Erweiterung von C ist). Die meisten Leute, die ich kenne (wie ich), verwirrt es, weil es überraschend ist und man sich daran erinnern muss.

Als Problemumgehung: Ich würde Onkelos verwenden.

1
Tobias

Nicht nur Java-Skript, fast alle Sprachen zeigen die falsche Antwort. Was von coneybeare gesagt wurde, ist richtig. Wenn wir mode'd haben, müssen wir einen Rest erhalten positive ganze Zahl....

Wenn Sie die Nummernzeile überprüfen, können Sie das verstehen

Ich habe auch das gleiche Problem in VB und es hat mich dazu gezwungen, eine zusätzliche Prüfung wie Zwingend hinzuzufügen. Wenn das Ergebnis negativ ist, müssen wir den Divisor zum Ergebnis hinzufügen

0
Anish Chandran

Für den Rest gibt es zwei Möglichkeiten, und das Zeichen hängt von der Sprache ab. ANSI C wählt das Vorzeichen der Dividende. Ich würde vermuten, dass dies der Grund ist, warum Objective-C dies auch tut. Siehe auch den Wikipedia-Eintrag .

0
user122376

Anstelle von a%b

Verwenden Sie: a-b*floor((float)a/(float)b)

Sie erwarten Rest und verwenden Modulo. In Mathe sind sie dasselbe, in C sind sie verschieden. GNU-C hat Rem () und Mod (), Objective-C hat nur Mod (), so dass Sie den obigen Code verwenden müssen, um die Rem-Funktion zu simulieren (das ist dasselbe wie Mod in der mathematischen Welt, aber nicht in der Programmierung Welt (zumindest für die meisten Sprachen)


Beachten Sie auch, dass Sie hierfür ein einfach zu verwendendes Makro definieren können.

#define rem(a,b) ((int)(a-b*floor((float)a/(float)b)))

Dann könnten Sie einfach rem(-1,3) in Ihrem Code verwenden und es sollte gut funktionieren.

0
Albert Renshaw