2009-06-13 18 views
42

Così ho pensato che i numeri negativi, quando mod'ed dovrebbe essere messo in spazio positivo ... i cant ottenere questo accada in Objective-CStrano comportamento Objective-C Mod per i numeri negativi

Mi aspetto che questo:

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

Ma ottenere questo

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

Perché è questo e c'è una soluzione?

+0

Clojure è la prima lingua che ho incontrato che implementa mod in modo corretto. Sìì! –

+2

@ToddOwen: Python lo fa anche correttamente – Claudiu

+0

@Todd, Lisp ha entrambi. – Pacerier

risposta

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

Non eseguire operazioni di mod extra come suggerito nelle altre risposte. Sono molto costosi e inutili.

+1

Non dipende dal processore se i condizionali sono migliori o peggiori di un modulo? – Nosredna

+2

Non ho mai visto un processore in cui divisione o modulo non sia l'operazione più lenta. Il controllo del negativo si riduce alla verifica del valore di un bit, quindi di solito è una delle istruzioni più veloci. – UncleO

+0

Sì. Probabilmente è giusto. Penso che nel Core Duo Intels, una divisione è qualcosa come 15-17 cicli. Vedo che molte persone cercano di evitare la ramificazione al giorno d'oggi. Ma con un mod probabilmente vale la pena. – Nosredna

4

mi sarei aspettato un numero positivo, come pure, ma ho trovato questo, da ISO/IEC 14882: 2003: Linguaggi di programmazione - C++, 5.6.4 (che si trova nella Wikipedia article on the modulus operation):

L'operatore% binario restituisce il resto dalla divisione della prima espressione per il secondo. .... Se entrambi gli operandi non sono negativi, il resto non è negativo; in caso contrario, il segno del resto è definito dall'implementazione

+1

Hooray per specifiche vaghe. : | – devios1

14

In C e Objective-C, gli operatori di divisione e modulo eseguono il troncamento verso zero. a/b è floor(a/b) se a/b > 0, altrimenti è ceiling(a/b) se a/b < 0. È sempre il caso che a == (a/b) * b + (a % b), a meno che, naturalmente, b sia 0. Di conseguenza, positive % positive == positive, positive % negative == positive, negative % positive == negative e negative % negative == negative (è possibile elaborare la logica per tutti i 4 casi, anche se è un po 'complicato).

+2

+1 per il _why_. –

0

Esistono due opzioni per il resto e il segno dipende dalla lingua. ANSI C sceglie il segno del dividendo. Sospetto che questo sia il motivo per cui vedi anche Objective-C. See the wikipedia entry as well.

4

Se questo è il comportamento, e sai che lo sarà, quindi per m % n = r, utilizzare solo r = n + r. Se non sei sicuro di cosa accadrà qui, utilizza quindi r = r % n.

Modifica: Per riassumere, utilizzare r = (n + (m % n)) % n

+1

Se hai appena detto che dovrebbe fare (-1 + 3)% 3 = 2, sono d'accordo. :-) – Nosredna

+1

Direi di fare (3 + (-1% 3))% 3 == (3 + (-1))% 3 == (2% 3) == 2 – maxwellb

+0

Gotcha. Quello è buono. Può essere fatto anche con un condizionale (se o ternario). – Nosredna

1

JavaScript fa questo, anche. Sono stato catturato da un paio di volte. Pensala come una riflessione intorno allo zero piuttosto che una continuazione.

8

Se n ha un intervallo limitato, è possibile ottenere il risultato desiderato semplicemente aggiungendo un multiplo costante noto di 3 che è maggiore del valore assoluto del minimo.

Per esempio, se n è limitato a -1000..2000, quindi è possibile utilizzare l'espressione:

result = (n+1002) % 3; 

Assicurarsi che la massima più il vostro costante non sarà traboccare quando sommati.

1

Perché: questo è il modo in cui l'operatore mod è specificato nello standard C (Ricorda che Objective-C è un'estensione di C). Confonde la maggior parte delle persone che conosco (come me) perché è sorprendente e devi ricordarlo.

Per quanto riguarda una soluzione: vorrei usare uncleo.

+0

Sì, confondendo proprio come si sottraggono sull'asse y per salire. Solo una di quelle cose di preferenza dei primi stilisti della lingua. All'inizio fastidioso; probabilmente utile in seguito. In effetti, scommetto che mod funzionante in questo modo aveva una grande utilità quando i programmatori dovevano progettare funzioni compatte per ottenere i loro byte nei loro programmi, lo stesso motivo per cui gli array partono dall'indice 0 e non dall'indice 1, rendeva la matematica più compattabile –

7

abbiamo un problema di lingua:

 
math-er-says: i take this number plus that number mod other-number 
code-er-hears: I add two numbers and then devide the result by other-number 
code-er-says: what about negative numbers? 
math-er-says: WHAT? fields mod other-number don't have a concept of negative numbers? 
code-er-says: field what? ... 
  • la persona per la matematica in questo conversazioni sta parlando di fare matematica in una linea circolare numero. Se si sottraggono dal fondo ci si avvolge verso l'alto.
  • la persona di codice sta parlando di un operatore che calcola il resto.

In questo caso, si desidera l'operatore mod del matematico e disporre della funzione resto a propria disposizione. puoi convertire l'operatore rimanente nell'operatore mod del matematico controllando se sei caduto dal fondo ogni volta che esegui la sottrazione.

+0

i numeri naturali definiscono la divisione in modo tale che (n + d)/d == (n/d) +1. Anche i numeri reali lo fanno. I numeri reali supportano anche (n/d) == (- n)/d, ma i numeri naturali no. È possibile che gli interi supportino un assioma o l'altro, ma non entrambi. Mentre il linguaggio di programmazione poteva sostenere il primo assioma per i numeri interi e alcuni lo fanno, i creatori di FORTRAN hanno deciso di supportare il secondo invece, e molte altre lingue hanno seguito l'esempio. – supercat

0

Non solo java script, quasi tutte le lingue mostra la risposta sbagliata' quello coneybeare detto è corretto, quando abbiamo mode'd dobbiamo ottenere resto resto è nulla, ma che rimane dopo la divisione e dovrebbe essere un intero positivo ....

Se si seleziona la linea numero che si può capire che

ho anche affrontare lo stesso problema in VB ed e mi ha fatto di aggiungere forza di controllo extra come se il risultato è negativo dobbiamo aggiungere il divisore al risultato

1

La risposta di UncleO è probabilmente più robusta, ma se vuoi farlo su una singola riga, e sei certo che il valore negativo non sarà più negativo di una singola iterazione della mod (ad esempio se sei sempre e solo sottraendo al massimo il valore mod in qualsiasi momento) è possibile semplificare ad una sola espressione:

int result = (n + 3) % 3; 

Dal momento che si sta facendo il mod in ogni caso, aggiungendo 3 al valore iniziale non ha alcun effetto a meno che n è negativo (ma non meno di -3), nel qual caso il risultato è il modulo positivo atteso.

0

Invece di a%b

Usa: a-b*floor((float)a/(float)b)

vi aspettate resto e si utilizza modulo. In matematica sono la stessa cosa, in C sono diversi. GNU-C ha Rem() e Mod(), ogg-c ha solo mod() quindi dovrai usare il codice sopra per simulare la funzione rem (che è la stessa di mod nel mondo matematico, ma non nella programmazione mondo [per la maggior parte delle lingue almeno])


Nota anche che è possibile definire una macro facile da usare per questo.

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

Allora si potrebbe utilizzare rem(-1,3) nel codice e dovrebbe funzionare bene.