Python: Numeri

Numeri: Tipi Fondamentali

Ci sono tre tipi numerici fondamentali:

Tipo Significato
int Rappresenta numeri interi (!)
float Rappresenta numeri razionali a virgola mobile (float ing-point)
bool Rappresenta condizioni, puo’ essere True o False

Note

I razionali float hanno precisione limitata: la maggior parte dei razionali puo’ essere rappresentata solo approssimatamente con un float.

Ai fini di questo corso, i dettagli non sono importanti.


Esempio. Creo tre variabili, una per tipo, poi le stampo a schermo con print:

n = 10
x = 3.14
cond = False

# Stampo le tre variabili
print(n, x, cond)

# Idem, inframezzando testo
print("n =", n, "x =", x, "e la condizione cond vale", cond)

Questa sintassi di print vale per tutti i tipi di variabili, non solo quelli numerici.


Numeri: Aritmetica

Tutti i tipi numerici mettono a disposizione le stesse operazioni aritmetiche:

Operazione Significato
a + b somma
a - b differenza
a * b prodotto
a / b divisione
a // b divisione intera
a % b resto della divisione (o modulo)
a ** b elevamento a potenza

Il tipo del risultato di n operazione m e’ automaticamente il tipo piu’ “complesso” tra i tipi di n e m – per questo si parla di conversione automatica.

La scala di complessita’ dei tipi numerici e’:

bool < int < float

Esempio. Ad esempio, se sommo un int ed un float, otterro’ un float:

risultato = 1.2 + 1             # float * int
print(risultato)                # 1.2
print(type(risultato))          # float

Questo perche’ e’ necessario un float per rappresentare il valore 1.2: un int non basterebbe!

Warning

Per evitare errori, e’ necessario scegliere il tipo delle variabili in modo che il tipo del risultato sia sufficientemente “complesso” da riuscire a rappresentarne il valore.


Numeri: Confronti

Tutti i tipi numerici (e in generale tutto i tipi Python che vedremo durante il corso) supportano le operazioni di comparazione:

Operazione Significato
a == b uguale
a != b diverso
a < b minore
a <= b minore o uguale
a > b maggiore
a >= b maggiore o uguale

Il risultato di un’espressione di confronto e’ sempre un bool: vale True se la condizione e’ soddisfatta, e False altrimenti.


Esempio. Aritmetica e confronti possono essere combinati per verificare condizioni “complesse”, come questa:

na, nc, ng, nt = 2, 6, 50, 4

risultato = (na + nt) > (nc + ng)
print(risultato)
print(type(risultato))

I valori Booleani bool (es. i risultati delle operazioni di confronto) possono essere combinati attraverso le operazioni logiche:

Operazione Significato
a and b congiunzione: True se e solo se a e b sono True
a or b disgiunzione: True se almeno una tra a e b e’ True
not a negazione: True se a e’ False e viceversa

Qui sia a che b sono dei bool.

Warning

In generale, fare aritmetica (es. somme) con valori Booleani e costruire espressioni logiche con valori interi o razionali e’ sconsigliato.

In questi casi, Python si comporta in modo (deterministico e spiegabile, ma decisamente) bizzarro.


Esempio. x > 12 e x < 34 danno come risultato dei bool, quindi le posso combinare per ottenere:

#     int          int
#      |            |
print((x > 12) and (x < 34))
#     \______/     \______/
#       bool         bool
#     \___________________/
#             bool

oppure:

#          int          int
#           |            |
print((not (x > 12)) or (x < 34))
#          \______/
#            bool
#     \____________/    \______/
#          bool           bool
#     \________________________/
#                bool

Esempi

Esempio. Calcolo gli zeri dell’equazione quadratica x^2 - 1 = 0:

a, b, c = 1.0, 0.0, -1.0

delta = b**2 - 4*a*c

zero1 = (-b + delta**0.5) / (2 * a)
zero2 = (-b - delta**0.5) / (2 * a)

print(zero1, zero2)

Qui uso x**0.5 per calcolare la radice quadrata: \sqrt{x} = x^\frac{1}{2}.


Esempio. Voglio calcolare il GC-content di un gene. So che il gene:

  • E’ lungo 1521 basi.
  • Contiene 316 citosine.
  • Contiene 235 guanine.

Simbolicamente, il GC-content e’ definito come (g + c) / n. Per calcolarlo posso scrivere:

n, c, g = 1521, 316, 235

gc_content = (c + g) / n
print(gc_content)

