Integrazione numerica

Come fare un disastro senza rendersene conto


I metodi d’integrazione numerica sono quelli che permettono il calcolo degli integrali definiti di una funziona usando i calcolatori elettronici. Detto in maniera più accessibile (anche se non del tutto formalmente corretta), l’integrazione numerica è quel processo che conduce alla valutazione, in molti casi approssimata, dell’area compresa tra una curva di equazione y=f(x) e l’asse delle ascisse, in una regione x∈[a,b].

L’integrale tra a e c della funzione f(x) rappresenta l’area T colorata di grigio; quello tra c e b della stessa funzione è l’area indicata con U. L’integrale tra a e b rappresenta la somma delle aree T+U. Immagine tratta da Wikimedia Commons (grazie a Juliusross~commonswiki).

Uno dei metodi d’integrazione numerica più semplici e allo stesso tempo più usati, risale al tempo di Isaac Newton (a dimostrazione che il calcolo numerico non è affatto, come si crede, strettamente legato all’uso dei computer). Consiste nel dividere l’intervallo [a,b] in una serie di N intervalli più piccoli [xᵢ,xᵢ₊₁], con x₁=a e xN+1=b, approssimare f(x) in ciascuno di essi con un una costante f(x)≃f(xᵢ)=cost, e approssimare l’area sotto la curva come la somma delle aree di rettangoli di base xᵢ₊₁-xᵢ e altezza f(x̅), dove x̅ è il punto medio del sotto-intervallo [xᵢ,xᵢ₊₁].

L’immagine, tratta da Wikimedia Commons (grazie a Greenbreen), mostra come si può approssimare un integrale definito con la somma delle aree di N rettangoli. Maggiore è il numero di rettangoli, migliore è l’approssimazione.

In effetti, il simbolo d’integrale (∫ ) è una “esse” allungata che deriva dal latino summa (somma). Gli estremi d’integrazione a e b si indicano in basso e in alto. Quello che si somma, in un integrale, è il prodotto della base infinitesima dx di un rettangolo per la sua altezza f(x). La notazione, in sostanza, indica la somma delle aree dei rettangoli di altezza f(x) e larghezza infinitesima dx. In certi casi, l’integrale di alcune funzioni si sa calcolare esattamente. Chi ha studiato un po’ di analisi matematica sa, per esempio, che

Numericamente, con un programma in C, l’integrale in questione si potrebbe calcolare come segue

double integral(double a, double b, int N) { 
  double I = 0., x = a; 
  double dx = (b - a)/N; 
  while (x < b) {
    I += sin(x+0.5*dx)*dx;
    x += dx;
  }
  return I;
}

In questa funzione si pone, inizialmente, la variabile I, che rappresenta l’integrale, uguale a 0. La variabile x, invece, si pone uguale ad a. Si divide quindi l’intervallo [a,b] in N parti di ampiezza dx. Nel ciclo while, alla variabile I si somma, iterativamente, il valore del seno di x, calcolato nel punto medio dell’intervallo, moltiplicato per dx, con x che si sposta ogni volta verso destra. Quando x finisce fuori dell’intervallo [a,b] la variabile I contiene la somma delle aree dei rettangoli di base dx e di altezza uguale al seno dei punti di mezzo di ciascun sotto-intervallo, che fornisce una stima dell’integrale. Una misura della precisione di questa stima è data da 𝛿=|2-I|/2, che fornisce la differenza percentuale tra il valore atteso 2 e quello stimato I.

La seguente tabella riporta il valore di 𝛿 per diversi valori di N.

N𝛿N𝛿
157%80.6%
211%90.5%
34.7%100.4%
42.6%111.7%
51.7%120.3%
65.6%131.2%
70.8%140.2%

N=1 equivale ad approssimare l’area sotto la funzione seno con quella di un rettangolo di base π e altezza uguale al seno di π/2, che vale 1. L’area così stimata (π) è chiaramente ben diversa da quella vera che vale 2. E infatti l’errore è grande (57%). All’aumentare di N, l’errore, come ci si potrebbe aspettare, diminuisce. Tuttavia, per certi valori di N, come N=6, N=11 e N=13, tale errore non solo non segue l’andamento decrescente atteso, ma è superiore di un ordine di grandezza rispetto a quello di valori del tutto simili dello stesso parametro.

