Jakie jest zachowanie podziału liczb całkowitych?

209

Na przykład,

int result;

result = 125/100;

lub

result = 43/100;

Czy wynikiem będzie zawsze podłoga dywizji? Jakie jest zdefiniowane zachowanie?

TTT
źródło
5
Podsumowanie: podpisany podział na liczby całkowite skraca się do zera . W przypadku wyników nieujemnych jest to to samo co floor (zaokrąglenie w kierunku -Infinity). (Strzeż się, że C89 tego nie gwarantuje, zobacz odpowiedzi.)
Peter Cordes,
5
Wszyscy powtarzają „obcinaj do zera”, „sufit” lub „podłoga”, tak jak kod, świadomie decydując, jakiej techniki użyć. Jeśli kod mógł mówić to powiedzieć"I just throw the dam fraction part in the trash and move on with life"
Timothy LJ Stewart
3
@ TimothyL.J.Stewart „Kod” podejmuje świadomą decyzję. Zgodnie ze specyfikacją dzielenie liczb całkowitych ma oznaczać podział T (runcation). Z tego powodu operator modulo / reszta jest implantowany inaczej niż w innym języku, powiedzmy Python lub Ruby. Zobacz to na listę różnych sposobów językami operatora modulo i tym papierze, który wymienia co najmniej pięciu z najczęstszych sposobów języki programowania decydują się zrobić div / modulo.
13steinj
1
@ 13steinj Mówię kolokwialnie o komentarzach, które zamieniały się w „jest ścięty do zera ... nie, to jest piętro ... nie, jeśli jego ujemny jest sufit ...” czasami szczegóły techniczne nie rozprzestrzeniają się w przyszłość z ludzką pamięcią jak chcemy, ale wiedząc intuicyjnie, że „część ułamkowa jest odrzucana”, możesz wyciągnąć wnioski techniczne. Techniczność jest dużym obciążeniem, ale intuicja jest lekka i orzeźwiająca jak wiatr, zabiorę je daleko i szeroko, a gdy będzie to konieczne, będę wiedział, od czego zacząć. Podobnie jak ten papier, który połączyłeś, dziękuję.
Timothy LJ Stewart
Odpowiedziałem tutaj z naciskiem na podział euklidesowy (gra między podziałem całkowitym a operatorem modułu).
Picaud Vincent

Odpowiedzi:

182

Czy wynikiem będzie zawsze podłoga dywizji? Jakie jest zdefiniowane zachowanie?

Tak, iloraz całkowity dwóch operandów.

6.5.5 Operatory multiplikatywne

6 Po podzieleniu liczb całkowitych wynikiem operatora / jest iloraz algebraiczny z odrzuconą dowolną częścią ułamkową. 88) Jeżeli iloraz a / b jest reprezentowalny, wyrażenie (a / b) * b + a% b będzie równe a.

i odpowiedni przypis:

88) Jest to często nazywane „obcięciem do zera”.

Oczywiście należy zwrócić uwagę na dwa punkty:

3 Zwykłe konwersje arytmetyczne są wykonywane na operandach.

i:

5 Wynikiem operatora / jest iloraz podziału pierwszego operandu przez drugi; wynikiem operatora% jest reszta. W obu operacjach, jeśli wartość drugiego operandu wynosi zero, zachowanie jest niezdefiniowane.

[Uwaga: moje podkreślenie]

bezpośrednio
źródło
26
... chyba że dzielisz liczbę ujemną przez dodatnią (lub vv), w którym to przypadku będzie to pułap.
Czy
74
To nie jest podłoga ani sufit, to obcięcie części ułamkowej, jest koncepcyjnie inne!
lornova,
38
@Will A: Nie. Jest to zdefiniowane jako obcięcie w kierunku zera. Nazywanie tego czymkolwiek innym spowoduje zamieszanie, więc powstrzymaj się od tego.
Martin York,
44
Przynajmniej z matematycznego punktu widzenia obcięcie w kierunku zera jest równoważne „jeśli> 0 to sufit w przeciwnym razie”. Myślę, że zwykłe nazywanie skrótu jest prostsze niż nazywanie podłogi / sufitu, ale jedno z nich jest ważne. Niezależnie od tego, punkt Willa A jest poprawny: odpowiedź Dirkgently jest częściowo niepoprawna, ponieważ stwierdził, że OP ma rację, ponieważ wynikiem jest podłoga dywizji.
Brian
9
@Philip Potter: Nie sądzę, że został zdefiniowany w C89 i nie ma go w standardzie C ++ z 1998 roku. W nich oczywiście (a / b) * b + a % b == atrzeba było spełnić, a wartość bezwzględna a % bmusiała być mniejsza niż a, ale czy a % bbyła ujemna dla ujemnej aczy bnie została określona.
David Thornley,
39

Dirkgently daje doskonały opis podziału liczb całkowitych w C99, ale powinieneś także wiedzieć, że w C89 dzielenie liczb całkowitych z argumentem ujemnym ma kierunek zdefiniowany przez implementację.

Z projektu ANSI C (3.3.5):

Jeśli któryś z argumentów jest ujemny, to czy wynik operatora / jest największą liczbą całkowitą mniejszą niż iloraz algebraiczny, czy też najmniejszą liczbą całkowitą większą niż iloraz algebraiczny, określa się implementację, podobnie jak znak wyniku operatora%. Jeżeli iloraz a / b jest reprezentowalny, wyrażenie (a / b) * b + a% b będzie równe a.