Esempio. Per controllare che x (il cui valore e’ “fuori dal mio controllo”, ma nell’esempio sotto fisso per convenienza) cada nell’intervallo A = [10,50] scrivo:

x = 17 # ad esempio

minimo_a, massimo_a, x = 10, 50

dentro_a = (minimo_a <= x <= massimo_a)
print(dentro_a)

oppure:

dentro_a = ((x >= minimo_a) and (x <= massimo_a))

Assumendo che dentro_a, dentro_b e dentro_c indichino che x e’ nell’intervallo A, B o C, rispettivamente, posso comporre condizioni piu’ complesse:

# x e' in almeno uno dei tre intervalli
dentro_almeno_uno = dentro_a or dentro_b or dentro_c

# x e' sia in A e B, ma non in C
dentro_a_e_b_ma_non_c = dentro_a and dentro_b and (not dentro_c)

Esercizi

  1. Creare alcune variabili, controllando ad ogni passaggio che valore e tipo siano corretti (usando print e type):

    1. a e b con valore 12 e 23 come interi.
    2. x e y con valore 21 e 14 come razionali.
  2. Usando print (una sola volta), stampare:

    1. Tutte le variabili di cui sopra sulla stessa riga.
    2. Tutte le variabili di cui sopra, separate da ;, sulla stessa riga.
    3. Il testo “il prodotto di a e b e’ a * b”, sostituendo ad a, b e a * b i valori delle variabili.
  3. Determinare valore e tipo di:

    1. Il prodotto di a e b.
    2. Il quoziente di x e y.
    3. Il quoziente intero di a e b.
    4. Il quoziente intero di x e y.
    5. Il prodotto di b e y.
    6. 2 elevato a 0.
    7. 2 elevato a 1.2.
    8. 2 elevato a -2.
    9. La radice quadrata di 4.
    10. La radice quadrata di 2.
  4. Che differenza c’e’ tra:

    1. 10 / 12
    2. 10 / 12.0
    3. 10 // 12
    4. 10 // 12.0
  5. Che differenza c’e’ tra:

    1. 10 % 3
    2. 10 % 3.0
  6. Usando pi = 3.141592 e dato r = 2.5, calcolare:

    1. La circonferenza di raggio r: 2 \pi r.
    2. L’area di un cerchio di raggio r: \pi r^2.
    3. Il volume di una sfera di raggio r: \frac{4}{3} \pi r^3.
  7. Creare due variabili a = 100 e b = True. Usando un numero opportuno di variabili ausiliarie (chiamatele come volete!), fate in modo che il valore di a finisca in b e che quello di b finisca in a.

    (Scrivere a = True e b = 100 non vale!)

    Si puo’ fare con una sola variabile ausiliaria?

  8. Sullo stesso strand di DNA si trovano due geni. Il primo include i nucelotidi dalla posizione 10 alla posizione 20, il secondo quelli dalla posizione 30 alla posizione 40. Scriviamo queste informazioni cosi’:

    gene1_inizio, gene1_fine = 10, 20
    gene2_inizio, gene2_fine = 30, 40
    

    Data una variabile pos che rappresenta una posizione arbitraria sullo strand, scrivere dei confronti per verificare se:

    1. pos si trova nel primo gene.
    2. pos si trova nel secondo gene.
    3. pos si trova tra l’inizio del primo gene e la fine del secondo.
    4. pos si trova tra l’inizio del primo gene e la fine del secondo, ma in nessuno dei due geni.
    5. pos si trova prima dell’inizio del primo gene o dopo la fine del secondo.
    6. pos cade in uno dei due geni.
    7. pos non dista piu’ di 10 dall’inizio del primo gene.
  9. Date le tre variabili Booleane t, u, e v, scrivere delle espressioni che valgono True se e solo se:

    1. t, u, v tutte e tre vere.
    2. t e’ vera oppure u e’ vera, ma non entrambe.
    3. Esattamente una delle tre variabili e’ falsa.
    4. Esattamente una delle tre variabili e’ vera.

