Quel est le comportement de la division entière?

211

Par exemple,

int result;

result = 125/100;

ou

result = 43/100;

Le résultat sera-t-il toujours le plancher de la division? Quel est le comportement défini?

TTT
la source
5
Résumé: la division entière signée tronque vers zéro . Pour les résultats non négatifs, c'est la même chose que le plancher (arrondi vers -Infinity). (Attention, C89 ne garantit pas cela, voir les réponses.)
Peter Cordes
6
Tout le monde n'arrête pas de dire "tronquer vers zéro" ou "plafond" ou "plancher" comme le code prend une décision délibérée sur la technique à utiliser. Si le code pouvait parler, il dirait"I just throw the dam fraction part in the trash and move on with life"
Timothy LJ Stewart
3
@ TimothyL.J.Stewart Le "code" prend une décision délibérée. Selon la spécification, la division entière est censée être une division T (runcation). Pour cette raison, l'opérateur modulo / reste est implanté différemment que s'il était dans une autre langue, disons Python ou Ruby. Voir ceci pour une liste des différentes façons dont les langages font l'opérateur modulo et cet article qui répertorie au moins cinq des façons courantes que les langages de programmation décident de faire div / modulo.
13steinj
1
@ 13steinj Je parle familièrement par les commentaires qu'il se transformait en "c'est tronqué vers zéro ... non c'est plancher ... non si c'est négatif son plafond ..." parfois les détails techniques ne se propagent pas dans le futur avec la mémoire humaine comme nous le souhaitons, mais sachant intuitivement que la "partie fraction est jetée" vous pouvez en déduire les points techniques. Les détails techniques sont un lourd fardeau, mais l'intuition est légère et rafraîchissante comme le vent, je les porterai loin et si nécessaire je saurai par où commencer. Comme ce papier que vous avez lié, merci.
Timothy LJ Stewart
J'ai répondu ici en mettant l'accent sur la division euclidienne (interaction entre la division entière et l'opérateur de module).
Picaud Vincent

Réponses:

182

Le résultat sera-t-il toujours le plancher de la division? Quel est le comportement défini?

Oui, quotient entier des deux opérandes.

6.5.5 Opérateurs multiplicatifs

6 Lorsque les entiers sont divisés, le résultat de l'opérateur / est le quotient algébrique avec toute partie fractionnaire rejetée. 88) Si le quotient a / b est représentable, l'expression (a / b) * b + a% b doit être égale à a.

et la note de bas de page correspondante:

88) Ceci est souvent appelé «troncature vers zéro».

Bien sûr, deux points à noter sont:

3 Les conversions arithmétiques habituelles sont effectuées sur les opérandes.

et:

5 Le résultat de l'opérateur / est le quotient de la division du premier opérande par le second; le résultat de l'opérateur% est le reste. Dans les deux opérations, si la valeur du deuxième opérande est nulle, le comportement n'est pas défini.

[Remarque: je souligne]

dirkgently
la source
26
... sauf, bien sûr, si vous divisez un nombre négatif par un positif (ou vv), auquel cas ce sera le plafond.
Will A
74
Ce n'est ni un plancher ni un plafond, c'est une troncature de partie fractionnaire, c'est conceptuellement différent!
lornova
38
@Will A: Non. Elle est définie comme une troncature vers zéro. L'appeler autrement ne fera qu'ajouter à la confusion, alors veuillez ne pas le faire.
Martin York
44
Au moins d'un point de vue mathématique, la troncature vers zéro équivaut à "si> 0 alors plancher sinon plafond". Je pense que l'appeler troncature est plus simple que l'appeler plancher / plafond, mais l'un ou l'autre est valide. Quoi qu'il en soit, le point de Will A est valable: la réponse de Dirkgently est partiellement incorrecte, car il a déclaré que l'OP avait raison sur le fait que le résultat était le plancher de la division.
Brian
9
@Philip Potter: Je ne pense pas que cela ait été défini en C89, et ce n'est pas dans la norme C ++ de 1998. Dans ceux-ci, il (a / b) * b + a % b == afallait bien sûr être satisfait, et la valeur absolue de a % bdevait être inférieure à a, mais que ce a % bsoit négatif pour négatif aou bnon spécifié.
David Thornley
41

Dirkgently donne une excellente description de la division entière en C99, mais vous devez également savoir que dans la division entière C89 avec un opérande négatif a une direction définie par l'implémentation.

Du projet ANSI C (3.3.5):

Si l'un des opérandes est négatif, que le résultat de l'opérateur / soit le plus grand entier inférieur au quotient algébrique ou le plus petit entier supérieur au quotient algébrique est défini par l'implémentation, tout comme le signe du résultat de l'opérateur%. Si le quotient a / b est représentable, l'expression (a / b) * b + a% b doit être égale à a.

