¿Cuál es el comportamiento de la división entera?


211

Por ejemplo,

int result;

result = 125/100;

o

result = 43/100;

¿El resultado será siempre el piso de la división? ¿Cuál es el comportamiento definido?


55
Resumen: firmado enteros trunca división hacia cero . Para resultados no negativos, esto es lo mismo que el piso (redondeado hacia -Infinito). (Tenga en cuenta que C89 no garantiza esto, vea las respuestas.)
Peter Cordes

66
Todos siguen diciendo "truncar hacia cero" o "techo" o "piso" como si el código estuviera tomando una decisión deliberada sobre qué técnica utilizar. Si el código pudiera hablar, diría"I just throw the dam fraction part in the trash and move on with life"
Timothy LJ Stewart,

3
@ TimothyL.J.Stewart El "código" está tomando una decisión deliberada. Según la especificación, la división de enteros está destinada a ser una división T (runcation). Debido a esto, el operador de módulo / resto se implementa de manera diferente que si estuviera en otro idioma, por ejemplo, Python o Ruby. Consulte esto para obtener una lista de las diferentes formas en que los lenguajes hacen el operador de módulo y este documento que enumera al menos cinco de las formas comunes en que los lenguajes de programación deciden hacer div / modulo.
13steinj

1
@ 13steinj Estoy hablando coloquialmente por los comentarios que estaba convirtiendo en un "está truncado hacia cero ... no, es el piso ... no, si es negativo su techo ..." a veces los tecnicismos no se propagan hacia el futuro con la memoria humana como deseamos, pero sabiendo intuitivamente que la "parte de la fracción se descarta" puede derivar los puntos técnicos. Los tecnicismos son una carga pesada, pero la intuición es ligera y refrescante como el viento, los llevaré lejos y cuando sea necesario sabré por dónde empezar. Al igual que el papel que vinculó, gracias.
Timothy LJ Stewart

Respondí aquí con énfasis en la división euclidiana (interacción entre la división de enteros y el operador de módulo).
Picaud Vincent

Respuestas:


182

¿El resultado será siempre el piso de la división? ¿Cuál es el comportamiento definido?

Sí, cociente entero de los dos operandos.

6.5.5 Operadores multiplicativos

6 Cuando se dividen los enteros, el resultado del operador / es el cociente algebraico con cualquier parte fraccional descartada. 88) Si el cociente a / b es representable, la expresión (a / b) * b + a% b será igual a a.

y la nota al pie correspondiente:

88) Esto a menudo se llama "truncamiento hacia cero".

Por supuesto, dos puntos a tener en cuenta son:

3 Las conversiones aritméticas habituales se realizan en los operandos.

y:

5 El resultado del operador / es el cociente de la división del primer operando por el segundo; El resultado del% operador es el resto. En ambas operaciones, si el valor del segundo operando es cero, el comportamiento es indefinido.

[Nota: el énfasis es mío]


26
... a menos, por supuesto, que esté dividiendo un número negativo por un positivo (o vv), en cuyo caso será el techo.
Will A

74
No es ni piso ni techo, es truncamiento de una parte fraccional, ¡es conceptualmente diferente!
lornova

38
@Will A: No. Se define como truncamiento hacia cero. Llamarlo de otra manera solo aumentará la confusión, por lo que debe abstenerse de hacerlo.
Martin York

44
Al menos desde una perspectiva matemática, el truncamiento hacia cero es equivalente a "si> 0, entonces piso más techo". Creo que llamarlo truncamiento es más simple que llamarlo piso / techo, pero cualquiera de los dos es válido. En cualquier caso, el punto de Will A es válido: la respuesta de Dirkgently es parcialmente incorrecta, ya que afirmó que el OP tiene razón acerca de que el resultado es el piso de la división.
Brian

9
@Philip Potter: No creo que se haya definido en C89, y no está en el estándar C ++ de 1998. En aquellos, por supuesto, (a / b) * b + a % b == atenía que satisfacerse, y el valor absoluto de a % btenía que ser menor que a, pero si a % bera negativo para negativo ao bno se especificaba.
David Thornley

41

Dirkgently da una excelente descripción de la división de enteros en C99, pero también debe saber que en C89 la división de enteros con un operando negativo tiene una dirección definida por la implementación.

Del borrador ANSI C (3.3.5):

