2012-02-14 7 views
20

Oggi al lavoro ho avuto una discussione interessante con uno dei miei colleghi. Fu sorpreso quando ha avuto il seguente succedere a lui:Perché l'operatore% viene definito come l'operatore "modulo" anziché l'operatore "resto"?

assert(-1 % 10 == -1) //Expecting 9 

Così, quando è venuto a chiedermi a questo proposito, gli ho detto "bene, che ha senso quando si divide -1 per 10, si ottiene 0. .. con -1 restante la sua tesi, tuttavia, era che l'operatore modulo dovrebbe tenere vero per il modello "sempre positivo" ho fatto una piccola ricerca e ho trovato che il modulo si riferiva a assomiglia a questo:

Sia q il quoziente intero di a e n. Sia r il resto. Poi:

a = n * q + r

La definizione mi stava usando, tuttavia, sembra essere la versione Knuth di modulo, che è:

Sia q pavimento di una divisa per n. Lascia che sia il resto. Poi:

r = a - n * q

Quindi, la mia domanda è: perché è finito in standard FORTRAN (e successivamente il C-standard) per avere l'operatore modulo troncare verso 0? Mi sembra un termine improprio chiamarlo "modulo" e non "resto" (in matematica, la risposta dovrebbe essere 9). Questo è legato a come l'hardware sta facendo la divisione?

Per riferimento:

TLDR; L'hardware è il motivo per cui l'operatore modulo tronca verso 0?

+3

Ti rendi conto che questa domanda e i collegamenti sono pieni di motivi per evitare il modulo con operandi negativi? –

+4

Evitarlo non è il punto della domanda. –

+0

Si chiama veramente "modulo" o "mod"? Quante sillabe ha "mod"? Che ne dici di "resto"? – supercat

risposta

15

sembra un termine improprio per me di chiamarlo "modulo" e non "resto" (in matematica, la risposta in realtà dovrebbe essere 9).

C lo chiama l'operatore% e chiama il suo risultato il resto. C++ copia questo da C. Né la lingua lo chiama l'operatore modulo. Questo spiega anche perché il resto è negativo: perché l'operatore/tronca verso 0 e (a/b) * b + (a % b) equivale a a.

Edit: David Rodríguez ricorda giustamente che C++ fa definiscono una classe template std::modulus, che chiama operator%. Secondo me, quella classe è mal chiamata. Scavando un po ', è ereditato da STL dove è già stato chiamato così com'è ora. Il download per STL dice "L'STL è stato sviluppato su SGI MIPSproTM C++ 7.0, 7.1, 7.2 e 7.2.1.", e per quanto posso dire senza avere effettivamente il compilatore e l'hardware, MIPSpro passa la divisione alla CPU e l'hardware MIPS tronca a 0, il che significherebbe che std::modulus è sempre stato erroneamente chiamato

+2

+1 Ho appena controllato lo standard C++: * l'operatore binario% restituisce il resto dalla divisione della prima espressione per il secondo *, quindi +1 per l'operatore stesso. Ora un altro problema è il nome del functor in 'functional' che usa' operator% 'che è chiamato * modulo *, quindi almeno parte della domanda è lasciata aperta ... –

+0

@ DavidRodríguez-dribeas Bella scoperta, non posso rispondere sulla storia che sta dietro e sul perché è chiamato così com'è. – hvd

+1

Penso che la fonte della confusione, almeno per me, è che se si utilizza 'fmod', ad esempio, non si otterrà un modulo reale, come implicherebbe il nome. Sembra che le due parole siano usate in modo intercambiabile. Ma tu sei corretto, il vero standard C++ dice resto. La fonte originale che ho usato era MSDN perché stavo cercando specificamente per VS2003. http://msdn.microsoft.com/en-us/library/ty2ax9z9(v=vs.71).aspx. Sembrerebbe che siano errati. –

4

% è il resto operatore in C e C++.

In Visual C++, è chiamata all'operatore % e produce il il resto della divisione. Nel C standard è chiamato il % operatore e poiché C99 realtà è un resto operatore Gli operatori modulo e resto differiscono rispetto ai valori negativi

L'operatore % è definito in C e C++ con a == (a/b * b) + a % b.

Il troncamento della divisione intera verso 0 in C viene eseguito da C99. In C89 è stata definita l'implementazione (e % può essere un operatore modulo in C89). C++ esegue anche il troncamento verso zero per la divisione intera.

Quando il troncamento viene eseguito verso zero, % è un operatore rimanente e il segno del risultato è il segno del dividendo. Quando il troncamento viene eseguito verso il meno infinito, % è un operatore modulo e il segno del risultato è il segno del divisore.

Sulle ragioni per cui C cambiato l'attuazione definito comportamento della divisione intera relativo troncamento, Doug Gwyn da C comittee detto:

C99 imposto un requisito Fortran-compatibili, nel tentativo di ottenere più rogrammers FORTRAN per aiutare nella conversione del codice Fortran a C.

C99 Rationale dice riguardanti troncamento verso divisione per zero integer:

In Fortran, tuttavia, il risultato troncerà sempre verso zero e l'overhead sembra essere accettabile per la comunità di programmazione numerica. Pertanto, C99 ora richiede un comportamento simile, che dovrebbe facilitare porting di codice da Fortran a C.

In gcc comportamento attuazione in C89 è sempre stato il troncamento verso lo zero.

Quindi % è l'operatore rimanente in C99, C++ e anche in Java, ma non è l'operatore residuo in tutti i linguaggi di programmazione. In Ruby e Python, % è in effetti l'operatore modulo (la divisione intera viene eseguita verso il meno infinito in queste lingue). Haskhell e Scheme hanno due operatori separati: mod e rem per Haskell e modulo e remainder per Schema.

+0

Haskhell eh? ;) – NateS

1

Ho paura che il problema derivi da un fraintendimento della matematica. Il modulo di congruenza n è una relazione di equivalenza , quindi definisce solo le classi di equivalenza . Quindi, è non corretto dire che 'in matematica, la risposta dovrebbe essere davvero 9' perché potrebbe essere anche 19, 29 e così via. E naturalmente può essere -1 o -11.Ci sono infiniti elementi della classe dei numeri n che sono n ≡ -1 mod (10).

http://en.wikipedia.org/wiki/Modular_arithmetic

http://en.wikipedia.org/wiki/Congruence_relation

Quindi, la domanda corretta potrebbe essere: quale elemento della classe dei numeri che sono ≡ -1 mod (10) sarà il risultato di -1% 10 in C++ ? E la risposta è: il resto della divisione di -1 per 10. Nessun mistero.

PS La tua definizione di modulo e Knuth sono, ehm, equivalente ... :)

+0

Queste definizioni non sono uguali. Collega -1% 10 e vedrai perché. –

+0

Perché? "Sia q il quoziente intero di aen" è lo stesso di "Sia q il piano di a diviso per n". Il resto della definizione è perfettamente uguale, dato che si gira n * q sull'altro lato dell'equivalente ...;) – ascanio

+3

Molte persone si aspetterebbero che l'operazione% restituisca un rappresentante univoco della classe di equivalenza. Questo non è il caso, perché restituisce rappresentanti diversi per coppie di numeri interi che appartengono alla stessa classe di equivalenza (x e -x, x! = 0). Il tuo argomento secondo cui -1% 10 potrebbe essere -1 o -11 avrebbe senso solo se lo stesso offset da [0, m-1] fosse sempre usato (es. Se -1% 10 = -11, allora anche il 9% 10 dovrebbe essere -11 e non 9). –