Qual è il comportamento della divisione intera?


211

Per esempio,

int result;

result = 125/100;

o

result = 43/100;

Il risultato sarà sempre il pavimento della divisione? Qual è il comportamento definito?


5
Riassunto: firmata intero tronca divisione verso lo zero . Per risultati non negativi, questo è lo stesso del piano (arrotondato verso -Infinito). (Attenzione, C89 non lo garantisce, vedere le risposte.)
Peter Cordes,

6
Tutti continuano a dire "tronca verso zero" o "soffitto" o "piano" come se il codice prendesse una decisione deliberata su quale tecnica usare. Se il codice potesse parlare direbbe"I just throw the dam fraction part in the trash and move on with life"
Timothy LJ Stewart l'

3
@ TimothyL.J.Stewart Il "codice" sta prendendo una decisione deliberata. Secondo la specifica, la divisione intera deve essere suddivisa in T (runcation). Per questo motivo, l'operatore modulo / resto viene impiantato in modo diverso rispetto a se fosse in un'altra lingua, ad esempio Python o Ruby. Vedi questo per un elenco di diversi modi in cui le lingue eseguono l'operatore modulo e questo documento che elenca almeno cinque dei modi comuni in cui i linguaggi di programmazione decidono di fare div / modulo.
13steinj,

1
@ 13steinj Sto parlando colloquialmente per i commenti che si stava trasformando in "è troncato verso zero ... no è piano ... no se è negativo il suo soffitto ..." a volte i tecnicismi non si propagano nel futuro con la memoria umana come desideriamo, ma sapendo intuitivamente che la "parte di frazione viene eliminata" è possibile ricavare i punti tecnici. I tecnicismi sono un fardello pesante, ma l'intuizione è leggera e rinfrescante come il vento, li porterò in lungo e in largo e quando necessario saprò da dove cominciare. Come quella carta che hai collegato, grazie.
Timothy LJ Stewart,

Ho risposto qui con l'accento sulla divisione euclidea (interazione tra divisione di interi e operatore di modulo).
Picaud Vincent,

Risposte:


182

Il risultato sarà sempre il pavimento della divisione? Qual è il comportamento definito?

Sì, quoziente intero dei due operandi.

6.5.5 Operatori moltiplicativi

6 Quando gli interi sono divisi, il risultato dell'operatore / è il quoziente algebrico con qualsiasi parte frazionaria scartata. 88) Se il quoziente a / b è rappresentabile, l'espressione (a / b) * b + a% b deve essere uguale a.

e la nota a piè di pagina corrispondente:

88) Questo è spesso chiamato '' troncamento verso zero ''.

Naturalmente due punti da notare sono:

3 Le solite conversioni aritmetiche vengono eseguite sugli operandi.

e:

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

[Nota: enfasi sulla mia]


26
... a meno che, ovviamente, non divida un numero negativo per un positivo (o vv), nel qual caso sarà il massimale.
Sarà il

74
Non è né pavimento né soffitto, è troncamento della parte frazionaria, è concettualmente diverso!
lornova,

38
@Will A: No. È definito come troncamento verso zero. Chiamarlo come altro aggiungerà solo confusione, quindi per favore astieniti dal farlo.
Martin York,

44
Almeno da una prospettiva matematica, il troncamento verso zero equivale a "if> 0 then floor else ceiling". Penso che chiamarlo solo troncamento sia più semplice di chiamarlo pavimento / soffitto, ma entrambi sono validi. Indipendentemente da ciò, il punto di Will A è valido: la risposta di Dirkgently è parzialmente errata, dal momento che ha affermato che l'OP ha ragione sul risultato che è il pavimento della divisione.
Brian,

9
@Philip Potter: non credo sia stato definito in C89 e non sia nello standard C ++ del 1998. In quelli, ovviamente, (a / b) * b + a % b == adovevano essere soddisfatti e il valore assoluto di a % bdoveva essere inferiore a a, ma se a % bera negativo per negativo ao bnon era specificato.
David Thornley,

41

Dirkgently fornisce un'eccellente descrizione della divisione intera in C99, ma dovresti anche sapere che in C89 la divisione intera con un operando negativo ha una direzione definita dall'implementazione.

Dalla bozza ANSI C (3.3.5):

Se uno degli operandi è negativo, se il risultato dell'operatore / è il numero intero più grande inferiore al quoziente algebrico o il numero intero più piccolo maggiore del quoziente algebrico è definito dall'implementazione, così come il segno del risultato dell'operatore%. Se il quoziente a / b è rappresentabile, l'espressione (a / b) * b + a% b deve essere uguale a.

