2013-07-04 13 views
19

Nelle classi precedenti, mi è stato insegnato che n % d = r e di pensarci come n = d*q + r, dove d è il divisore, q è il quoziente, e r è il resto (notare che il resto non può mai essere negativo).Quali sono le regole dell'aritmetica modulare in C?

Così, per esempio, è -111 mod 1110, perché -111 = -11*-11 + 10 (al contrario di -111 = -11*10 -1, visto che che ci darebbe un resto negativo).

Tuttavia, quando si stampano i risultati di -111 % 11, -1 è il risultato e non 10. Perché? Non è tecnicamente sbagliato?

+1

Ah, il vecchio negativo operando modulo :-) ricordo Python ottenere nel modo giusto (in senso matematico) in tutti i casi particolari. – Cameron

+0

Se vuoi forzare l'operatore '%' di C in un modulo che funziona come ti aspettavi, fai questo: '((a% b) + b)% b' – paddy

+2

C'è una bella tabella sulla pagina di Wikipedia di Modulo Operazione che mostra come ogni lingua ha la propria implementazione modulo: http://en.wikipedia.org/wiki/Modulo_operation –

risposta

6

Per modulo, -1 sarebbe una risposta errata.

L'operatore % di C è un operatore rimanente, non un operatore modulo, e per il resto è consentito 10 o -1.

+0

Si prega di definire cosa si intende con modulo.Sembrano esserci definizioni diverse, a seconda del contesto, e per alcuni di questi, ISTM che -1 sarebbe corretto. –

+0

@RudyVelthuis: "modulo" è normalmente associato a [aritmetica modulare] (http://mathworld.wolfram.com/ModularArithmetic.html). Almeno come l'aritmetica modulare è normalmente definita, sono ammessi solo numeri non negativi. –

+0

Come ho detto, dipende dal contesto. Se stai alludendo alla divisione di Euclide, allora in effetti, il resto è sempre positivo. Ma in altri contesti, questo non è necessariamente il caso. Soprattutto perché questo è un forum di programmazione, dovrebbe essere noto che il significato di "modulo" può variare da una lingua all'altra. –

4

L'operatore % è implementato in modo tale che a == b * (a/b) + (a % b) è vero, in cui si utilizza la divisione integer.

In questo caso -111/11 è -10, quindi -111 == 11 * -10 + x è soddisfatto da x == -1.

+0

IOW, 'a% b = a - (a/b) * b'. Poiché '-111/11' restituisce' -10', il risultato è '-111 - (-10 * 11)', cioè '-1'. –

19

Risposta breve:

La garanzia standard che (a/b)*b + a%b è uguale a a.

In C99, il risultato della divisione / verrà troncato verso zero. Il risultato dell'operatore % sarà certo, in questo caso, -1.

In C89, il risultato della divisione / può essere troncato in entrambi i modi per gli operandi negativi. Quindi il risultato dell'operatore % dipende anche dalla macchina.

lunga risposta:

Da C99 6.5.5

5 Il risultato della/operatore è il quoziente della divisione del primo operando dalla secondo; il risultato dell'operatore% è il resto. In entrambe le operazioni, se il valore di il secondo operando è zero, il comportamento non è definito.

6 Quando gli interi sono divisi, il risultato dell'operatore/è il quoziente algebrico con qualsiasi parte frazionata scartata. Se il quoziente a/b è rappresentabile, l'espressione (a/b) * b + a% b deve essere uguale a; in caso contrario, il comportamento di a/b e a% b è indefinito.

e la nota sulla stessa pagina per spiegare come funziona /, si dice:

Questo è spesso chiamato ‘‘il troncamento verso lo zero’’.

Secondo questa regola, -111/11 può essere solo -10, non 1. Da (a/b)*b + a%b deve essere pari a a, abbiamo -111 % 11 è -1.

Tuttavia, K & R Capitolo 2.5 dà una risposta diversa:

La direzione di troncamento per/e il segno del risultato% sono per operandi negativi dipende dalla macchina, come nel seguito dato ai overflow o underflow.

In base a questo, sia -1 o 10 può essere un risultato legale.

La ragione è in C89 3.3.5:

Quando interi vengono divisi e la divisione è inesatto, se entrambi gli operandi sono positivi il risultato del/operatore è il più grande intero minore del quoziente algebrico e il risultato dell'operatore% è positivo. Se uno degli operandi è negativo, se il risultato dell'operatore/è il più grande intero meno del quoziente algebrico o il più piccolo intero maggiore del quoziente algebrico è definito dall'implementazione, come il segno del risultato dell'operatore%. Se il quoziente a/b è rappresentabile, l'espressione (a/b) * b + a% b deve essere uguale a a.

Si è verificato un cambiamento da C89 a C99.

C99 Rationale 6.5.5 fornisce alcune ragioni storiche:

In C89, divisione di numeri interi che coinvolgono operandi negativi potrebbe arrotondare verso l'alto o verso il basso in modo definito dall'implementazione; l'intento era di evitare di sovraccaricare il codice di runtime per verificare casi speciali e applicare un comportamento specifico. In Fortran, tuttavia, il risultato troncerà sempre verso zero e l'overhead sembra essere accettabile per la comunità di programmazione numerica. Pertanto, C99 richiede ora un comportamento simile, che dovrebbe facilitare il porting del codice da Fortran a C. La tabella in §7.20.6.2 di questo documento illustra la semantica richiesta.

Ed ecco la tabella in §7.20.6.2:

numer denom quot rem 
7  3 2 1 
–7  3 –2 –1 
7  –3 –2 1 
–7  –3 2 –1 
+1

Penso che solo -1 sia consentito - la nota 90 (nella versione n1256 dello standard C99) dice, in riferimento al testo "[...] il quoziente algebrico con qualsiasi parte frazionata scartata", che "questo è spesso chiamato troncamento" verso 0 ". Quindi prendo questo per significare che '-111/11' può essere solo -10, e quindi '-111% 11' può essere solo -1 a causa del requisito che' (a/b) * b + a% b' deve essere uguale a a. –

+0

Inoltre, gli operatori bit a bit funzionano diversamente! Anche se '&' e '>>' sono di solito paragonati a modulo e divisione in potenze di 2, '>>' non "troncano verso zero", quindi '-5 >> 1 == -3', e' - 11 & 3 == 1' (mentre '-11% 4 == -3') –

+1

Sì, questo è stato modificato in C99. I compilatori C89 possono fare entrambi e generalmente fanno tutto ciò che è più conveniente per l'hardware. – torek