Python tiene siete operadores aritméticos básicos y cada uno esconde al menos una decisión de diseño que te va a sorprender si vienes de C, JavaScript o Java. Vamos a verlos todos, pero prestando atención a los detalles que realmente importan.
El más llamativo es la distinción entre / y //. En Python 3, la división / siempre devuelve un float, sin excepción: 10 / 2 no es 5, es 5.0. Esto fue un cambio deliberado respecto a Python 2, donde / entre enteros hacía división entera y causaba bugs silenciosos constantísimos (el clásico 1/2 == 0). La floor division //, en cambio, redondea hacia menos infinito —no hacia cero— y devuelve int si ambos operandos son enteros, o float si alguno lo es. Esa matización de “hacia menos infinito” es importante: -7 // 2 da -4, no -3.
El operador % (módulo) sigue la misma lógica de “hacia menos infinito”, lo que lo hace diferente al % de C. En Python, el resultado siempre tiene el mismo signo que el divisor. En C, tiene el mismo signo que el dividendo. Esto afecta directamente a cualquier cálculo con negativos: -7 % 3 en Python es 2, en C sería -1. Cuando escribas código que sea consciente del signo, eso importa.
Para exponenciación tienes ** y math.pow(). Son distintos en tipo de retorno: 2 ** 10 devuelve un int (1024), pero math.pow(2, 10) devuelve siempre un float (1024.0) porque internamente delega a la función pow() de C, que opera sobre double. Si necesitas potencias de enteros y quieres conservar precisión arbitraria (Python tiene enteros de tamaño ilimitado), usa **. Si estás en un contexto numérico con float de todos modos, ambos funcionan igual de bien.
La precedencia de operadores sigue el orden clásico: ** primero, luego *, /, //, %, y por último + y -. Pero la regla práctica es más simple: si hay cualquier duda —o si el lector tiene que pensar dos segundos para entender el orden— pon paréntesis. No para el intérprete, sino para quien lee el código en seis meses.
import math # División: / siempre da float, // hace floor division print(10 / 3) # 3.3333333333333335 print(10 // 3) # 3 print(10.0 // 3) # 3.0 → float porque el operando lo es # Floor division con negativos: redondea hacia -∞, no hacia cero print(-7 // 2) # -4 (no -3) print(7 // -2) # -4 # Módulo: el resultado tiene el signo del divisor print(-7 % 3) # 2 → en C sería -1 print(7 % -3) # -2 # ** conserva enteros; math.pow() siempre devuelve float big_int = 2 ** 100 print(type(big_int)) # <class 'int'> print(type(math.pow(2, 100))) # <class 'float'> # math.pow tiene límites de precisión porque usa double de C print(2 ** 53 + 1) # 9007199254740993 (exacto) print(math.pow(2, 53) + 1) # 9007199254740992.0 (pierde el +1) # Precedencia: estos dos producen resultados diferentes sin_parentesis = 2 + 3 * 4 ** 2 # 2 + 3 * 16 = 2 + 48 = 50 con_parentesis = (2 + 3) * (4 ** 2) # 5 * 16 = 80 # Los paréntesis aquí no cambian el resultado, pero sí la legibilidad precio_con_iva = precio_base * (1 + tasa_iva) # intención clara precio_con_iva_2 = precio_base + precio_base * tasa_iva # misma aritmética, más ruido precio_base = 100 tasa_iva = 0.21 print(precio_base * (1 + tasa_iva)) # 121.0
Desglose del código
La primera sección deja claro que // no es simplemente “división entera”: es floor division, que redondea hacia el entero más pequeño, no hacia cero. 10.0 // 3 demuestra que el tipo del resultado depende de los operandos, no del operador en sí.
Los ejemplos con negativos son donde la gente se quema. -7 // 2 da -4 porque el floor de -3.5 es -4. El módulo sigue coherentemente: si a = (a // b) * b + (a % b), entonces -7 = (-4) * 2 + 2, que verifica. Python garantiza esa identidad para cualquier combinación de signos.
La comparación de 2 ** 53 + 1 vs math.pow(2, 53) + 1 es el argumento más concreto para elegir ** cuando trabajas con enteros grandes. Los float de Python (IEEE 754 de 64 bits) tienen 53 bits de mantisa; a partir de ahí pierdes precisión. Los int de Python no tienen ese límite.
Los últimos dos ejemplos de precio_con_iva ilustran por qué los paréntesis explícitos mejoran la legibilidad aunque sean redundantes: la intención de “base más porcentaje” se lee directamente en base * (1 + tasa), sin necesidad de reconstruir la aritmética mentalmente.
Errores que debes conocer
Error: Asumir que // trunca hacia cero, como el cast a int en C o Java.
# ❌ Incorrecto — esperas -3, obtienes -4 resultado = -7 // 2 print(resultado) # -4 # ✅ Si necesitas truncar hacia cero, usa int() resultado = int(-7 / 2) print(resultado) # -3
int() sobre un float sí trunca hacia cero; // no lo hace.
Error: Usar math.pow() para potencias enteras grandes y perder precisión silenciosamente.
# ❌ Pierde el bit menos significativo print(math.pow(2, 53) + 1) # 9007199254740992.0 ← mal # ✅ ** trabaja con precisión arbitraria print(2 ** 53 + 1) # 9007199254740993 ← correcto
El problema no es visible con números pequeños, lo que lo hace especialmente traicionero en código criptográfico o en cálculos con identificadores grandes.
Error: Confundir el signo del módulo cuando una de las operandos es negativa, especialmente al portear código desde C o JavaScript.
# ❌ Expectativa de alguien que viene de C print(-7 % 3) # Espera -1, Python devuelve 2 # ✅ Para comportamiento tipo-C (signo del dividendo), usa math.fmod import math print(math.fmod(-7, 3)) # -1.0
math.fmod() replica la semántica de C; úsala si necesitas exactamente eso, pero ten en cuenta que devuelve float.
N° 24