Nombres, operadors i conversions
Aquesta entrada se centra en els tipus numèrics bàsics de Python: enters (int), flotants (float), algunes funcions relacionades, operadors i conversions. No veurem encara decimal ni fractions però esmentarem en quins casos els podem necessitar.
Tipus numèrics principals en Python
int: enters
Els valors enters a Python no tenen un límit fix (com passava a C o Java amb int32 o int64). En principi, pots representar qualsevol nombre enter, positiu o negatiu, amb l’única limitació de la memòria disponible:
x = 42
y = -100
z = 10**100 # Un enter enorme
Python canvia internament de representació quan els enters creixen, però tu no has de fer res. Aquest comportament és molt útil en criptografia, finances o algoritmes matemàtics on es treballa amb enters grans.
float: números de coma flotant
Un float a Python és un número en notació decimal, que internament es representa com a doble precisió IEEE-754, igual que en la majoria dels llenguatges moderns.
a = 3.14
b = -0.00001
c = 1.0e6
El límit està en la precisió: un float representa números reals de forma aproximada. El més important és que no tots els decimals es poden representar exactament, i això genera errors comuns:
>>> 0.1 + 0.2
0.30000000000000004
No és un bug, és com funciona l’aritmètica binària amb decimals. No tots els números que s’ escriuen amb precisió decimal tenen una representació exacta en binari flotant.
Literals numèrics
Pots escriure números de diverses formes:
42 # decimal
0b1010 # binari
0o52 # octal
0x2A # hexadecimal
1.5e3 # notació científica (1500.0)
Les lletres e o E indiquen notació exponencial en els float. No confondre amb **, que és l’operador de potència.
Operadors numèrics
Python té els operadors estàndard per treballar amb números. Hi ha alguns detalls que convé tenir clars.
Aritmètica bàsica
| Operador | Significat | Exemple |
| + | Suma | 2 + 3 |
| – | Resta | 4 – 1 |
| * | Multiplicació | 2 * 5 |
| / | Divisió (float) | 5 / 2 → 2.5 |
| // | Divisió entera | 5 // 2 → 2 |
| % | Mòdul | 5 % 2 → 1 |
| ** | Potència | 2 ** 3 → 8 |
Python distingeix entre / i //. Aquesta diferència importa molt, sobretot si vens de C o JavaScript.
>>> 5 / 2
2.5
>>> 5 // 2
2
>>> -5 // 2
-3 # arrodoneix cap avall, no cap a zero
Aquesta última línia sol confondre. Python arrodoneix la divisió sencera cap al nombre més petit, no cap a zero. És coherent amb la definició matemàtica del pis (floor division), però no tots els llenguatges ho fan així.
Operadors bit a bit (només per a enters)
Aquests operadors només funcionen amb int i es fan servir més del que sembla: en sistemes embeguts, programació de baix nivell, estructures compactes, etc.
| Operador | Nom | Exemple |
| & | AND bit a bit | 5 & 3 → 1 |
| ` | ` | OR bit a bit |
| ^ | XOR | 5 ^ 3 → 6 |
| ~ | NOT bit a bit | ~5 → -6 |
| << | Desplaçament a l’ esquerra | 1 << 3 → 8 |
| >> | Desplaçament a la dreta | 8 >> 2 → 2 |
Aquests operadors no converteixen tipus. Si fas 5 & 3.0 et retorna un TypeError.
Precedència d’ operadors
A la pràctica, molts errors venen d’assumir que Python avalua d’esquerra a dreta, sense tenir en compte la precedència d’operadors.
Aquí va un resum parcial (de major a menor precedència):
- **
- -x, +x, ~x (unaris)
- *, /, //, %
- +, –
- <<, >>
- &
- ^
- |
- Comparacions (<, >, ==, etc.)
- not
- and
- or
Exemple:
>>> 2 + 3 * 4
14 # no 20: * té més precedència
>>> -2 ** 2
-4 # perquè s'avalua com a -(2 ** 2), no com a (-2) ** 2
>>> (1 << 2) + 1
5
No cal memoritzar aquesta llista, però sí tenir en compte que l’ordre importa. Quan hi hagi dubtes, fes servir parèntesis.
Conversió de tipus (càsting)
Python permet convertir entre tipus numèrics explícitament amb funcions:
int(3.9) # 3
float(5) # 5.0
int("42") # 42
float("1e-3") # 0.001
No hi ha conversió implícita en expressions com aquesta:
int("3.5") # ValueError
Per convertir una cadena amb punt decimal a enter, cal fer doble pas:
int(float("3.5")) # 3
La conversió implícita sí que passa en operacions mixtes:
>>> 3 + 2.0
5.0 # el resultat es promou a float
Aquesta promoció a float és automàtica si qualsevol dels operands ho és. Això pot generar errors subtils si estàs treballant amb enters grans i esperes que el resultat es mantingui exacte.
Comparacions i tipus mixtos
Python permet comparar tipus numèrics diferents:
>>> 3 == 3.0
True
>>> 3 < 3.1
True
Això funciona perquè int i float estan pensats per a interoperar. Tanmateix, amb altres tipus numèrics com Decimal, el resultat pot ser diferent:
from decimal import Decimal
>>> Decimal('3.0') == 3
False # Tipus diferents, semàntica diferent
Per a evitar sorpreses, convé mantenir els tipus alineats en operacions crítiques, especialment en càlculs financers.
Arrodoniment i truncament
Python ofereix diverses formes d’arrodonir o truncar valors:
round(3.14159, 2) # 3.14
int(3.9) # 3 (truncament)
math.floor(3.9) # 3
math.ceil(3.1) # 4
La funció round té un comportament una mica diferent a l’esperat quan hi ha empats:
round(2.5) # 2
round(3.5) # 4
Esto se llama round half to even, o arrodoniment “a parell”. Es l’arrodoniment per defecte a Python (i a IEEE-754), perquè evita biaixos sistemàtics en sumar molts números.
Nombres negatius i mòdul
L’operació a % b a Python sempre retorna un resultat del mateix signe que el divisor:
>>> -7 % 3
2 # perquè -7 = (-3 * 3) + 2
Això pot xocar si véns de llenguatges on el signe del resultat segueix al dividend. Convé provar casos amb negatius si estàs treballant amb cicles, calendaris o divisions modulars.
Què passa amb els errors de precisió
Ja vam veure el cas clàssic:
>>> 0.1 + 0.2 == 0.3
False
Llavors què es fa si necessites comparar flotants?
Es fan servir comparacions amb tolerància:
import math
math.isclose(0.1 + 0.2, 0.3, rel_tol=1e-9)
En càlculs crítics, no facis servir == amb floats. Fes servir math.isclose o, millor, fes servir decimal. Decimal si necessites precisió decimal exacta (per exemple, per a facturació).
Errors típics en treballar amb números a Python
1. Assumir que int() arrodoneix
>>> int(3.9)
3
Això no arrodoneix: trunca cap a zero. Si necessites arrodonir, fes servir round():
>>> round(3.9)
4
>>> round(-3.9)
-4
I si necessites truncar explícitament cap avall o cap amunt:
import math
math.floor(3.9) # 3
math.ceil(3.9) # 4
math.trunc(3.9) # 3
2. Comparar floats amb ==
Com ja hem esmentat, fer servir == amb flotants és problemàtic:
>>> 0.1 + 0.2 == 0.3
False
El correcte:
math.isclose(0.1 + 0.2, 0.3, rel_tol=1e-9)
I si el número és molt petit, és millor fer servir abs_tol:
math.isclose(1e-10, 0.0, abs_tol=1e-12)
3. Fer servir float per a càlculs financers
Evita-ho, llevat que els muntants siguin irrellevants. Fes servir decimal. Decimal:
from decimal import Decimal
Decimal('0.1') + Decimal('0.2') == Decimal('0.3') # True
Això et dona resultats exactes i configurables.
Funcions útils al mòdul math
Python inclou funcions matemàtiques bàsiques en el mòdul math, totes per a float:
import math
math.sqrt(16) # 4.0
math.sin(math.pi) # quasi 0.0
math.log(100, 10) # 2.0
math.exp(1) # e ≈ 2.718
math.isfinite(x)
math.isnan(x)
math.isinf(x)
Tots els resultats són de tipus float. math no serveix per a enters grans ni per a treballar amb Decimal (per això hi ha el mòdul decimal, que té la seva pròpia API).
Alguns comportaments poc intuïtius
Divisió entera amb números negatius
Ja ho vam veure, però val la pena repetir-ho perquè causa errors lògics:
>>> -5 // 2
-3
>>> -5 % 2
1
Perquè (-3 * 2) + 1 = -5. El resultat de % sempre té el mateix signe que el divisor.
Potències negatives amb enters
>>> 2 ** -3
0.125
El resultat és float, encara que el número base sigui enter. Això importa si estàs esperant int en una funció.
Com es comporten int() i float() amb cadenes?
Depèn de la cadena:
>>> int("42")
42
>>> float("3.14")
3.14
>>> int("3.14")
ValueError
No pots convertir directament “3.14” a int. Cal passar per float() primer.
També has d’evitar confiar en entrades d’usuari sense validació:
try:
x = int(input("Número: "))
except ValueError:
print("Això no és un sencer vàlid.")
Com detectar el tipus de número que estàs fent servir
Python no distingeix visualment entre 3 i 3.0 en molts casos, però pots verificar amb type() o isinstance():
type(3) # <class 'int'>
type(3.0) # <class 'float'>
isinstance(3, int) # True
isinstance(3.0, float) # True
Això és útil quan reps arguments que poden ser de diferents tipus i necessites tractar-los diferent.
Quin tipus de nombre s’ obté en operacions mixtes
Python promou automàticament al tipus de major precisió:
| Operant 1 | Operant 2 | Resultat |
| int | int | int |
| int | float | float |
| float | float | float |
>>> type(2 + 3.0)
<class 'float'>
La promoció passa fins i tot si el resultat podria representar-se com a int. Si necessites mantenir sencers exactes, assegura’t de no barrejar tipus sense voler.
Què passa amb valors especials: NaN, inf, -inf?
Pots generar-los així:
float('inf')
float('-inf')
float('nan')
I comparar-los:
math.isinf(float('inf')) # True
math.isnan(float('nan')) # True
Però compte:
>>> float('nan') == float('nan')
False
Això és per definició: NaN no és igual a res, ni tan sols a si mateix. Per a detectar-ho, sempre fes servir math.isnan().
Exemple pràctic: mitjana d’ una llista mixta
Vegem un cas real: calcular la mitjana d’una llista que pot contenir sencers i flotants, i gestionar el cas buit.
def promedio(llista):
if not llista:
return None
total = sum(llista)
quantitat = len(llista)
return total / cantidad
promedi([1, 2, 3]) # 2.0
promediquantitat([1.0, 2, 3.5]) # 2.166...
promedi([]) # None
El resultat és sempre float, perquè la divisió amb / el força. Si vols que sigui int si tots els valors ho són i el resultat és exacte, necessites més lògica, però rarament convé complicar-ho.
Què convé recordar de tot això
- int en Python no té límit fix, però float sí que té precisió limitada.
- arrodoneix cap avall, no cap a zero.
- % retorna el residu amb el signe del divisor.
- No compares float amb == si pots evitar-ho.
- No fas servir float per a diners.
- Usa math.isclose() si necessites comparar amb tolerància.
- Les operacions amb tipus mixtos promouen el tipus de major precisió.
- El resultat d’int() trunca, no arrodoneix.
I si necessito més precisió o comportament exacte?
Llavors no facis servir float. Python té altres dues opcions:
- decimal. Decimal: per a càlculs exactes amb decimals, configurable, ideal per a diners o càlculs comptables.
- fractions. Fraction: per a fraccions exactes, com 1/3, 5/7, etc.
Aquestes no es cobreixen en aquesta entrada, però formen part de l’ecosistema estàndard i val la pena explorar-les si la teva aplicació depèn de càlculs precisos.