In un recente post spiegavo come la scelta del costrutto da utilizzare per realizzare un ciclo dovesse basarsi sul tipo di controllo che si poteva eseguire: nel caso in cui si possa prevedere il numero di volte che il ciclo sarà percorso è più opportuno usare il costrutto for, riservando il while per le situazioni nelle quali questo non è possibile.

Nel caso in esame, seguendo quel consiglio, avremmo dovuto usare il for per realizzare il ciclo, così:

double integral(double a, double b, int N) {
  double I = 0., x = a;
  double dx = (b - a) /N;
  for (int i = 0; i < N; i++) {
    I += sin(x+0.5*dx)*dx;
    x += dx;
  }
  return I;
}

In questo caso, i risultati che si ottengono sono esattamente gli stessi, ma per N=6, 11 e 13, gli errori corrispondenti sono, rispettivamente, 𝛿=1.1%, 0.3% e 0.2%, perfettamente in linea con le attese.

Come si spiega? Il fatto è che i numeri nella memoria di un calcolatore sono rappresentati sempre con un numero finito di cifre. Quando si somma dx a x può dunque accadere che, all’ultima iterazione, il valore risultante sia appena più piccolo o appena più grande di b, causando l’omissione o la ripetizione di un addendo nella somma. È così che, anche se l’errore su x, come nel caso in esame, è dell’ordine di 2-53, l’errore finale può essere disastrosamente alto. Usando il costrutto for garantiamo che il numero di intervalli effettivamente usati per la stima sia quello giusto.

Come si vede, l’adesione alle convenzioni descritte nel post sopra indicato, non è solamene una questione di stile, ma permette di limitare errori altrimenti difficili da controllare nei casi generali. Questo caso, inoltre, suggerisce un’ulteriore “regola“: quando si deve scegliere un numero intero arbitrario (come nel caso del numero di intervalli in cui dividere [a,b]), meglio scegliere una potenza di 2 (non 10, ma 8 o 16; non 100, ma 64 o 128; non 1000, ma 1024). Con quelle, gli errori di arrotondamento sono ridotti al minimo possibile.

Questo e altri suggerimenti dello stesso tenore sono contenuti nel mio libro “Programmazione Scientifica“, edito da Pearson.

10 milioni per 7 è sempre pari a 70 milioni?

Il calcolo numerico può condurre a sottili e pericolosi errori di arrotondamento. Per evitarli è necessario conoscere il problema e sapere come aggirarlo.


Consideriamo il seguente programma, scritto in C:

#include <stdio.h>
int main() {
  float x = 7;
  float S = 0;
  int i;
  for (i = 0; i < 10000000; i++) {
    S += x;
  }
  printf(“%f\n”, S);
}

Il programma aggiunge 7 alla variabile S dieci milioni di volte. Il risultato atteso è quindi di 70 milioni. Ma in effetti, compilando (senza ottimizzazioni) ed eseguendo il programma si ottiene

77603248.000000

che è piú grande di oltre il 10%. Sorpresi? È l’effetto degli errori di arrotondamento causati dal fatto che i numeri, nei computer, si possono rappresentare solo con un numero finito di cifre. Ora, sia 7 che 10 milioni sono perfettamente rappresentabili nella memoria di un computer. Allora, perché il risultato è così cattivo?

La rappresentazione dei numeri nei computer

I numeri, nella memoria di un computer, si rappresentano nel sistema binario. In questo sistema qualsiasi numero è rappresentato in un sistema posizionale in base 2, in modo tale che qualsiasi numero intero composto di m cifre (0 e 1) rappresenta un numero

dove dᵢ è il valore della i-esima cifra (0 o 1). Ad esempio, il numero intero 5 si rappresenta come 00000101 in un computer a 8 bit, essendo 1⨉2²+0⨉2¹+1⨉2⁰=4+0+1=5. Gli zeri iniziali non sono, naturalmente, significativi.

Per rappresentare numeri non interi, come 3.14, in linea di principio si potrebbe usare la stessa notazione, con la sola differenza che il valore iniziale di i è negativo e pari al numero di cifre dopo la virgola. Ad esempio, 3.14 corrisponde a 11.001000111111010101110001 in binario. In effetti,

