Perché il comportamento dell’operatore modulo (%) è diverso tra C e Ruby per gli interi negativi?

Stavo facendo funzionare del codice qui . Ho provato -40 % 3 . Mi dà l’uscita 2 . quando ho eseguito la stessa operazione in C, ottengo:

 int i = (-40) % 3 printf("%d", i); 

l’output è

 -1 

In che modo entrambe le lingue eseguono internamente l’operazione modulo?

Wiki dice:

Dati due numeri positivi , a (il dividendo) n (il divisore), un modulo n (abbreviato come un mod n) è il resto della divisione euclidea di a by n .
…. Quando a o n è negativo, la definizione ingenua si interrompe e i linguaggi di programmazione differiscono nel modo in cui questi valori sono definiti .


Ora la domanda è perché -40 % 3 è 2 in Ruby o in altre parole qual è la matematica dietro di esso?

Iniziamo con la divisione euclidea che afferma che:

Dati due interi a e n , con n ≠ 0 , esistono interi unici q ed r tali che a = n*q + r e 0 ≤ r < |n| , dove |n| denota il valore assoluto di n .

Adesso noti le due definizioni di quoziente:

1. Donald Knuth ha descritto la divisione pavimentata in cui il quoziente è definito dalla funzione floor q=floor(a/n) e il resto r è
inserisci la descrizione dell'immagine qui

Qui il quoziente ( q ) è sempre arrotondato verso il basso (anche se è già negativo) e il resto ( r ) ha lo stesso segno del divisore .

2. Alcune implementazioni definiscono il quoziente come

q = sgn(a)floor(|a| / n) whre sgn è signum function.

e il resto ( r ) ha lo stesso segno del dividendo ( a ) .

Ora tutto dipende da q :

  • Se l'implementazione va con definizione 1 e definisce q come floor(a/n) allora il valore di 40 % 3 è 1 e -40 % 3 è 2 . Che qui sembra il caso di Ruby.
  • Se l'implementazione segue la definizione 2 e definisce q come sgn(a)floor(|a| / n) , il valore di 40 % 3 è 1 e -40 % 3 è -1 . Che qui sembra il caso di C e Java.

In Java e C, il risultato dell’operazione modulo ha lo stesso segno del dividendo, quindi -1 è il risultato nel tuo esempio.

In Ruby, ha lo stesso segno del divisore, quindi +2 sarà il risultato in base al tuo esempio.

Nell’implementazione del ruby, quando il numeratore è negativo e il denominatore è positivo, la domanda che risponde l’operatore modulo è: “Qual è il più piccolo numero positivo che, quando sottratto dal numeratore, consente al denominatore di dividersi in modo uniforms nel risultato?”

In tutte le implementazioni, quando il numeratore e il denominatore sono entrambi positivi, la risposta alla domanda è: “Qual è il più piccolo numero positivo che, quando sottratto dal numeratore, consente al denominatore di dividersi in modo uniforms nel risultato?”

Quindi puoi vedere che l’implementazione di ruby ​​risponde in modo coerente alla stessa domanda, anche se all’inizio il risultato non è intuitivo.