Soluzioni

  1. Soluzioni:

    a = 12
    b = 23
    print(a, b)
    print(type(a), type(b))          # int, int
    
    x = 21.0
    y = 14.
    print(x, y)
    print(type(x), type(y))          # float, float
    
  2. Soluzioni:

    print(a, b, x, y)
    
    print(a, ";", b, ";", x, ";", ...)
    
  3. Soluzioni:

    # casi semplici:
    
    prodotto = a * b                # int * int
    print(prodotto)
    print(type(prodotto))           # int
    
    # divisione e divisione intera tra vari
    # tipi di numeri:
    
    quoziente = x / y               # float / float
    print(quoziente)
    print(type(quoziente))          # float
    
    risultato = a // b              # int // int
    print(risultato)
    print(type(risultato))          # int
    
    risultato = x // y              # float // float
    print(risultato)
    print(type(risultato))          # float
    
    risultato = b * y               # int * float
    print(risultato)
    print(type(risultato))          # float
    
    # qui il tipo e' determinato automaticamente
    # in base alla magnitudine del risultato:
    
    risultato = 2**0                # int**int
    print(risultato)
    print(type(risultato))          # int
    
    risultato = 2**1.2              # int*float
    print(risultato)
    print(type(risultato))          # float
    
    risultato = 2**-2               # int*int
    print(risultato)
    print(type(risultato))          # *** float!!! ***
    
    risultato = 4**0.5              # int*float
    print(risultato)
    print(type(risultato))          # float
    
    risultato = 2**0.5              # int*float
    print(risultato)
    print(type(risultato))          # float
    
  4. Soluzioni:

    >>> print(10 / 12)
    0.8333333333333334
    >>> print(10 / 12.0)
    0.8333333333333334
    >>> print(10 // 12)
    0
    >>> print(10 // 12.0)
    0.0
    

    Come si vede la divisione intera si comporta normalmente rispetto ai tipi: quando la applico ai due float il risultato e’ quello della divisione normale, ma troncato all’intero 0.

  5. Soluzioni:

    >>> 10 % 3
    1
    >>> 10 % 3.0
    1.0
    

    Come si puo’ vedere, % ritorna il resto di 10 / 3:

    10 = 3*3 + 1
    #          ^
    #       il resto
    

    Il tipo degli operandi non influenza il valore del risultato, solo il suo tipo.

  6. Soluzione:

    pi = 3.141592
    r = 2.5
    
    circonferenza = 2 * pi * r
    print(circonferenza)
    
    area = 2 * pi * r**2
    print(area)
    
    area = 2 * pi * r * r
    print(area)
    
    volume = (4.0 / 3.0) * pi * r**3
    print(volume)
    
  7. Soluzione:

    a, b = 100, True
    
    a2 = a
    b2 = b
    b = a2
    a = b2
    
    print(a, b)
    

    oppure:

    a, b = 100, True
    
    x = a
    a = b
    b = x
    
    print(a, b)
    
  8. Soluzione:

    gene1_inizio, gene1_fine = 10, 20
    gene2_inizio, gene2_fine = 30, 40
    
    # disegnino:
    #
    # 5'                            3'
    # ~~~~~xxxxxxxx~~~~~xxxxxxx~~~~~>
    #     10      20   30     40
    #      \______/     \_____/
    #       gene_1       gene_2
    
    
    # due alternative
    condizione_1 = (10 <= pos <= 20)
    condizione_1 = (pos >= 10 and pos <= 20)
    
    
    condizione_2 = (30 <= pos <= 40)
    
    
    condizione_3 = (10 <= pos <= 40)
    
    
    # due alternative
    condizione_4 = condizione_3 and not (condizione_1 or condizione_2)
    condizione_4 = (20 <= pos <= 40)
    
    
    condizione_5 = pos < 10 or pos > 40
    # occhio che:
    #
    #   pos < 10 and pos > 40
    #
    # non ha senso: e' sempre False!
    
    
    condizione_6 = condizione_1 or condizione_2
    
    
    condizione_7 = (0 <= pos <= 20)
    

    Il codice va testato con diversi valori di posizione, in modo da controllare che le condizioni si comportino come vogliamo: che siano True quando la posizione soddisfa i requisiti della domanda, e False altrimenti.

  9. Soluzione:

    tutte_e_tre = t and u and v
    
    t_oppure_u_ma_non_tutte_e_due = (t or u) and not (t and u)
    
    # NOTA: qui i backslash alla fine delle righe servono
    # per andare "a capo", potete ignorarli.
    una_delle_tre_falsa = \
        (t and u and not v) or \
        (t and not u and v) or \
        (not t and u and v)
    
    una_delle_tre_vera = \
        (t and not u and not v) or \
        (not t and u and not v) or \
        (not t and not u and v)
    

    Di nuovo, il codice va testato usando diversi valori per t, u e v. Ci sono 8 combinazioni in tutto:

    t, u, v = False, False, False
    t, u, v = False, False, True
    t, u, v = False, True, False
    t, u, v = False, True, True
    # ...