Estaba averiguando cómo hacer operaciones de piso/techo sin el módulo math . Resolví esto usando la división de piso // , y descubrí que el negativo "da el techo". Así que esto funciona:
>>> 3//2 1 >>> -3//2 -2 Me gustaría que la respuesta fuera positiva, así que primero probé --3//2 , pero da 1. Inferí que esto se debe a que Python evalúa -- como + . Entonces, para resolver esto, descubrí que podía usar -(-3//2)) , problema resuelto.
Pero encontré otra solución para esto, a saber (incluí el ejemplo anterior para comparar):
>>> --3//2 # Does not give ceiling 1 >>> 0--3//2 # Does give ceiling 2No puedo explicar por qué incluir el 0 ayuda. He leído la documentación sobre la división, pero no encontré ninguna ayuda allí. Pensé que podría ser debido al orden de evaluación:
Si uso --3//2 como ejemplo, de la documentación tengo que Positive, negative, bitwise NOT es más estricto en este ejemplo, y supongo que esto evalúa -- a + . Luego viene Multiplication, division, remainder , así que supongo que esto es +3//2 que se evalúa como 1 , y hemos terminado. No puedo deducir de la documentación por qué incluir 0 debería cambiar el resultado.
Referencias:
Python usa el símbolo - como operador unario ( -x ) y binario ( xy ). Estos tienen diferenteprecedencia de operadores .
En específico, el pedido wrt // es:
-//- Al introducir un 0 como 0--3//2 , el primero - es un binario - y se aplica en último lugar. Sin un 0 inicial como --3//2 , ambos - son unarios y se aplican juntos.
El árbol de evaluación/sintaxis correspondiente es más o menos así, evaluando los nodos en la parte inferior primero para usarlos en el nodo principal:
---------------- ---------------- | --3//2 | 0--3//2 | |================|================| | | ------- | | | | 0 - z | | | | -----+- | | | | | | -------- | ----+--- | | | x // y | | | x // y | | | -+----+- | -+----+- | | | | | | | | | ----+ +-- | ---+ +-- | | | --3 | | 2 | | | -3 | | 2 | | | ----- --- | ---- --- | ---------------- ---------------- Debido a que los unarios - se aplican juntos, se anulan. En cambio, el unario y el binario - se aplican antes y después de la división, respectivamente.
Esta es una simple cuestión de orden de las operaciones.
--3//2 es lo mismo que (-(-3)) // 2 . Como no hay nada en el lado izquierdo, cada - debe ser una negación unaria; y esto tiene mayor precedencia que // ; entonces 3 se niega dos veces (dando 3) y luego se divide por 2.
0--3//2 es lo mismo que 0 - ((-3) // 2) . Ahora que hay algo en el lado izquierdo - el primero debe ser una resta binaria, que tiene una precedencia menor que // . El segundo - sigue siendo una negación unaria; -3 se divide por 2 dando como resultado -2 , y luego ese valor se resta de 0 .
Otra forma de saber cómo calcula realmente CPython es usar el módulo dis para ver qué hace realmente con su máquina de pila.
>>> import dis >>> dis.dis('0--3//2') 1 0 LOAD_CONST 0 (2) 2 RETURN_VALUEVaya, las constantes se calculan durante la compilación, así que usa un nombre.
>>> t=3 >>> dis.dis('0--t//2') 1 0 LOAD_CONST 0 (0) 2 LOAD_NAME 0 (t) 4 UNARY_NEGATIVE 6 LOAD_CONST 1 (2) 8 BINARY_FLOOR_DIVIDE 10 BINARY_SUBTRACT 12 RETURN_VALUE