Osserviamo che il numero preciso risultante dal calcolo di cui sopra è, in effetti, 3.1400003433. I numeri razionali in una base non sono necessariamente numeri razionali in un’altra base (ad esempio, 1/10 è irrazionale in base 2). Una tale rappresentazione è poco pratica per i computer, che hanno bisogno di un numero enorme di cifre per rappresentare, con sufficiente precisione, numeri che, nella notazione decimale, richiedono un numero limitato di cifre. I computer, per questo, utilizzano la notazione standard IEEE754. All’interno di questa notazione, i numeri in virgola mobile, come vengono chiamati, si rappresentano con 32 bit, utilizzando una sorta di notazione scientifica in base 2. Nella notazione scientifica, un numero x si scrive come x=y×10ⁿ, dove, di solito, y∈[1,10) e n è scelto di conseguenza. Ad esempio, la distanza media della Terra dal Sole è di 149 597 870 700 m, che si scrive anche come 1.49 597 870 700⨉10¹¹ m. Analogamente, 3.1400003433, in base 2, si può scrivere come 1.100100011110101110001⨉2¹, cioè, come y×2ⁿ, con y∈[1,2) e n=1. Con questa convenzione, la cifra che precede il punto decimale è sempre 1 e si può omettere. Il numero che moltiplica la potenza di due (1.100100100011111101010101110001) si chiama mantissa e può essere rappresentato, nella cosiddetta forma normale, come 1001000111111010101110001, omettendo il primo 1. Nella notazione IEEEE754, un numero si rappresenta utilizzando il primo bit per il suo segno (0 se positivo), 8 bit per rappresentare l’esponente di 2 (n=1 nell’esempio) nella notazione in eccesso a 127 (cioè come un intero tale che n=m-127; m=128 nel nostro esempio), e 23 bit per rappresentare la sua mantissa nella forma normale. La sequenza di bit necessaria per rappresentare il nostro numero è la seguente: 0 10000000 10010001 11101011 1000100.

Anatomia del problema

Dichiarando x come numero in virgola mobile (float), il compilatore lo rappresenta come 0 10000001 1100000 000000000000 0000000000, cioè come (1+1×2-¹+1×2-²)×2²=7. Infatti, il primo 0 rappresenta il segno +. Il seguente gruppo di 8 bit rappresenta 129 che, a sua volta, corrisponde all’esponente di due 129-127=2. Dei restanti 23 bit, solo i primi due non sono nulli e corrispondono alle potenze -1 e -2. L’1 aggiunto a queste potenze è implicito nella forma normale e non rappresentato esplicitamente.

Il problema sorge quando il programma effettua la somma. Per fare ciò, una CPU deve considerare i due termini della somma come rappresentati utilizzando la stessa potenza di due; in questo modo può utilizzare la proprietà distributiva della moltiplicazione. Quando S=16 777 222, la sua rappresentazione nella memoria del computer è 0 10010111 000000000000 000000000000 0000011. L’esponente di due è 10010111, corrispondente al numero intero 151. L’esponente di 2 nella notazione scientifica è quindi 151-127=24. S, di conseguenza, si esprime come y×2²⁴. Per poter sommare x=7 ad esso, dobbiamo esprimere x come z×2²⁴, in modo che la CPU possa fare la somma di y e z per ottenere il nuovo valore di S. La rappresentazione originale di x era 1,11 seguita da 21 zeri, per 2². Per esprimerla come z×2²⁴, dobbiamo spostare i bit della mantissa di 22 posti a destra. Il risultato è un numero composto da 21 zeri seguiti dalle cifre 111. In un numero a 32 bit non c’è posto per l’ultimo 1, che si perde, e, di fatto, x=6 e S=16 777 228.

Per mitigare gli effetti dell’arrotondamento, le somme si eseguono nella FPU (Floating Point Unit), che utilizza 80 bit per rappresentare i numeri in virgola mobile. Aggiungendo 7 a 16 777 228 si ottiene 16 777 235. Sfortunatamente, quando si copia questo numero nella memoria, la FPU aggiunge un 1 alla mantissa, per recuperare l’errore precedente. Il risultato è S=16 777 236, cioè 16 777 228 + 8. Di fatto, il valore aggiunto alla somma è 8 invece di 7. Lo stesso accade a ogni iterazione successiva e di fatto si aggiunge 8 invece di 7 molte volte. In un caso, il valore aggiunto alla somma effettiva S è in realtà 11!

La lezione

