W programie C próbowałem poniższych operacji (aby sprawdzić zachowanie)
x = 5 % (-3);
y = (-5) % (3);
z = (-5) % (-3);
printf("%d ,%d ,%d", x, y, z);
dał mi wyjście jak (2, -2 , -2)
w gcc. Za każdym razem spodziewałem się pozytywnego wyniku. Czy moduł może być ujemny? Czy ktoś może wyjaśnić to zachowanie?
Odpowiedzi:
C99 wymaga, aby gdy
a/b
był reprezentowalny:(a/b) * b
+a%b
będzie równya
Logicznie ma to sens. Dobrze?
Zobaczmy, do czego to prowadzi:
Przykład A.
5/(-3)
to-1
=>
(-1) * (-3)
+5%(-3)
=5
Może się to zdarzyć tylko wtedy, gdy
5%(-3)
jest 2.Przykład B.
(-5)/3
to-1
=>
(-1) * 3
+(-5)%3
=-5
Może się to zdarzyć tylko wtedy, gdy
(-5)%3
jest-2
źródło
-5/3
jest,-2
a mod staje się 1. Krótko mówiąc: jeden moduł ma znak, który następuje po znaku dywidendy (obcięcie), drugi moduł ma znak, który następuje po znaku dzielnika (Knuth).%
Operator C nie jest modulo operatora, ale pozostała operatora.Moduły i pozostałe operatory różnią się pod względem wartości ujemnych.
W przypadku operatora reszty znak wyniku jest taki sam jak znak dywidendy, natomiast w przypadku operatora modulo znak wyniku jest taki sam jak dzielnik.
C definiuje
%
operacjęa % b
jako:z
/
podziałem na liczby całkowite z obcięciem w kierunku0
. To obcięcie, które jest wykonywane w kierunku0
(a nie w kierunku ujemnej nieskończoności), które definiuje%
jako operator reszty, a nie operator modulo.źródło
remainder
orazmodulo
w Schemacierem
imod
w Haskell). Te specyfikacje operatorów różnią się w tych językach w zależności od sposobu podziału: obcięcie w kierunku 0 lub w kierunku ujemnej nieskończoności. Nawiasem mówiąc C Standardowy nigdy nazywa operatora modulo , po prostu wymienić mu operator% .%
remainder
funkcją w C, która implementuje pozostałą część IEEE z semantyką zaokrąglenia w kierunku najbliższego podziałuNa podstawie specyfikacji C99:
a == (a / b) * b + a % b
Możemy napisać funkcję do obliczenia
(a % b) == a - (a / b) * b
!Do działania modulo możemy mieć następującą funkcję (zakładając
b > 0
)Mój wniosek jest taki, że
a % b
w C jest operacją reszty, a NIE operacją modulo.źródło
b
jest ujemne (a w rzeczywistości zarówno dla negatywnych, jakr
ib
negatywnych daje wyniki mniejsze niż-b
). Aby zapewnić pozytywne wyniki dla wszystkich danych wejściowych, których możesz użyć,r + abs(b)
lub aby dopasowaćb
znak s, możeszr*b < 0
zamiast tego zmienić warunek na .r + abs(b)
to UB kiedyb == INT_MIN
.Nie sądzę, że trzeba sprawdzać, czy liczba jest ujemna.
Prostą funkcją znalezienia pozytywnego modulo byłoby:
Edycja: Zakładając
N > 0
iN + N - 1 <= INT_MAX
Będzie to działać zarówno dla dodatnich, jak i ujemnych wartości x.
Oryginalny PS: też jak podkreślił @chux, Jeśli x i N może osiągnąć coś podobnego INT_MAX-1 i INT_MAX odpowiednio, po prostu zastąpić
int
zlong long int
.A jeśli przekraczają również granice długich długich (tj. W pobliżu LLONG_MAX), wówczas osobno zajmiemy się przypadkami dodatnimi i ujemnymi, jak opisano w innych odpowiedziach tutaj.
źródło
N < 0
wynik może być ujemny jak wmodulo(7, -3) --> -2
.x % N + N
Może również przepełnićint
matematykę, która jest niezdefiniowanym zachowaniem. np.modulo(INT_MAX - 1,INT_MAX)
może spowodować -3.long long int
lub osobno zająć się przypadkiem negatywnym (kosztem utraty prostoty).Inne odpowiedzi wyjaśniły w C99 lub później, podział liczb całkowitych obejmujący argumenty ujemne zawsze jest skracany do zera .
Zauważ, że w C89 , czy zaokrąglenie wyniku w górę, czy w dół jest zdefiniowane w implementacji. Ponieważ
(a/b) * b + a%b
jest równya
we wszystkich standardach, wynik%
angażowania argumentów ujemnych jest również zdefiniowany w C89.źródło
%
może być ujemna, ponieważ jest operatorem reszty , reszta po dzieleniu, a nie po podziale Euclidean . Od C99 wynik może być 0, ujemny lub dodatni.Modulo PO chciała to klasyczny euklidesowa modulo , nie
%
.Aby wykonać moduł euklidesowy, który jest dobrze zdefiniowany za każdym razem, gdy
a/b
jest zdefiniowany,a,b
mają dowolny znak, a wynik nigdy nie jest ujemny:źródło
Wynik działania Modulo zależy od znaku licznika, a zatem otrzymujesz -2 dla y i z
Oto odniesienie
http://www.chemie.fu-berlin.de/chemnet/use/info/libc/libc_14.html
źródło
W matematyce, z której wywodzą się te konwencje, nie można twierdzić, że arytmetyka modulo powinna dać wynik dodatni.
Na przykład.
1 mod 5 = 1, ale może również wynosić -4. Oznacza to, że 1/5 daje resztę 1 z 0 lub -4 z 5. (Oba współczynniki 5)
Podobnie, -1 mod 5 = -1, ale może również wynosić 4. Oznacza to, że -1/5 daje resztę -1 z 0 lub 4 z -5. (Oba czynniki 5)
W celu dalszej lektury zapoznaj się z klasami równoważności w matematyce.
źródło
a
ab
,b <> 0
. Zgodnie z twierdzeniem o podziale euklidesowym istnieje dokładnie jedna para liczb całkowitychm
,r
gdziea = m * b + r
i0 <= r < abs( b )
. Jestr
to wynik (matematycznego) działania modulo i z definicji nie jest ujemne. Więcej lektur i dalsze linki na Wikipedii: en.wikipedia.org/wiki/Euclidean_division1 mod 5
jest zawsze 1.-4 mod 5
może być również 1, ale są to różne rzeczy.Zgodnie ze standardem C99 , sekcja 6.5.5. Operatory multiplikacyjne , wymagane są:
Wniosek
Znak wyniku pozostałej operacji, zgodnie z C99, jest taki sam jak dywidendy.
Zobaczmy kilka przykładów (
dividend / divisor
):Gdy tylko dywidenda jest ujemna
Gdy tylko dzielnik jest ujemny
Gdy zarówno dzielnik, jak i dywidenda są ujemne
źródło
Operator modułu podaje resztę. Operator modułu c zwykle przyjmuje znak licznika
Również operator modułu (reszty) może być używany tylko z liczbą całkowitą i nie może być stosowany z liczbą zmiennoprzecinkową.
źródło
Uważam, że bardziej użyteczne jest myślenie
mod
tak, jak jest zdefiniowane w abstrakcyjnej arytmetyki; nie jako operacja, ale jako cała inna klasa arytmetyki, z różnymi elementami i różnymi operatorami. Oznacza to, że dodaniemod 3
nie jest tym samym, co „normalne” dodanie; to jest; dodawanie liczb całkowitych.Więc kiedy to zrobisz:
Próbujesz odwzorować liczbę całkowitą 5 na element w zestawie
mod -3
. Są to elementymod -3
:Więc:
Powiedz, że musisz pozostać z jakiegoś powodu 30 godzin, ile godzin pozostało ci z tego dnia?
30 mod -24
.Ale to, co implementuje C
mod
, nie jest resztą. W każdym razie chodzi o to, że zwracanie negatywów ma sens.źródło