Esercizio 3condizioni, cortocircuito e divisioni
In questa pagina 8
Testo (questionario di dicembre 2022 e test d'esame di dicembre 2012 e gennaio 2014 del corso di Fondamenti di Informatica UniPD; adattato da un tema d'esame in Java). Teoria: Logica booleana e istruzione ifValori di verità, operatori di confronto e logici con valutazione a corto circuito, leggi di De Morgan, truthiness; if/elif/else, espressione condizionale e match.Logica booleana e istruzione if →, Tipi numerici ed espressioniint, float, complex e bool; operatori aritmetici con divisione intera e modulo; precedenza; conversioni di tipo; modulo math e arrotondamenti.Tipi numerici ed espressioni →, Eccezioni in PythonEccezioni e traceback, eccezioni predefinite più comuni, try/except/else/finally, raise per segnalare errori, propagazione lungo le chiamate.Eccezioni in Python →.
- Il metodo
if ((a % b == 0) && (b != 0)) return true; else return false;può lanciare un'eccezione? E se si scriveif ((b != 0) && (a % b == 0))? Come si traduce in Python? - In Java
public void prova(int x) { if (-(x / 2) != -x / 2) throw new IllegalArgumentException(); }lancia l'eccezione per qualche intero? In quali circostanze? E in Python? - Con e veri e falso, valutare
P1 or P2 and P3,(P1 or P2) and P3enot P1 or P2 and not P3. - Sapendo
a = False, che valore ha(a and b) or (not a)? E cona = True? - Che cosa restituisce
alfa = "ciao"; return 1 if alfa == "ciao mare" else 2 if alfa.startswith("ciao") else 3? E che differenza c'è tra==eisper le stringhe? - Il metodo
public static double valuta(double a, double b) { return a / b; }(Java) può lanciareArithmeticExceptionsebvale 0? Che cosa fa in Python e in C?
1. Cortocircuito e divisione per zero
Gli operatori and e or valutano da sinistra a destra e si fermano appena il risultato è noto (cortocircuito): False and ... è sicuramente falso, True or ... è sicuramente vero, il secondo operando non viene calcolato.
(b != 0) and (a % b == 0): con il primo operando è falso ea % bnon viene mai eseguito → nessuna eccezione.(a % b == 0) and (b != 0):a % bviene calcolato per primo; con sollevaZeroDivisionError(in JavaArithmeticException).
L'ordine degli operandi non è una questione di stile: la condizione "di guardia" va prima.
2. Divisione intera sui negativi
In Java e in C, / tra interi tronca verso zero: e . Allora e coincidono sempre, tranne nell'overflow: per il valore non sta in 32 bit e "ricomincia" da , quindi mentre . L'eccezione è lanciata solo per .
In Python l'operatore // fa invece il quoziente per difetto (verso ): . Il confronto diventa vero per ogni dispari, e non c'è overflow perché gli interi sono illimitati. Il resto cambia di conseguenza: -7 % 3 vale in Python ( in Java e C).
3. Precedenze
Da più alta a più bassa: not, poi and, poi or (come moltiplicazione e somma). Con , :
P1 or P2 and P3=P1 or (P2 and P3)= True;(P1 or P2) and P3= False;not P1 or P2 and not P3=(not P1) or (P2 and (not P3))= True.
4. Semplificare con la tabella di verità
Quando le variabili sono poche si prova ogni combinazione:
a |
b |
(a and b) or (not a) |
|---|---|---|
| F | F | V |
| F | V | V |
| V | F | F |
| V | V | V |
Con a = False è sempre vero; con a = True vale b (la colonna coincide con b). L'espressione è l'implicazione .
5. Stringhe: == e is
alfa == "ciao mare" confronta i valori: "ciao" ≠ "ciao mare", falso; alfa.startswith("ciao") è vero: restituisce . (In Java l'operatore == su due String confronta i riferimenti, e per il testo si deve usare equals: l'errore tipico del quiz originale. In Python == è già il confronto per valore.)
is verifica l'identità: lo stesso oggetto in memoria. Due stringhe uguali costruite in modo diverso possono essere oggetti distinti: "".join(["ci", "ao"]) is "ciao" è di solito False, mentre == dà True. Per le stringhe e i numeri non si usa is (il risultato dipende dall'interprete); si usa is solo con None e con True/False (Variabili, oggetti e riferimentiIn Python una variabile è un nome legato a un oggetto; tipo, identità e valore; assegnamento, aliasing, oggetti mutabili e immutabili, None.Variabili, oggetti e riferimenti →).
6. Divisione per zero tra numeri in virgola mobile
In Java (e in C) la divisione tra double segue lo standard IEEE 754 e non lancia eccezioni: vale se , se , NaN (not a number) se ; l'ArithmeticException esiste solo per la divisione tra interi. In C 1.0 / 0.0 dà inf. In Python invece anche la divisione tra float solleva ZeroDivisionError: 1 / 0.0 è un errore, mentre float("inf") e math.inf esistono come valori. Si ricorda anche che NaN non è uguale a niente, nemmeno a se stesso: float("nan") == float("nan") è False, si usa math.isnan.
Verifica in Python
def valuta_ok(a, b):
return b != 0 and a % b == 0 # la guardia prima
def valuta_ko(a, b):
return a % b == 0 and b != 0 # a % b prima della guardia
print(valuta_ok(6, 0), valuta_ok(6, 3)) # False True
try:
valuta_ko(6, 0)
except ZeroDivisionError as e:
print("ZeroDivisionError:", e)
def wrap32(n): # un intero a 32 bit "alla Java"
n &= 0xFFFFFFFF
return n - (1 << 32) if n >> 31 else n
def div_java(a, b): # divisione che tronca verso zero
q = abs(a) // abs(b)
return q if (a < 0) == (b < 0) else -q
casi = list(range(-1000, 1001)) + [2 ** 31 - 1, -2 ** 31]
print([x for x in casi if wrap32(-div_java(x, 2)) != div_java(wrap32(-x), 2)]) # [-2147483648]
print([x for x in range(-6, 7) if -(x // 2) != (-x) // 2]) # [-5, -3, -1, 1, 3, 5]
print(-7 % 3, -7 // 3, div_java(-7, 3)) # 2 -3 -2
P1, P2, P3 = True, True, False
print(P1 or P2 and P3, (P1 or P2) and P3, not P1 or P2 and not P3) # True False True
for a in (False, True):
for b in (False, True):
print(a, b, (a and b) or (not a))
alfa = "ciao"
print(1 if alfa == "ciao mare" else 2 if alfa.startswith("ciao") else 3) # 2
import math
try:
1 / 0.0
except ZeroDivisionError as e:
print("ZeroDivisionError:", e) # float division by zero
print(math.inf, float("nan") == float("nan"), math.isnan(math.inf - math.inf)) # inf False True
print("ciao" == "".join(["ci", "ao"])) # TrueErrori comuni
- Mettere la condizione che può fallire prima della guardia.
- Credere che
/e//coincidano per i negativi, o che%abbia lo stesso segno in tutti i linguaggi. - Confondere le precedenze di
andeore non parentesizzare. - Usare
isper confrontare stringhe o numeri. - Credere che la divisione per zero tra
floatproduca lo stesso risultato in tutti i linguaggi (Python: errore; Java e C:info NaN).
Versione ripasso
Questionario di dicembre 2022 e test di dicembre 2012 e gennaio 2014 (UniPD, in Java; adattato a Python). Teoria: Logica booleana e istruzione ifValori di verità, operatori di confronto e logici con valutazione a corto circuito, leggi di De Morgan, truthiness; if/elif/else, espressione condizionale e match.Logica booleana e istruzione if →, Tipi numerici ed espressioniint, float, complex e bool; operatori aritmetici con divisione intera e modulo; precedenza; conversioni di tipo; modulo math e arrotondamenti.Tipi numerici ed espressioni →.
- Cortocircuito:
andeorvalutano da sinistra e si fermano appena il risultato è noto.b != 0 and a % b == 0non dà mai errore;a % b == 0 and b != 0sollevaZeroDivisionErrorper . La guardia va prima. - Divisione intera: in Java/C
/tronca verso zero, in Python//va per difetto (,-7 % 3). in Java solo per (overflow); in Python per ogni dispari. - Precedenze:
not>and>or. Con , :P1 or P2 and P3= True;(P1 or P2) and P3= False;not P1 or P2 and not P3= True. - Tabella di verità per semplificare:
(a and b) or (not a)è : sempre vero seaè falso, uguale abseaè vero. ==confronta i valori,isl'identità:issolo conNone,True,False(Variabili, oggetti e riferimentiIn Python una variabile è un nome legato a un oggetto; tipo, identità e valore; assegnamento, aliasing, oggetti mutabili e immutabili, None.Variabili, oggetti e riferimenti →). In Java==suStringconfronta i riferimenti (serveequals).- Divisione tra
floatper : in Java e C vale o NaN (IEEE 754), in Python sollevaZeroDivisionError; NaN è diverso anche da se stesso.
Errori comuni: guardia dopo l'operazione che può fallire; / e // scambiati; precedenze senza parentesi; is su stringhe e numeri.