Quando si sommano, con un computer, due valori, S e x, è necessario prestare attenzione ai loro valori relativi. Se log₂(S)-log₂(x) ≪ p, dove p è il numero di bit utilizzati per la mantissa, allora non avrete problemi. Se invece log₂(S)-log₂(x) ≃ p o più grande, allora, molto probabilmente, vi imbatterete in errori di arrotondamento che potrebbero anche essere gravi. Mai sommare ciecamente numeri troppo diversi. Allo stesso modo, dovreste sempre prestare attenzione alla differenza di numeri molto simili. Se i numeri sono troppo vicini, la loro differenza può essere difficile da rappresentare e può essere pari a zero, anche se i due numeri sono diversi.

Il galateo del programmatore

Scrivere software non è un’attività puramente tecnica, così come scrivere un articolo per un giornale non è una mera elencazione di fatti. È anche un esercizio di stile, del tutto simile a quello che si mette in atto quando si scrive un romanzo.

I linguaggi di programmazione, sempre molto rigidi nel rispetto delle regole sintattiche (molto più rigidi di quanto non sia un correttore di bozze), ma lasciano spesso, al programmatore, alcune libertà che, se mal utilizzate, come tutte le libertà, si rivelano deleterie e, quasi sempre, si ritorcono contro l’autore.

Attraverso le scelte “di stile” il programmatore può veicolare messaggi ulteriori rispetto al contenuto dei propri lavori. Scegliendo una forma piuttosto che un’altra, in una certa misura si comunicano informazioni che, spesso, aiutano chi legge (spesso lo stesso autore) a decifrare il contenuto di un programma.

I nomi delle variabili
La scelta dei nomi da assegnare alle variabili riveste grande importanza nella scrittura di un programma. A ogni variabile si deve sempre dare un nome sensato, che ne richiama il significato e l’utilizzo che se ne fa nel programma. Anche il tipo di dato contenuto nelle variabili può essere suggerito dal nome che, comunque, non deve mai essere troppo lungo.

Ad esempio, le variabili intere avranno nomi che iniziano con una lettera compresa tra “i” e “n”. Per variabili ausiliarie e indici si tenderà a usare nomi composti di una sola lettera, mentre, di norma il nome evocherà la quantità che rappresenta. Per esempio x, y e z sono nomi sensati per coordinate di un punto, così come t e T possono rappresentare, rispettivamente, un tempo e una temperatura. Se si usano variabili composte di più parole si può usare la convenzione secondo la quale la prima lettera di ogni parola, esclusa la prima, va scritta in maiuscolo. Per esempio: gasPressure, totalCrossSection, etc.

Il ruolo delle funzioni
Specialmente all’inizio della loro carriera di programmatori, molti tendono a scrivere funzioni che includono la stampa di messaggi relativi al risultato delle operazioni che la funzione deve svolgere. Questo è un errore.

Le funzioni, a meno che non siano state pensate proprio allo scopo di stampare un risultato (nel qual caso, devono occuparsi esclusivamente di questo aspetto), devono sempre limitarsi a calcolare e a restituire il risultato richiesto, che poi sarà stampato a cura del programma che userà la funzione.

La scelta degli operatori
In alcuni casi, i linguaggi di programmazione permettono di usare operatori diversi per giungere allo stesso risultato. Per esempio, in C esiste l’operatore di autoincremento che serve per aggiungere al valore corrente di una variabile una certa quantità. Quello che, anche in C, si potrebbe scrivere come

a = a + 3;

nel C si scrive più propriamente come

a += 3;

Premesso che anche la prima forma è corretta e che il compilatore C la processa senza alcun problema, quest’ultima notazione rende molto più evidente il significato dell’operazione che si sta compiendo, e non si rischia di confondere la notazione con quella equivalente di un’equazione matematica che non ha una soluzione. Se poi, invece di 3, si vuole sommare alla variabile di sinistra il valore intero 1, allora si preferirà scrivere

a++;

invece di

a += 1; 

Anche in questo caso non cambia nulla nella sostanza, ma il registro col quale si comunica si adatta alle circostanze. In fondo, anche quando scrivete un’email scegliete opportunamente la forma secondo che il destinatario sia un conoscente o un’Autorità. Il messaggio può essere lo stesso, ma la forma cambia secondo i casi. Per annunciare la disdetta di un appuntamento, per esempio, potete dire

Ciao. Mi spiace, ma stasera non posso più venire

se state comunicando con un amico, mentre scriverete

Spiace comunicare che, per cause di forza maggiore, non mi sarà possibile essere presente all’incontro previsto per la prossima settimana

se invece dovete disdire un appuntamento di lavoro. Quando si scrive un programma occorre pensare negli stessi termini, cercando di comunicare più di quanto non sia strettamente necessario per una sua corretta esecuzione.