Si cualquiera de los operandos es negativo, si el resultado del operador / es el entero más grande menor que el cociente algebraico o el entero más pequeño mayor que el cociente algebraico está definido por la implementación, como lo es el signo del resultado del operador%. Si el cociente a / b es representable, la expresión (a / b) * b + a% b será igual a a.

Así que ten cuidado con los números negativos cuando estás atascado con un compilador C89.

Es un hecho divertido que C99 eligió el truncamiento hacia cero porque así fue como FORTRAN lo hizo. Ver este mensaje en comp.std.c.


2
Y C99 borrador N1256 prólogo párrafo 5 menciona reliable integer divisioncomo una nueva característica de lenguaje. Increíble *-*.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

El truncamiento es el comportamiento más común del hardware de la CPU (por ejemplo, x86), por lo que sería una locura tomar una decisión diferente. IDK que vino primero, la semántica de Fortran o el comportamiento del hardware, pero no es una coincidencia que también sean iguales.
Peter Cordes

2
@PeterCordes: el hardware de CPU más común podría dividir en pisos por la mayoría de las constantes más rápido de lo que podrían hacer la división truncada. En mi humilde opinión, hubiera sido mejor para el Estándar decir eso expr1 / expr2y expr1 % expr2debe ser coherente entre sí cuando ambas instancias expr1combinan los mismos objetos de la misma manera, y de la misma manera paraexpr2 , pero la elección de la división truncada en comparación con el piso no está especificada. Eso habría permitido una generación de código más eficiente sin romper mucha compatibilidad (y las implementaciones podrían documentar un comportamiento específico si está inclinado)
supercat

23

Donde el resultado es negativo, C se trunca hacia 0 en lugar de piso: aprendí esta lectura sobre por qué la división entera de Python siempre toca piso aquí: por qué los pisos de división entera de Python


3
Estoy de acuerdo con el comentario preguntándome si tener (neg% pos) ir negativo es útil alguna vez? En una nota relacionada, me pregunto si alguna vez es útil el comportamiento aritméticamente incorrecto requerido en algunos casos de "unsignedvar >ignedvar". Puedo entender las razones para no requerir un comportamiento siempre correcto; No veo ninguna razón para exigir un comportamiento incorrecto.
supercat

8
+1 para una excelente referencia sobre por qué el piso es el comportamiento correcto para la división de enteros (contrario a la definición de C, que está rota y casi nunca es útil).
R .. GitHub DEJA DE AYUDAR AL HIELO

@supercat Considere: filtered = (k - 1) * filtered + value + carry; carry = filtered % factor; filtered /= factoriterado con valores cambiantes de value. Hace una buena aproximación entera a un filtro de paso bajo de primer orden con constante de tiempo k... pero solo es simétrico si la división se trunca y carryobtiene valores negativos. Ambos comportamientos para la división son útiles de vez en cuando.
hobbs

1
@hobbs: No creo que el código anterior se comportaría limpiamente cuando las señales cruzan cero. Si dives un operador de división con piso y factores extraño, filtered += (filter+(factor div 2)) div factorproduciría un comportamiento limpio y simétrico para todos los valores hasta INT_MAX-(factor div 2).
supercat

@supercat sí funciona; ese código solo está ligeramente destilado de algo que he estado ejecutando en el controlador de un reloj atómico durante un tiempo.
hobbs

21

Sí, el resultado siempre se trunca hacia cero. Se redondeará hacia el valor absoluto más pequeño.

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

Para valores con signo sin signo y sin signo negativo, esto es lo mismo que floor (redondeando hacia -Infinity).


43
Truncamiento, no piso.
dan04

9
@ dan04: el piso sí sería válido solo para enteros positivos :)
Leonid el

13

¿El resultado será siempre el piso de la división?

No. El resultado varía, pero la variación ocurre solo para valores negativos.

¿Cuál es el comportamiento definido?

Para que quede claro, el piso se redondea hacia el infinito negativo, mientras que la división entera se redondea hacia cero (trunca)

Para valores positivos son iguales

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

Para valor negativo esto es diferente

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

0

Sé que la gente ha respondido tu pregunta, pero en términos simples:

5 / 2 = 2 // ya que 5 y 2 son enteros y la división de enteros siempre trunca los decimales

5.0 / 2 or 5 / 2.0 or 5.0 /2.0 = 2.5 // aquí 5 o 2 o ambos tienen decimal, por lo tanto, el cociente que obtendrás estará en decimal.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.