Uważaj więc na liczby ujemne, gdy utkniesz przy kompilatorze C89.

To zabawne, że C99 wybrał obcięcie w kierunku zera, bo tak właśnie zrobił FORTRAN. Zobacz tę wiadomość na comp.std.c.

schot
źródło
2
A wstęp do C99 projektu N1256, akapit 5, wspomina reliable integer divisiono nowej funkcji językowej. Niesamowite *-*.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
Obcinanie to sposób, w jaki zachowuje się najbardziej popularny sprzęt CPU (np. X86), więc szaleństwem byłoby dokonać innego wyboru. IDK, który był pierwszy, semantyka Fortrana lub zachowanie sprzętowe, ale to nie przypadek, że one też są takie same.
Peter Cordes,
2
@PeterCordes: Najpopularniejszy sprzęt CPU może wykonywać dzielenie zmiennoprzecinkowe według większości stałych szybciej niż podział obcięty. IMHO, byłoby lepiej, gdyby Standard to powiedział expr1 / expr2i expr1 % expr2musi być ze sobą spójne, gdy oba przypadki expr1łączą te same obiekty w ten sam sposób, i podobnie expr2, ale wybór podziału obciętego na zmienny jest inaczej nieokreślony. Które pozwoliłyby bardziej efektywne generowanie kodu bez zerwania dużo kompatybilność (i implementacje mogłyby udokumentować specyficzne zachowanie jeżeli nachylona)
SuperCat
23

Tam, gdzie wynik jest ujemny, C skraca się w kierunku 0 zamiast podłogi - nauczyłem się tego czytania o tym, dlaczego podział liczb całkowitych w Pythonie zawsze ma podłogę tutaj: dlaczego podłogi w liczbach całkowitych w Pythonie

Gareth Williams
źródło
3
Zgadzam się z komentarzem, zastanawiając się, czy posiadanie (neg% pos) ujemnego jest kiedykolwiek przydatne? W powiązanej notatce zastanawiam się, czy wymagane zachowanie arytmetycznie niepoprawne w niektórych przypadkach „unsignedvar> podpisane” jest kiedykolwiek przydatne? Potrafię zrozumieć uzasadnienie, by nie wymagać zawsze poprawnego zachowania; Nie widzę żadnego uzasadnienia dla żądania złego zachowania.
supercat
8
+1 za doskonałe odniesienie do tego, dlaczego podłoga jest właściwym zachowaniem dla podziału na liczby całkowite (w przeciwieństwie do definicji C, która jest zepsuta i prawie nigdy nie jest przydatna).
R .. GitHub ZATRZYMAJ LÓD
@ supercat Zastanów się:, filtered = (k - 1) * filtered + value + carry; carry = filtered % factor; filtered /= factoriteracja ze zmieniającymi się wartościami value. Jest to dobre przybliżenie liczb całkowitych do filtra dolnoprzepustowego pierwszego rzędu ze stałą czasową k... ale jest symetryczne tylko wtedy, gdy podział jest obcinany i carryotrzymuje wartości ujemne. Oba zachowania przy podziale przydają się od czasu do czasu.
hobbs
1
@ Hobbs: Nie sądzę, aby powyższy kod zachowywał się czysto, gdy sygnały przekroczą zero. Jeśli divjest operatorem dzielenia zmiennoprzecinkowego i factorjest nieparzysty, to filtered += (filter+(factor div 2)) div factordałby czyste i symetryczne zachowanie dla wszystkich wartości do INT_MAX-(factor div 2).
supercat
@ superupat działa jednak; ten kod jest tylko nieznacznie destylowany z czegoś, co miałem przez jakiś czas w kontrolerze zegara atomowego.
hobbs
21

Tak, wynik jest zawsze przycinany do zera. Zaokrągli się w kierunku najmniejszej wartości bezwzględnej.

-5 / 2 = -2
 5 / 2 =  2

W przypadku niepodpisanych i nieujemnych wartości ze znakiem jest to to samo co floor (zaokrąglenie w kierunku -Infinity).

Leonid
źródło
43
Obcięcie, nie podłoga.
dan04,
9
@ dan04: Tak, podłoga byłaby ważna tylko dla dodatnich liczb całkowitych :)
Leonid
13

Czy wynikiem będzie zawsze podłoga dywizji?

Nie. Wynik jest różny, ale zmiana występuje tylko w przypadku wartości ujemnych.

Jakie jest zdefiniowane zachowanie?

Aby wyczyścić podłogę, zaokrągla się w kierunku ujemnej nieskończoności, podczas gdy podział na liczby całkowite zaokrągla w kierunku zera (obcina)

Dla wartości dodatnich są takie same

int integerDivisionResultPositive= 125/100;//= 1
double flooringResultPositive= floor(125.0/100.0);//=1.0

W przypadku wartości ujemnej jest inaczej

int integerDivisionResultNegative= -125/100;//=-1
double flooringResultNegative= floor(-125.0/100.0);//=-2.0
Mohamed El-Nakib
źródło
0

Wiem, że ludzie odpowiedzieli na twoje pytanie, ale w sposób laicki:

5 / 2 = 2 // ponieważ zarówno 5, jak i 2 są liczbami całkowitymi, a dzielenie liczb całkowitych zawsze obcina miejsca po przecinku

5.0 / 2 or 5 / 2.0 or 5.0 /2.0 = 2.5 // tutaj albo 5, albo 2 albo oba mają dziesiętne, stąd iloraz, który otrzymasz, będzie dziesiętny.

adi1ya
źródło