La programmazione strutturata
I programmi strutturati sono quelli composti unicamente di “strutture”: moduli che rappresentano tutti i possibili gruppi di istruzioni che hanno la proprietà di avere un solo punto d’entrata e un solo punto d’uscita. Furono introdotte da Bohm e Jacopini nel 1966. I due matematici identificarono tre tipi di strutture: sequenziale, di selezione e di iterazione.

La struttura sequenziale rappresenta una qualunque sequenza di operazioni eseguite nell’ordine in cui sono scritte. Le strutture di selezione sono quelle in cui si controlla il risultato di un’espressione logica e si esegue l’uno o l’altro gruppo di istruzioni secondo il risultato. Le strutture di iterazione, infine, sono quelle che permettono di ripetere le operazioni più volte.

Un programma strutturato garantisce un controllo maggiore sul flusso delle operazioni, grazie proprio alla presenza di un unico punto d’entrata e un unico punto d’uscita dalle strutture.

Per realizzare un programma strutturato basta seguire poche semplici regole: evitare di usare istruzioni tipo break e scrivere funzioni che hanno un solo return. Va da sé che l’istruzione goto dovrebbe essere bandita da ogni programma degno di tale nome.

I programmi strutturati sono più leggibili, più facili da manutenere e più solidi dal punto di vista della possibilità che includano errori (bug) di programmazione.

Questioni di efficienza
Quando vi si chiede di scrivere il codice necessario per decidere se si sia o meno verificata una determinata condizione, fatevi sempre la domanda: “faccio prima a individuare la situazione secondo cui la condizione è vera o quando questa è falsa?”.

Per verificare, ad esempio, se una stringa sia palindroma, si potrebbe costruire una stringa i cui caratteri siano disposti al contrario e confrontare questa con quella originale; oppure ancora confrontare tutte le coppie di caratteri (str[i], str[N-1-i]), dove N rappresenta la lunghezza della stringa e i va da zero a N/2.

Per verificare, al contrario, che la stringa NON sia palindroma, basta scrivere un codice che esegue i confronti carattere per carattere e abbandona l’iterazione non appena uno di questi confronti dia esito negativo. Basta quindi negare la risposta per fornire la funzione richiesta.

La scelta del costrutto per le iterazioni
Quando si sceglie il costrutto da usare per compiere iterativamente una serie di istruzioni, solitamente si può scegliere tra almeno due alternative: il for e il while. Quest’ultima forma è spesso disponibile nelle varianti while (...) do {...} o nella forma do {...} while (...) (secondo i linguaggi di programmazione). Naturalmente i costrutti sono tutti equivalenti dal punto di vista del risultato che si può ottenere ed è quasi sempre facile trasformare un ciclo in un altro. Ma adottando i criteri sotto riportati si scriverà codice irreprensibile, facile da comprendere e da manutenere.

Il costrutto for si sceglie quando il numero di passi da compiere è noto o si può calcolare immediatamente prima di entrare nel ciclo. Quando invece il numero di passi che saranno compiuti dall’algoritmo non è noto a priori si preferisce usare il while in una delle due forme. Se disponibili entrambe, il costrutto do {...} while (...) si usa per sottolineare che il ciclo sarà percorso almeno una volta.

Per esempio, nell’esempio della stringa palindroma, l’approccio di “forza bruta” consistente nel testare tutte le coppie di caratteri si eseguirebbe attraverso un ciclo for. Se invece optiamo per la soluzione più efficiente non possiamo sapere quante volte percorreremo il ciclo prima di entrarvi, pertanto sceglieremo il costrutto while.

L’International Obfuscated C Code Contest
Quanto sopra permette di scrivere codice facilmente interpretabile, il che ne permette una manutenzione semplice anche a distanza di tempo. Vi qualifica anche come programmatori accurati e attenti. Garantisce che, qualora la vostra libreria di funzioni cresca enormemente, il controllo del codice si possa mantenere senza sforzi.

Se imparerete ad adottare queste regole di certo non ve ne pentirete, a meno che non abbiate intenzione di partecipare a un curioso concorso denominato The International Obfuscated C Code Contest. Potete consultarne le regole sul sito ioccc.org. A proposito: uno dei miei preferiti è https://www.ioccc.org/2018/yang/prog.c.

Pubblicato il bando per una nuova edizione della Scuola di Fisica con Arduino e Smartphone