Faites donc attention aux nombres négatifs lorsque vous êtes coincé avec un compilateur C89.

C'est un fait amusant que C99 a choisi la troncature vers zéro parce que c'est ainsi que FORTRAN l'a fait. Voir ce message sur comp.std.c.

schot
la source
2
Et le paragraphe 5 de l'avant-propos du projet N1256 de C99 mentionne reliable integer divisionune nouvelle fonctionnalité linguistique. Etonnant *-*.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
La troncature est le comportement du matériel CPU le plus courant (par exemple x86), il serait donc fou de faire un choix différent. IDK qui est venu en premier, sémantique Fortran ou comportement matériel, mais ce n'est pas un hasard si ce sont les mêmes aussi.
Peter Cordes
2
@PeterCordes: La plupart des matériels CPU courants peuvent effectuer une division par le sol par la plupart des constantes plus rapidement que la division tronquée. À mon humble avis, il aurait été préférable que la norme dise cela expr1 / expr2et expr1 % expr2doit être cohérente lorsque les deux instances de expr1combiner les mêmes objets de la même manière, et de même pour expr2, mais le choix de la troncature par rapport à la division au sol est par ailleurs non spécifié. Cela aurait permis une génération de code plus efficace sans casser beaucoup de compatibilité (et les implémentations pourraient documenter un comportement spécifique si elles étaient inclinées)
supercat
23

Lorsque le résultat est négatif, C tronque vers 0 plutôt que sur le sol - j'ai appris cette lecture sur les raisons pour lesquelles la division entière Python planifie toujours ici: Pourquoi les étages de la division entière de Python

Gareth Williams
la source
3
Je suis d'accord avec le commentaire se demandant si avoir (négatif% pos) devenir négatif est jamais utile? Sur une note connexe, je me demande si le comportement arithmétique incorrect requis dans certains cas de "unsignedvar> signedvar" est jamais utile? Je peux comprendre la raison de ne pas exiger un comportement toujours correct; Je ne vois aucune justification pour exiger un mauvais comportement.
supercat
8
+1 pour une excellente référence sur pourquoi le revêtement de sol est le comportement correct pour la division entière (contrairement à la définition de C, qui est cassée et presque jamais utile).
R .. GitHub STOP STOPINGING ICE
@supercat Considérez:, filtered = (k - 1) * filtered + value + carry; carry = filtered % factor; filtered /= factoritéré avec des valeurs changeantes de value. Il fait une belle approximation entière d'un filtre passe-bas du premier ordre avec une constante de temps k... mais il n'est symétrique que si la division est tronquée et carryobtient des valeurs négatives. Les deux comportements de division sont utiles de temps en temps.
hobbs
1
@hobbs: Je ne pense pas que le code ci-dessus se comporterait correctement lorsque les signaux franchiraient zéro. Si divest un opérateur de division au sol et qu'il factorest impair, filtered += (filter+(factor div 2)) div factorcela donnerait un comportement propre et symétrique pour toutes les valeurs jusqu'à INT_MAX-(factor div 2).
supercat
@supercat cela fonctionne bien; ce code n'est que légèrement distillé à partir de quelque chose que j'ai eu pendant un certain temps dans le contrôleur d'une horloge atomique.
Hobbs
21

Oui, le résultat est toujours tronqué vers zéro. Il arrondira vers la plus petite valeur absolue.

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

Pour les valeurs signées non signées et non négatives, c'est la même chose que floor (arrondi vers -Infinity).

Leonid
la source
43
Troncature, pas plancher.
dan04
9
@ dan04: yep floor ne serait valide que pour les entiers positifs :)
Leonid
13

Le résultat sera-t-il toujours le plancher de la division?

Non. Le résultat varie, mais la variation ne se produit que pour les valeurs négatives.

Quel est le comportement défini?

Pour le rendre clair, le sol arrondit vers l'infini négatif, tandis que la division entière arrondit vers zéro (tronque)

Pour les valeurs positives, ce sont les mêmes

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

Pour une valeur négative, c'est différent

int integerDivisionResultNegative= -125/100;//=-1
double flooringResultNegative= floor(-125.0/100.0);//=-2.0
Mohamed El-Nakib
la source
0

Je sais que les gens ont répondu à votre question, mais en termes simples:

5 / 2 = 2 // puisque 5 et 2 sont des entiers et la division des entiers tronque toujours les décimales

5.0 / 2 or 5 / 2.0 or 5.0 /2.0 = 2.5 // ici 5 ou 2 ou les deux ont des décimales donc le quotient que vous obtiendrez sera en décimal.

adi1ya
la source