En Python, ¿cuál es una buena manera de redondear hacia cero en la división entera?

1/2 

da

 0 

como debería. Sin embargo,

 -1/2 

da

 -1 

, pero quiero que se redondee hacia 0 (es decir, quiero que -1/2 sea 0), independientemente de si es positivo o negativo. ¿Cuál es la mejor manera de hacer eso?

Hacer división de punto flotante y luego convertir a un int. No se necesitan módulos adicionales.

 >>> int(float(-1)/2) 0 >>> int(float(-3)/2) -1 >>> int(float(1)/2) 0 >>> int(float(3)/2) 1 

La división predeterminada de enteros de Python es devolver el piso (hacia el infinito negativo) sin capacidad de cambiar eso. Puedes leer el motivo de la BDFL.

Para hacer la división ‘redondear’, usarías:

 >>> a=1 >>> b=2 >>> (a+(-a%b))//b 1 >>> a,b=-1,2 >>> (a+(-a%b))//b 0 

Para realizar el truncamiento hacia cero y mantener la división de enteros, use (a+(-a%b))//b si a o b son negativos y la división predeterminada si ambos son positivos.

Esto hará división entera y siempre redondeará hacia cero:

 >>> a=1 >>> b=2 >>> a//b if a*b>0 else (a+(-a%b))//b 0 >>> a=-1 >>> b=2 >>> a//b if a*b>0 else (a+(-a%b))//b 0 >>> a,b=-3,2 >>> a//b if a*b>0 else (a+(-a%b))//b -1 >>> a,b=3,2 >>> a//b if a*b>0 else (a+(-a%b))//b 1 

nota

Curiosamente, C99 declara que la ronda hacia cero es el valor predeterminado:

 #include  int main(int argc, const char * argv[]) { int a=-3; int b=2; printf("a=%d, b=%d, a/b=%d\n",a,b,a/b); a=3; printf("a=%d, b=%d, a/b=%d\n",a,b,a/b); return 0; } 

Huellas dactilares:

 a=-3, b=2, a/b=-1 a=3, b=2, a/b=1 

Por lo que vale, mi solución favorita es esta. Solo aritmética de enteros, una sola división y todo lo demás tiempo lineal:

 def integer_divide_towards_zero(a, b): return -(-a // b) if a < 0 else a // b 

Eso supone que b es positivo, pero en la mayoría de las aplicaciones que he visto es cierto. Si también necesita lidiar con la b negativa, entonces la función se vuelve un poco más complicada:

 def integer_divide_towards_zero(a, b): return -(-a // b) if (a < 0) ^ (b < 0) else a // b 

Algunas salidas de muestra:

 >>> integer_divide_towards_zero(11, 3) 3 >>> integer_divide_towards_zero(-11, 3) -3 >>> integer_divide_towards_zero(6, 3) 2 >>> integer_divide_towards_zero(-6, 3) -2 >>> integer_divide_towards_zero(11, -3) -3 >>> integer_divide_towards_zero(-11, -3) 3 

Prueba esto. Solo funciona para números mayores que -1

 import math x = .5 y = -.5 print math.floor(math.fabs(x)) >> 0 print math.floor(math.fabs(y)) >> 0 

El código correcto para hacer esto es, en mi opinión, demasiado oscuro para escribir como 1-liner. Así que lo pondría en una función, como:

 def int0div(a, b): q = a // b if q < 0 and b*q != a: q += 1 return q 

Buenas características: funciona para cualquier tamaño de int, no hace ningún ajuste al resultado en bruto ( a//b ) a menos que sea necesario, solo hace una división ( % también hace una división debajo de las coberturas) y no crea cualquier número entero mayor que las entradas. Esos pueden o no pueden importar en su aplicación; se vuelven más importantes (para la velocidad) si usas números enteros "grandes".

Lanzar mi sombrero con algunas ideas alternativas:

Múltiple el signo del número [abs (x) / x] por el abs (x) / 2

 (abs(x)/x)*(abs(x)/2) 

Realice la sum, pero si el número es menor que cero, agregue uno para desplazarlo más cerca de 0.

 x/2 + int(x<0) 

También puede usar el módulo decimal como parte de las bibliotecas de python estándar.

Específicamente, “El operador de división de enteros // se comporta de manera análoga, devolviendo la parte entera del cociente verdadero (truncando hacia cero) en lugar de su piso, para preservar la identidad habitual x == (x // y) * y + x % y: ”

 >>> -7 // 4 -2 >>> Decimal(-7) // Decimal(4) Decimal('-1') 

Además, eche un vistazo a los modos de redondeo, ya que tienen varias formas de ver / redondear su información: techo, abajo, piso, mitad abajo, mitad par, mitad arriba, arriba y arriba.

Decimal fue escrito como una solución al problema tradicional de las matemáticas binarias en un mundo que esperaba soluciones decimales.