È stato pubblicato all’indirizzo https://www.uniroma1.it/it/offerta-formativa/corso-di-alta-formazione/2019/fisica-con-arduino-e-smartphone il bando per la partecipazione alla III edizione della Scuola di Fisica con Arduino e Smartphone di Sapienza.

La scuola è un’attività full time intensiva di tre giorni destinata agli insegnanti di matematica e fisica o aspiranti tali. Non ci sono prerequisiti: non è necessario saper programmare o avere competenze di elettronica per partecipare. L’esperienza delle prime due edizioni ha dimostrato che un insegnante completamente digiuno di programmazione si può trasformare in un vero e proprio maker in soli tre giorni!

20170907_144943-collageIl primo giorno insegneremo a programmare una scheda Arduino e chiederemo agli insegnanti di pensare a un esperimento che vorrebbero realizzare nella loro classe. Il secondo giorno porteremo gli insegnanti ad acquistare il materiale necessario (il budget è volutamente ridotto a 20 euro ciascuno per consentire l’esecuzione di misure precise e accurate con una spesa minima) e li assisteremo nella realizzazione pratica della loro idea. Il terzo giorno l’esperimento sarà condotto e illustrato.

È un’esperienza coinvolgente ed estremamente utile per acquisire quelle che oggi si chiamano soft-skills e per rendere l’insegnamento della fisica appetibile anche agli studenti meno motivati.

La partecipazione alla scuola è pagabile con la carta docente per gli insegnanti in servizio. Altre informazioni alle pagine dedicate del PLS-Fisica di Sapienza.

Le scuole di Fisica con Arduino e Smartphone crescono

Le Scuole di Fisica con Arduino e Smartphone cui ho dato vita dal 2016 continuano a riscuotere un discreto successo. Alcuni insegnanti hanno già iniziato a lavorare con Arduino nelle loro classi e presumibilmente avremo materiale da presentare al prossimo Congresso della Società Italiana di Fisica.

Recentemente è stato pubblicato un mio post su Math is in the Air: un blog di divulgazione della matematica. Alcuni insegnanti hanno cominciato a fare sperimentazione in classe con Arduino e a Marzo parteciperò a un Workshop internazionale a Parigi per illustrare le nostre esperienze a un panel di esperti provenienti da vari Paesi europei.

Abbiamo anche ricevuto un invito per presentare le Scuole al Summer Meeting dell’American Association of Physics Teachers, dove condurremo anche un workshop sull’uso di Arduino per esperimenti scientifici.

 

Indagine sugli studenti di fisica

Sono ormai quattro anni che propongo ai miei studenti di fisica un questionario standardizzato a inizio corso. Il questionario serve a raccogliere i dati degli studenti necessari per lo svolgimento delle attività di laboratorio, ma con l’occasione chiedo loro alcune informazioni aggiuntive per studiare alcuni fenomeni relativi alle attitudini degli studenti al primo anno di corso all’Università.

In questi quattro anni, apparentemente sono tre gli aspetti interessanti, che denotano un chiaro trend: il numero di studenti che non ha mai sentito parlare di Arduino, il numero di studenti senza smartphone e il numero di studenti che conosce il sistema operativo Linux. Tutte le indagini sono eseguite su un campione di circa 100 studenti per anno.

Il numero di studenti che non ha mai sentito parlare di Arduino è, fortunatamente, in diminuzione, sebbene il numero assoluto di studenti che ignorano del tutto il fenomeno sia ancora molto alto: nell’ultima indagine (2017) ben il 43% degli studenti ha dichiarato di non aver mai sentito nominare questo nome.

arduino

L’andamento in funzione dell’anno è riportato nel grafico sopra. Anche la frazione di studenti che conosce Linux è in discesa, come si vede dal grafico sotto.

linux

Al contrario della precedente questa non è una buona notizia, ma c’era da aspettarselo in quanto presumibilmente dipendente dal fatto che i computer stanno diventando sempre meno diffusi in favore dei tablet. Il dato più eclatante è fornito dall’andamento del numero di studenti privi di smartphone:

smartphone

La discesa appare, in questo caso, inequivocabile particolarmente evidente e addirittura sembra essere esponenziale. Questo è ragionevole, in quanto la variazione (cioè il numero di studenti che passa dal non avere uno smartphone ad averlo in un anno) dev’essere proporzionale alla popolazione priva di smartphone.