Quindi fai attenzione con i numeri negativi quando sei bloccato con un compilatore C89.

È un fatto divertente che C99 abbia scelto il troncamento verso zero perché è stato così che FORTRAN l'ha fatto. Vedi questo messaggio su comp.std.c.


2
E la bozza C99 N1256 prefazione paragrafo 5 menziona reliable integer divisioncome una nuova funzionalità linguistica. Incredibile *-*.
Ciro Santilli 11 冠状 病 六四 事件 法轮功 l'

Il troncamento è il comportamento dell'hardware più comune della CPU (ad es. X86), quindi sarebbe folle fare una scelta diversa. IDK che è venuto per primo, semantica di Fortran o comportamento hardware, ma non è una coincidenza che anche quelli siano gli stessi.
Peter Cordes,

2
@PeterCordes: l'hardware della CPU più comune potrebbe eseguire la divisione pianificata per la maggior parte delle costanti più velocemente di quanto potrebbero fare la divisione troncante. IMHO, sarebbe stato meglio dello standard di dire che expr1 / expr2e expr1 % expr2deve essere coerente con l'altro quando entrambi istanze di expr1combinare gli stessi oggetti nello stesso modo, e così per expr2, ma la scelta di troncare rispetto divisione pavimento è altrimenti specificato. Ciò avrebbe consentito una generazione di codice più efficiente senza compromettere molta compatibilità (e le implementazioni potrebbero documentare comportamenti specifici se propensi)
supercat

23

Dove il risultato è negativo, C si tronca verso 0 anziché verso il pavimento - Ho imparato questa lettura sul perché la divisione di numeri interi di Python va sempre a segno qui: Perché la divisione di numeri interi di Python Floors


3
Concordo con il commento chiedendosi se avere (neg% pos) diventa negativo sia mai utile? In una nota correlata, mi chiedo se il comportamento aritmeticamente errato richiesto in alcuni casi di "unsignedvar> signedvar" sia mai utile? Riesco a capire la logica per non aver richiesto un comportamento sempre corretto; Non vedo alcuna logica per aver richiesto un comportamento sbagliato.
supercat

8
+1 per un riferimento eccellente sul perché il pavimento è il comportamento corretto per la divisione di numeri interi (contrariamente alla definizione di C, che è rotta e quasi mai utile).
R .. GitHub FERMA AIUTANDO ICE

@supercat Considerare:, filtered = (k - 1) * filtered + value + carry; carry = filtered % factor; filtered /= factorripetuto con la modifica dei valori di value. Fa una bella approssimazione di numeri interi a un filtro passa-basso del primo ordine con costante di tempo k... ma è solo simmetrico se la divisione viene troncata e carryottiene valori negativi. Entrambi i comportamenti per la divisione sono utili di volta in volta.
Hobbs,

1
@hobbs: non credo che il codice sopra riportato si comporterebbe in modo pulito quando i segnali attraversano lo zero. Se divè un operatore di divisione a pavimento ed factorè dispari, allora filtered += (filter+(factor div 2)) div factorprodurrebbe un comportamento pulito e simmetrico per tutti i valori fino a INT_MAX-(factor div 2).
supercat

@supercat funziona però; quel codice è solo leggermente distillato da qualcosa che ho avuto in esecuzione nel controller di un orologio atomico per un po '.
Hobbs

21

Sì, il risultato viene sempre troncato verso zero. Arrotonderà verso il valore assoluto più piccolo.

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

Per i valori con segno non firmato e non negativo, questo è uguale a floor (arrotondamento verso -Infinito).


43
Troncamento, non piano.
dan04,

9
@ dan04: yep floor sarebbe valido solo per numeri interi positivi :)
Leonid

13

Il risultato sarà sempre il pavimento della divisione?

No. Il risultato varia, ma la variazione si verifica solo per valori negativi.

Qual è il comportamento definito?

Per chiarire che il piano si arrotonda verso l'infinito negativo, mentre la divisione dei numeri interi arrotonda verso lo zero (tronca)

Per valori positivi sono gli stessi

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

Per valore negativo questo è diverso

int integerDivisionResultNegative= -125/100;//=-1
double flooringResultNegative= floor(-125.0/100.0);//=-2.0

0

So che le persone hanno risposto alla tua domanda ma in termini laici:

5 / 2 = 2 // poiché sia ​​5 che 2 sono numeri interi e la divisione dei numeri interi tronca sempre i decimali

5.0 / 2 or 5 / 2.0 or 5.0 /2.0 = 2.5 // qui 5 o 2 o entrambi hanno i decimali, quindi il quoziente che otterrai sarà in decimale.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.