Nell’indagine 2017 nessuno degli studenti intervistati (115) ha dichiarato di non essere in possesso di uno smartphone. Questo significa che possiamo porre un limite superiore a meno del 3% (il 2.6% per la precisione) al 95% di livello di confidenza. Possiamo cioè affermare che, con il 95% di probabilità di essere nel giusto, che almeno tra gli studenti che s’iscrivono a un corso di laurea in fisica più di 97 su 100 possiedono almeno uno smartphone.

School of Physics with Arduino and Smartphones – II edition

The second edition of the School of Physics with Arduino and Smartphone is over and, as in the first edition, was a great success.

foto di gruppo scuola arduino.jpg-large

During the school, 24 high school teachers with no experience in programming nor in electronics, were turned into real makers: they have learned how to program an Arduino board and how to use a smartphone to make physics experiments and they did them.

Day 1 was devoted to lessons, by myself and David Cuartielles, one of the Arduino co-founders, about Arduino programming and about phyphox: a smartphone App developed by our colleagues at Aachen. In the afternoon, after a visit to the FabLab of Fondazione Mondo Digitale, where the school was held, participants started designing the experiments, that must be made using readily available materials besides Arduino and few sensors provided by us.

IMG_20170907_111112

At the beginning of Day 2 we brought the group of teachers to the Eva shop (a shop own by a Chinese woman that sells almost everything), where they could buy whatever they need to perform the experiments. Then, each group started building its own experiment with the support of the FabLab personnel and few tutors (among which, four teachers from the first edition).

Experiments were fine tuned on the morning of Day 3, and presented in the afternoon. Experiments will be described on this blIMG_20170907_124710-ANIMATIONog during next days.

Teachers were enthusiasts. Using Arduino or smartphones to perform experiments adds lot of value to them: traditionally, laboratory kits need just to be assembled and run. They appear almost as “black boxes” from which there is few to learn. Self-constructed experiments force students to think about every detail and to deeply understand what they are doing. Experimental errors (both statistical and systematic) must be properly taken into account and data analysis has to be made offline, forcing a review of the all the physics behind the experiments. Physics can be literally grasped in any aspect. Moreover, the experience is engaging and stimulates competition among participants.

IMG_20170908_151813

Experiments were done on objects falling on a slide, Doppler effect, energy conservation, theinverse square law for illumination, the magnetic field produced by a current, light attenuation traversing a medium and the Newton’s second Law. Moreover a wearable device was realised to physically turn a circular motion into an harmonic one.

In summary, the school was extremely fruitful in showing how simple and instructive can be the realisation of performant experiments using technologies like Arduino and Smartphone.

VID_20170908_113457 IMG_20170908_130338 IMG_20170908_102204.jpg
IMG_20170908_145031.jpg

We look forward to the next edition of such a school. A photo gallery is available here.

La stima di π

Il problema della cosiddetta quadratura del cerchio è molto antico. Consiste nella determinazione dell’area di un cerchio di raggio 1 (l’area del cerchio di raggio qualsiasi essendo semplicemente quella del cerchio di raggio 1 moltiplicata per il raggio al quadrato). Un modo per definire questa misura è il seguente: prendiamo un cerchio di raggio 1 e inscriviamolo in un quadrato, che evidentemente deve avere lato pari a 2 (e dunque area pari a 4). Se chiamiamo π l’area di questo cerchio, il rapporto tra quest’area e quella del quadrato è π/4.

Il 14 marzo è il cosiddetto Pi Day: il giorno del pi greco (in inglese la data del 14 marzo si scrive 3/14). Questo post è dunque un suggerimento per attività didattiche da portare avanti in quella giornata.

Se si distribuiscono N punti in maniera uniforme all’interno del quadrato, una frazione di essi cadrà all’interno del cerchio ed è evidente che il numero di punti che cade all’interno del cerchio diviso il numero di punti N sarà in media uguale al rapporto delle aree di queste figure. Chiamando Nint il numero di punti interni al cerchio possiamo perciò dire che

Nint/N ≃ π/4,

e, di conseguenza, possiamo stimare π semplicemente contando il numero Nint che cade all’interno del cerchio:

π ≃ 4Nint/N.

La statistica c’insegna che la precisione con cui potremo determinare il valore di π sarà tanto migliore quanto maggiore sarà il numero di punti Nint, che a sua volta dipende da N.

Con il linguaggio di programmazione Scratch anche i bambini possono scrivere un semplice algoritmo per stimare il valore di π.

All’indirizzo https://scratch.mit.edu/projects/149703806/ si può vedere in funzione il programma piCat che fa proprio questo. Il gattino di Scratch chiede quanti punti N si devono generare e comincia a mettere un pallino in punti a caso scelti all’interno del quadrato. Quando il pallino si trova nel cerchio (e questo lo si determina controllando il colore col quale il pallino è in contatto) cambia colore e incrementa il valore di un contatore Ninside. La stima di π è costantemente aggiornata. Con N=2000 si trovano valori molto prossimi a quello vero, pari a 3.1415926535897932384626433832795028841971693… (alla pagina http://www.piday.org/million/ trovate il valore di π con un milione di cifre dopo la virgola).

Simulazione di campi magnetici

Nei giorni scorsi, preparando le mie lezioni di Fisica per Biotecnologie, cercavo un modo efficace di spiegare qualitativamente come mai il campo magnetico prodotto da molte spire sia relativamente uniforme all’interno e poco intenso all’esterno del gruppo di spire. Volevo anche includere questa spiegazione nel mio e-book Fisica Sperimentale, che sono vicino a terminare (almeno per quanto riguarda i suoi contenuti: la forma e le eventuali correzioni richiederanno ancora molto tempo).

Non trovando nulla di soddisfacente sulla rete ho deciso di scrivere da me il software necessario (il codice è disponibile su bitbucket). In fondo non è difficile. Si parte da un filo percorso da corrente che produce un campo magnetico le cui linee di forza sono circonferenze centrate sul filo e la cui intensità è data dalla Legge di Biot-Savart.  Una spira circolare, a questo punto, si può pensare come a una coppia di fili: per simmetria, infatti, due punti opposti sulla spira sono equivalenti a tutti gli altri e ciascuno produce un campo equivalente a quello prodotto da un filo tangente alla spira in quel punto.

Avendo a disposizione il campo di una spira si può calcolare quello prodotto da molte spire semplicemente sommando (vettorialmente) quello prodotto da ciascuna di esse in un dato punto dello spazio.

Ho così scritto un programma che calcola il campo di N spire sovrapposte e di una spira che si trova a una certa distanza da queste, con l’asse allineato a quello delle altre. Facendo variare la distanza di quest’ultima spira se ne simula l’avvicinamento al gruppo di N spire. Per ogni distanza produco quindi un grafico che rappresenta con un codice di colori l’intensità del campo in un punto e uno nel quale disegno i vettori campo in punti selezionati. Salvo i grafici in altrettante immagini e da queste genero un gif animato che fa vedere come evolve il campo in questione.

Qui sotto si vede l’animazione che rappresenta le N spire che cadono l’una sull’altra: l’intensità del campo magnetico tra le spire diventa via via più grande e uniforme (in bianco sono rappresentati i campi più intensi).

Nel video sotto invece si vedono i vettori campo magnetico in diversi punti dello spazio. Si può notare come, vicino a una singola spira, il vettore campo descriva circonferenze concentriche attorno alla spira. Sommandosi, i campi di molte spire danno luogo a un campo praticamente uniforme all’interno del solenoide formato da tante spire e orientato come il suo asse.

Le immagini sono state ottenute con gnuplot e i filmati con il programma convert di Linux.

Se siete interessati ai dettagli potete contattarmi agli usuali recapiti. Il codice è rilasciato con licenza GPL ed è quindi pubblico e utilizzabile da chiunque.

Inizio lezioni 2016/17

Il 3 ottobre 2016 hanno inizio le lezioni per i corsi di laurea in Fisica e in Biotecnologie di Sapienza Università di Roma.

La prima lezione del mio corso di Fisica per Biotecnologi si tiene, come da calendario, lunedì 3 ottobre alle 17:00 in Aula Amaldi (Edificio Marconi del Dipartimento di Fisica). Il calendario delle lezioni prosegue il giovedi dalle 12:00 alle 14:00 e il venerdi dalle 10:00 alle 12:00. Tutti i dettagli sul corso si trovano alla relativa pagina.

La prima vera lezione del corso di Laboratorio di Calcolo è invece prevista per mercoledì 5 dalle 11:00 alle 12:00. Il giorno 4 ottobre è infatti prevista l’accoglienza delle matricole, che ovviamente sono invitate a partecipare. In quella giornata saranno illustrati i contenuti e i metodi dei corsi del primo semestre e forniremo informazioni utili. Ulteriori informazioni sul corso le trovate qui.