Red Hot Cyber

La cybersecurity è condivisione.
Riconosci il rischio, combattilo, condividi le tue esperienze ed 
incentiva gli altri a fare meglio di te.

Cerca

la Magia della Programmazione incontra il fascino della Matematica: un viaggio di crescita e apprendimento

Davide Cavallini : 23 Febbraio 2024 07:04

Questo articolo è stato scritto con la preziosa collaborazione di Stefano Versace, mio ex professore di matematica delle scuole superiori e attualmente insegnante al Liceo Scientifico. Lo ringrazio molto per aver partecipato alla stesura dell’articolo, e anche come insegnante.

Ha contribuito alla scrittura Giovanni Pollola, laureando in Ingegneria Meccanica all’Università “Luigi Vanvitelli”, che ringrazio con tutto il cuore. Inoltre è stato revisionato da Sergio Corpettini, Advanced Project Engineer, e da Giuseppe Longobardi, Cybersecurity Architect & Trainer.

Nell’articolo precedente abbiamo affrontato matematicamente il problema della collisione di alcuni algoritmi di hashing, con particolare riferimento al controllo di integrità dei file. Questa volta vedremo un esempio pratico di applicazione della matematica nel campo della programmazione.

Spesso ricordo che gli studenti trascuravano alcune materie, sostenendo che “solitamente nella programmazione si fanno calcoli semplici, come somme e resti”, ma non sempre è così. E’ fondamentale avere la padronanza di alcuni concetti chiave, prettamente matematici, per avere la capacità di poter produrre attraverso questi degli artifici pratici utili, e a volte addirittura indispensabili, ai fini della programmazione. Quando studiamo, soprattutto nelle scuole superiori, ci facciamo spesso un’idea di “che cosa vorremmo fare da grandi”, ma poi non sappiamo effettivamente dove andremo a capitare. 

Analogamente alle leggi della meccanica quantistica, l’universo presenta infinite possibilità e andremo a “cadere” con una certa probabilità in un lavoro preciso, ma non sappiamo mai bene quale, a meno che non ereditiamo il lavoro dei genitori (notaio, avvocato, titolare della fabbrica del padre, nobile, eccetera).

Potrebbe capitare l’occasione di dover fare calcoli complessi, come appunto nella computazione quantistica, o di lavorare sulla meccanica, oppure in agenzie aerospaziali, e se fossi privo di conoscenze matematiche avanzate, dovresti certamente rinunciare.

Quindi, per come la vedo io, vale sempre la pena di impegnarsi a studiare, e di continuare sempre a farlo nella propria vita.

Introduzione

Oggi ci immergeremo in un affascinante mondo dove la matematica e la programmazione si fondono per risolvere problemi reali in modo creativo e appassionante. Nel nostro viaggio, esploreremo l’interessante connessione tra queste due discipline e come insieme possano aprire porte a soluzioni innovative.

Il nostro avvincente esempio ruota attorno al vasto universo delle assicurazioni per automobili e all’utilizzo di dati di velocità provenienti da un’app di navigazione satellitare. Immaginatevi di dover calcolare l’accelerazione, la decelerazione, la velocità massima e la distanza percorsa da un veicolo in un determinato intervallo di tempo. Sembrerà difficile? Beh, noi useremo il linguaggio di programmazione PHP e il software OpenOffice Calc per semplificare il processo e rendere tutto più accessibile e divertente.

Vi guideremo attraverso la creazione di un grafico delle velocità nel tempo, dove applicheremo concetti matematici come derivata e integrale per ottenere le informazioni desiderate. Vi spiegheremo la magia dietro la derivata, il rapporto incrementale, l’integrale definito e indefinito, e persino la misteriosa sommatoria di Riemann. Ma niente paura, lo faremo con esempi pratici, formule matematiche e una buona dose di entusiasmo!

L’importanza di studiare e approfondire la matematica sarà il nostro messaggio finale. Vi incoraggiamo a cogliere le competenze necessarie per affrontare le sfide future con successo. Concluderemo il nostro viaggio sottolineando quanto il vostro impegno nello studio di queste materie possa aprirvi le porte a un mondo di opportunità.

Preparatevi per un’avventura intellettuale che vi farà apprezzare il potere della matematica e della programmazione nel plasmare il nostro mondo!

Requisiti dell’applicazione

Ora che ho finito di farvi la predica, andiamo a vedere un esempio, o case study, come lo chiamano adesso, nel quale potrebbe servire effettuare dei calcoli abbastanza avanzati.

Il caso è il seguente:

  • siamo un assicurazione per automobili
  • riceviamo da un’app di navigazione satellitare una serie di misure di velocità in km/h per ogni secondo percorso da un autovettura. Ipotizziamo che questo ci servirà in futuro per valutare lo stile di guida della persona assicurata
  • da questi dati, dobbiamo ricavare:
    • l’accelerazione massima
    • la decelerazione massima
    • la velocità massima
    • i picchi momentanei di velocità massima tra ogni variazione di accelerazione
    • la distanza percorsa dal tempo a al temp

Visualizzazione grafica del problema

Per questo esperimento scriviamo il programma in php utilizzando questo sito: https://php-play.dev

Ogni indice $s del vettore $speed corrisponde ad un passo di 1 secondo nell’asse del tempo, altrimenti avrei dovuto usare due liste, una per il tempo e una per la velocità, ma ho voluto semplificare per una maggiore comprensione dell’articolo.

Riassumendo il concetto:

  • l’indice $s contiene i valori 0,1,2…. secondi
  • il vettore $speed[$s] contiene i valori della velocità nell’istante $s

Dichiariamo l’array $speed (in rosso). I valori nell’asse delle ordinate (km/h) in questo caso sono i seguenti:

In PHP, come in quasi tutti i linguaggi di programmazione, gli indici degli array iniziano da 0. Quindi, quando diciamo speed[0], ci stiamo riferendo al primo elemento del vettore (che da ora chiameremo “array”) speed, che rappresenta la velocità nell’istante s=0. Quando diciamo speed[1], ci stiamo riferendo al secondo elemento dell’array, che rappresenta la velocità nell’istante s=1, e così via.

Ecco un esempio più dettagliato con i primi tre indici:

  • speed[0] = 0 km/h: Questo significa che nell’istante s=0 (all’inizio), la velocità è 0 km/h.
  • speed[1] = 20 km/h: Questo significa che nell’istante s=1, la velocità è  20 km/h.
  • speed[2] = 30 km/h: Questo significa che nell’istante s=2, la velocità è  30 km/h.
  • Questo “funzionamento” continua per tutti gli elementi nell’array speed. 
  • L’indice $s dell’array quindi in questo caso corrisponde all’istante nel tempo, e il valore corrispondente in speed[$s] rappresenta la velocità in quell’istante.

Contando la dimensione dell’array, cioè il numero totale di elementi (indici) all’interno di speed, possiamo sapere quale sarà l’ultimo indice, ovvero la dimensione dell’array meno uno. Per calcolare la dimensione si usa la funzione count(array). 

Quindi scriviamo nell’editor di PHP:

Così facendo vediamo che la lista contiene 27 elementi, e visto che l’indice non parte da 1 ma da 0, l’ultimo indice sarà il 26 (dimensione – 1).  Questo significa che possiamo arrivare al massimo a $speed[26]. Ora andiamo ad affrontare i problemi uno ad uno.

Prima cosa, dobbiamo trovare l’istante di massima accelerazione, o più precisamente l’intervallo temporale di massima accelerazione. Andiamo a costruire il grafico dei tempi nell’asse orizzontale e velocità nell’asse verticale di questi punti con OpenOffice Calc, un software simile ad Excel dove poter inserire dati.

Per riportare i valori della velocità nel foglio di calcolo, ho bisogno che siano scritti in colonna. Quindi per evitare di copiarli uno ad uno dalla lista sopra, sfrutto il linguaggio di programmazione per scriverli in colonna, utilizzando il ciclo “foreach”.

PHP ci mostra queste linee da copiare in OpenOffice Calc:

  • 0
  • 20
  • 30
  • 34
  • 40
  • 40
  • 40
  • 40
  • 30
  • 10
  • 20
  • 30
  • 30
  • 32
  • 31
  • 30
  • 20
  • 10
  • 20
  • 40
  • 70
  • 73
  • 73
  • 73
  • 40
  • 20
  • 0

Ok, copiamo tutti i valori di velocità nella colonna A di Calc. 

E’ importante dire che in questo caso ho inserito solo i valori di velocità perché il passo del vettore tempo è sempre uno, e OpenOffice Calc utilizza i numeri naturali di default sull’asse delle ascisse. Altrimenti bisognerebbe inserire entrambe le colonne e usare il grafico a dispersione (che si chiama XY in Calc). Ora selezioniamo tutte le righe della colonna A, e andiamo in Inserisci > Grafico. Selezioniamo il tipo di grafico a linea senza opzioni aggiuntive. Continuiamo ad andare sempre Avanti e nel Passo 4 mettiamo:

  • asse ascisse: s (secondi)
  • asse ordinate: km/h (chilometri orari)

Alla fine otteniamo quindi il seguente risultato:

Per comprendere il significato del grafico analizziamo alcune situazioni, tenendo presente che l’accelerazione rappresenta la pendenza del grafico delle velocità.

Ad esempio, tra 0 secondi e 1 secondo la velocità aumenta, e si nota nel grafico che procedendo da sinistra a destra il grafico procede in salita. La salita significa che l’accelerazione è positiva, quindi il segno sarà +. Tra 1 e 2, è ancora positiva, ma ha un valore numerico inferiore perché il grafico è meno ripido.

Viceversa ad esempio nell’intervallo 8 e 9 il segmento che raccorda i due punti da sinistra a destra va in discesa, quindi l’accelerazione è negativa (segno -).

Quindi chiaramente l’accelerazione maggiore è dove il grafico sale più “ripidamente”. 
Viceversa il grafico ha una pendenza sempre più ripida verso il basso (segno -) man mano che la decelerazione (o la frenata) diventa più forte.

Concetto di base della derivata

Per essere più precisi, gli istanti di maggiore accelerazione e decelerazione si trovano con le DERIVATE (per essere ancora più precisi con le derivate prime). Se andiamo a vedere la definizione formale di derivata in un punto, infatti questa viene indicata come “limite del rapporto incrementale della funzione in quel punto al tendere dell’incremento a zero”. 

La derivata è quella funzione che associa ad ogni punto il valore della derivata in quel punto. Per arrivare al concetto di derivata, però, bisogna necessariamente passare per il concetto di rapporto incrementale.

Il rapporto incrementale

Nel nostro caso i valori del tempo, indicati con s, sono discreti invece che continui. Non potendo far tendere a zero la distanza tra di essi (dopo vedremo che cosa significa), scelgo di valutare il rapporto incrementale sulla distanza minima che possono avere l’uno dall’altro. Questa distanza si chiama passo, che nel nostro caso è costantemente 1 tra un istante s e il successivo.

  • prendiamo il punto (s[0], $speed[s[0]]) che nomino “a”
  • prendiamo il punto (s[0], $speed[s[0]]) che nomino “b”
  • prendiamo il punto (s[1], $speed(s[0])) che chiamo h. h significa incremento

A questo punto disegniamo sull’asse parallelo all’asse dei tempi (s) il segmento che collega (a, h), e sull’asse parallelo a quello delle velocità disegnamo il segmento (h,b). Così facendo si  forma un triangolo rettangolo, quindi:

  • calcolo la divisione tra i due cateti ottenuti da $s ed $speed(s)
  • Così facendo ottengo il rapporto incrementale, ovvero la pendenza media in quell’intervallo.

Nel caso del nostrografico della velocità nel tempo, questo rapporto indica l’accelerazione media tra i due “istanti”, ovvero la derivata media tra due punti.

Esempio di derivata in una funzione continua

Se il tempo variasse con continuità, cioè se potessi valutare la velocità in ogni istante, come nel secondo 2.000000000001, e quindi se funzione fosse continua, come ad esempio nel caso di , chiaramente le differenze dei tempi (Δs) potrebbero diventare talmente vicine allo zero, tendendo al limite, che diventerebbero infinitesimali. In questo caso il DELTA (Δ) prenderebbe il nome di differenziale, e verrebbe indicato con la lettera .

Probabilmente vi è stato insegnato che una tangente tocca una curva in un solo punto, e questo è corretto. Tuttavia, se esaminiamo il concetto più da vicino, vediamo che la tangente può essere vista come una secante che passa per due punti sulla curva che sono così vicini l’uno all’altro che la loro distanza diventa infinitesimale. In altre parole, i due punti si avvicinano così tanto da sembrare un unico punto. Questo è il fondamento del calcolo infinitesimale e del concetto di derivata.

Chiaramente, nel nostro caso, essendo il passo 1, non possiamo agire con calcoli differenziali. Siccome conosciamo solo i valori discreti non possiamo ottenere la DERIVATA ESATTA (o derivata istantanea), ma solo la derivata media, ovvero la pendenza media in un intervallo, che può essere anche indicata semplicemente come rapporto incrementale.
Esempio di rapporto incrementale tra due punti casuali della funzione :

ora se sostituiamo s con dei numeri, e facciamo i calcoli dei rapporti incrementali nei primi intervalli, otteniamo:

Δf(s) = 1-0        1
_________ =   __ = 1
Δs = 1-0            1

Δf(s) = 4-1        3
_________ =   __ = 3
Δs = 2-1            1

Δf(s) = 9-4       5
_________ =   __ = 5
Δs = 3-2           1

Δf(s) = 16-9       7
_________ =   __ = 7
Δs = 4-3            1

Quindi il rapporto incrementale (pendenza) aumenta LINEARMENTE di 2 unità per ogni “passo”. Possiamo vedere questo rapporto incrementale come una retta secante tra i due punti.

Tirando al limite verso zero uno degli intervalli fino ad ottenere una distanza infinitesimale, otteniamo la derivata ESATTA di , che in qualsiasi punto è uguale a 2s

Questo significa che in s=2 la derivata (quindi la pendenza o tangente) sarà uguale a 4, mentre in s=6 sarà uguale a 12, in s=8 sarà uguale a 16, e così via.

Chiaramente, essendo quella del grafico una funzione semplice, è facilissimo calcolare la derivata esatta utilizzando le regole delle cosiddette “derivate fondamentali”.

Iniziamo a programmare seriamente

andiamo quindi a creare un ciclo che calcoli il rapporto incrementale per ogni Δs.

Quindi dovremmo:

  • partire da Δs=0
  • salire per ogni passo (1s)
  • fermarsi all’indice massimo di $speed (lunghezza degli elementi – 1, in questo caso 26)

Andiamo a creare un ciclo per eseguire questa operazione. Il ciclo più “naturale” e semplice che si possa utilizzare secondo me è il while.

Eseguendo questo codice ottengo i seguenti rapporti incrementali:

20, 10, 4, 6, 0, 0, 0, -10, -20, 10, 10, 0, 2, -1, -1, -10, -10, 10, 20, 30, 3, 0, 0, -33, -20, -20

Punti critici massimi assoluti

L’accelerazione massima è nel punto in cui il rapporto incrementale è maggiormente positivo. Inseriamo una variabile per memorizzare il valore massimo trovato. 

Il punto in cui il rapporto incrementale sarà maggiormente negativo è dove c’è la massima decelerazione. Inseriamo una variabile per memorizzare il valore minimo trovato (sotto lo zero). 

$max_accel){
      $max_accel=$incremental;
   }


   if($incremental";
echo "max_accel: ". $max_accel. " km/h per second";
echo "
"; echo "max_decel: ". $max_decel. " km/h per second";

Già con queste modifiche, eseguendo lo script, otteniamo il seguente risultato:

Quindi siamo già a cavallo.


La richiesta successiva è di trovare la velocità massima, cosa molto facile analizzando tutti gli elementi di speed. Modifico il codice:

$max_speed){
   $max_speed=$actual_speed;
  }

  //indice dell’incremento di f(s)
  $h = $s_index + 1;

  //delta s sarà sempre 1 s
  $delta_s = 1;

  //delta f(s)
  $delta_speed_s = $speed[$h] - $actual_speed;

  //calcolo il rapporto incrementale
  $incremental = $delta_speed_s / $delta_s;

  if($incremental>$max_accel){
     $max_accel=$incremental;
  }

  if($incremental";
echo "max_speed (km/h): " . $max_speed;
echo "
"; echo "max_accel: ". $max_accel. " km/h per second"; echo "
"; echo "max_decel: ". $max_decel. " km/h per second";

Eseguendo questo script, otteniamo il seguente risultato:

Punti critici massimi locali

La richiesta successiva è di trovare i picchi momentanei di velocità massima tra ogni variazione di accelerazione.

Se la funzione fosse continua avrebbe più senso partire dal calcolo della derivata seconda (derivata della derivata prima) per trovare i punti critici. 

Siccome però siamo in una funzione a valori discreti, e la derivata seconda già di per sé potrebbe scambiare un punto flesso (una curva piatta) per un massimo locale, e inoltre è ancora meno precisa nelle funzioni a valori discreti, in questo caso utilizziamo un altro approccio secondo me molto migliore, cioè quello dell’istante nel quale cambia il segno (cioè la direzione della curva nel grafico).

Quindi ragionandoci:

  • quando l’ultimo rapporto incrementale precedente conosciuto (la pendenza va in “su”) era maggiore di 0, e il rapporto successivo è minore di 0 (la pendenza “scende”), ci troviamo probabilmente in un punto massimo locale 
  • quando l’ultimo rapporto incrementale precedente conosciuto era minore di 0, e il rapporto successivo è maggiore di 0, ci troviamo probabilmente in un punto minimo locale

Questo è basato sul fatto che in un punto massimo locale, la pendenza della funzione è positiva prima del punto e diventa negativa dopo, mentre in un punto minimo locale, la pendenza è negativa prima del punto e diventa positiva dopo. 

Andiamo a modificare il codice per scoprire i massimi locali:

 $max_speed) {
       $max_speed = $actual_speed;
   }

   //indice dell’incremento di f(s)
   $h = $s_index + 1;

   //delta s sarà sempre 1 s
   $delta_s = 1;

   //delta f(s)
   $delta_speed_s = $speed[$h] - $actual_speed;

   //calcolo il rapporto incrementale
   $incremental = $delta_speed_s / $delta_s;

   if ($incremental  0 && $previousSign != "+") {
       $previousSign = "+";
   }

   if ($incremental > $max_accel) {
       $max_accel = $incremental;
   }

   if ($incremental ";
echo "
"; echo "incrementals (km/h per second): " . join(', ', $incrementalList); echo "
"; echo "
"; echo "localMaxima (km/h): " . join(', ', $localMaxima); echo "
"; echo "
"; echo "max_speed (km/h): " . $max_speed; echo "
"; echo "
"; echo "max_accel: " . $max_accel . " km/h per second"; echo "
"; echo "
"; echo "max_decel: " . $max_decel . " km/h per second";

Distanza percorsa con gli integrali definiti

L’ultima richiesta è di trovare la distanza percorsa (presumendo che sia in metri) dal secondo a al secondo b. Per fare questo, chi avesse familiarità con la matematica, saprebbe sicuramente che bisogna integrare, ovvero trovare l’area sotto al grafico. 

Per evitare incoerenze tra le unità di misura, devo prima di tutto convertire il secondo di riferimento in ora, dato che ho le velocità di  chilometri orari. 

Quindi devo dividere un secondo per 3600 e moltiplicarlo per i km/h, ottenendo così lo spazio percorso in quel tempo ed effettuare la sommatoria con tutti gli altri intervalli.

L’integrale altro non è che la sommatoria di tutti i delta nell’intervallo (a,b) rispetto ad s (i secondi), nel nostro caso, moltiplicati per la funzione in s in tutti i delta dell’intervallo. 

Nell’integrale però al posto del delta di usa un differenziale, quindi l’integrale è in realtà una somma dei prodotti tra i differenziali e la funzione in s in quei punti.

Per questo l’integrale definito è indicato come “la somma di un numero di partizioni tendenti all’infinito in un intervallo definito”.
In pratica è come sommare tanti rettangoli finissimi uno dopo l’altro, sotto alla curva del grafico. Questa procedura è chiamata anche “sommatoria di Riemann”.

Didascalia: Esempio di sommatoria di Riemann. 

NB Se le aree degli intervalli sono sotto la curva, la somma si dice “inferiore”, quindi corrisponde all’area sotto-stimata della curva. 

Se le aree degli intervalli superano la curva la somma si dice “superiore”, quindi è l’area sovra-stimata della funzione. 

Per calcolare l’area precisa bisogna che le somme inferiori e superiori siano corrispondenti.

Per essere corrispondenti o ben approssimate, bisogna che le partizioni dell’intervallo siano di numero maggiore possibile, quindi si dice che “tendono ad infinito”, cioè che tendono ad un numero di partizioni infinito.

Il simbolo dell’integrale è una S, scritta ∫, che sta ad indicare appunto una “somma”, e si usa un simbolo differente per distinguerlo dalla normale sommatoria, che si indica con Σ (sigma).

In questo caso, siccome i delta al limite tendente a 0 NON sono infinitesimali, ma sono discreti (1 secondo), l’integrale prenderà la forma di sommatoria tra i vari intervalli per la loro funzione.

Come partizione quindi prenderò l’area del triangolo rettangolo da dove è stato calcolato il rapporto incrementale + l’area del rettangolo sotto, e dopo averlo salvato in una lista calcolo la differenza tra:

  • la somma degli indici fino a b 
  • la somma degli indici fino ad a

Così facendo troveremo l’integrale definito, ovvero appunto, l’area tra due intervalli discreti, in questo caso.

Parentesi sul concetto di integrale indefinito

Se integri un’accelerazione espressa rispetto al tempo, ottieni la funzione della  velocità rispetto al tempo. Viceversa se derivi la velocità rispetto al tempo, ottieni l’accelerazione rispetto al tempo. 

Il fatto che l’integrale sia l’inverso della derivata vale sempre, e ovviamente vale anche viceversa.

Quindi la seguente equazione è sempre vera, ed è nota come “Teorema Fondamentale del Calcolo Integrale”:

Infatti:

– f è la funzione integranda, ma è al contempo la derivata di F

– F è la primitiva, chiamata anche anti-derivata, o integrale indefinito di f. 

L’integrale indefinito è una famiglia di funzioni, ciascuna delle quali ha f come sua derivata.

Ora, pensa a ogni persona come a una funzione. Ogni funzione è unica, ma tutte le funzioni in una “famiglia di funzioni” condividono alcune caratteristiche comuni che le legano insieme come famiglia. Queste caratteristiche comuni potrebbero essere la forma generale della funzione, o il modo in cui la funzione si comporta, o una particolare proprietà matematica.

Per essere più specifici, l’integrale indefinito appartiene sempre all’insieme dei numeri reali, e quindi si può calcolare generalmente solo nelle funzioni continue, tranne casi particolari, e finisce sempre con + c, perché derivando la primitiva la derivata perde sempre la costante. 

Infatti i valori costanti nel grafico sarebbero rappresentati da una linea piatta, quindi pendenza 0, quindi resterebbe + 0 nella funzione derivata.

Quindi l’integrale definito si porta sempre con sé tutta la famiglia di costanti della funzione primitiva.

– F(a) – F(b) è l’integrale definito tra due intervalli, ovvero l’area tra due intervalli [a, b].

Chiusa parentesi

 $max_speed) {
     $max_speed = $actual_speed;
  }

  //intervallo di incremento di f(s) = 1 second
  $h = $s_index + 1;

  //delta s sarà sempre 1 s
  $delta_s = 1;

  //delta f(s)
  $delta_speed_s = $speed[$h] - $actual_speed;

  //calcolo il rapporto incrementale
  $incremental = $delta_speed_s / $delta_s;

  if($incremental0 && $previousSign!="+"){
     $previousSign="+";
  }

  if ($incremental > $max_accel) {
     $max_accel = $incremental;
  }

  if ($incremental  0) {
     // echo "actualSpeed: ".$actual_speed."\n";
     // echo "afterSpeed: ".$speed[$h]."\n";
     // echo "rectangleArea: ".$speed[$h]."\n";
     $baseRectangleHeight = $actual_speed;
  } else {
     // echo "actualSpeed: ".$actual_speed."\n";
     // echo "afterSpeed: ".$speed[$h]."\n";

     // $triangleArea=;
     // echo "rectangleArea: ".$speed[$h]."\n";
     $baseRectangleHeight = $speed[$h];
  }

  $baseRectangleArea = $delta_s * $baseRectangleHeight;
  $triangleArea =  $delta_s * abs($delta_speed_s) / 2;

  $intervalArea = $baseRectangleArea + $triangleArea;

  //converto le ore in secondi (moltiplicando per 3600) per sapere i km percorsi nell'intervallo
  //divido per 1000 per sapere i metri percorsi in quell'intervallo
  $intervalAreas[] = $intervalArea * 1000 / 3600;


  /*echo "incremental: " . $incremental . "\n";
  echo "baseRectangleWidth: " . $delta_s . "\n";
  echo "baseRectangleHeight: " . $baseRectangleHeight . "\n";
  echo "baseRectangleArea: " . $baseRectangleArea . "\n";

  echo "baseTriangleWidth: " . $delta_s . "\n";
  echo "triangleHeight: " . abs($delta_speed_s) . "\n";
  echo "triangleArea: " . $triangleArea . "\n";

  echo "totalArea: " .$intervalArea . "\n";
  echo "\n";
  echo "\n";*/

  //aumento l'indice
  $s_index = $h;
}

function areaBelowCurve($from_index_a, $to_index_b)
{
  global $intervalAreas;

  $sum_b = array_sum(array_slice($intervalAreas, 0, $to_index_b));

  $sum_a = array_sum(array_slice($intervalAreas, 0, $from_index_a));

  return round($sum_b - $sum_a, 2);
}

echo "speeds (km/h): " . join(', ', $speed);
echo "
"; echo "
"; echo "incrementals (km/h per second): " . join(', ', $incrementalList); echo "
"; echo "
"; echo "localMaxima (km/h): " . join(', ', $localMaxima); echo "
"; echo "
"; echo "intervalAreas (meters covered in interval): " . join(', ', $intervalAreas); echo "
"; echo "
"; echo "max_speed (km/h): " . $max_speed; echo "
"; echo "max_accel: " . $max_accel . " km/h per second"; echo "
"; echo "max_decel: " . $max_decel . " km/h per second"; echo "
"; echo "area below index 2 and 5 (meters covered in 3 seconds from 8.8... to the first 11.1... in 2 decimals): " . areaBelowCurve(2, 5); echo "
";

Miglioramento del codice

Per completezza, finisco riscrivendo il codice ottimizzato, dato che prima era stato semplificato nella speranza di una maggiore comprensione da parte di tutti. 

Inoltre ho aggiunto alcune caratteristiche molto utili, quali ad esempio gli indici che corrispondono nel nostro caso agli istanti di tempo nei quali abbiamo trovato un certo valore di velocità.


    */
   private array $speed = [];

   /**
    * @var array
    */
   private array $incrementalList = [];

   /**
    * @var array
    */
   private array $intervalAreas = [];

   /**
    * @var array
    */
   private array $localMaximaIndexes = [];

   /**
    * @var array
    */
   private array $localMaxima = [];

   private float $maxAcceleration = 0;
   private int $maxAccelerationIndex = 0;
   private float $maxDeceleration = 0;
   private int $maxDecelerationIndex = 0;
   private int $maxSpeedIndex = 0;
   private float $maxSpeed = 0;
   private string $previousSign = '=';

   /**
    * Constructor.
    *
    * @param array $speed
    */
   public function __construct($speed)
   {
       $this->speed = $speed;


       $this->analyseValues();
   }

   public function areaBelowCurve(int $from_index_a, int $to_index_b): float
   {
       $sum_b = array_sum(array_slice($this->intervalAreas, 0, $to_index_b));


       $sum_a = array_sum(array_slice($this->intervalAreas, 0, $from_index_a));


       return round($sum_b - $sum_a, 2);
   }

   /**
    * @return array
    */
   public function getSpeed()
   {
       return $this->speed;
   }

   /**
    * @return array
    */
   public function getIncrementalList()
   {
       return $this->incrementalList;
   }

   /**
    * @return array
    */
   public function getLocalMaximaIndexes()
   {
       return $this->localMaximaIndexes;
   }

   /**
    * @return array
    */
   public function getLocalMaxima()
   {
       return $this->localMaxima;
   }

   /**
    * @return array
    */
   public function getIntervalAreas()
   {
       return $this->intervalAreas;
   }

   public function getMaxSpeedIndex(): int
   {
       return $this->maxSpeedIndex;
   }

   public function getMaxSpeed(): float
   {
       return $this->maxSpeed;
   }

   public function getMaxAccelerationIndex(): int
   {
       return $this->maxAccelerationIndex;
   }

   public function getMaxAcceleration(): float
   {
       return $this->maxAcceleration;
   }

   public function getMaxDecelerationIndex(): int
   {
       return $this->maxDecelerationIndex;
   }

   public function getMaxDeceleration(): float
   {
       return $this->maxDeceleration;
   }

   private function analyseValues(): void
   {
       $arraySize = count($this->speed);

       if ($arraySize maxSpeed = $this->speed[0];

       $delta_s = 1;

       for ($s_index = 0; $s_index speed[$s_index];

           if ($actual_speed > $this->maxSpeed) {
               $this->maxSpeed = $actual_speed;
               $this->maxSpeedIndex = $s_index;
           }

           $h = $s_index + $delta_s;

           $delta_speed_s = $this->speed[$h] - $actual_speed;

           $incremental = $delta_speed_s / $delta_s;

           if ($incremental previousSign) {
               $this->localMaxima[] = $actual_speed;
               $this->localMaximaIndexes[] = $s_index;
               $this->previousSign = '-';
           } elseif ($incremental > 0 && '+' != $this->previousSign) {
               $this->previousSign = '+';
           }

           if ($incremental > $this->maxAcceleration) {
               $this->maxAcceleration = $incremental;
               $this->maxAccelerationIndex = $s_index;
           }

           if ($incremental maxDeceleration) {
               $this->maxDeceleration = $incremental;
               $this->maxDecelerationIndex = $s_index;
           }

           $this->incrementalList[] = $incremental;

           if ($delta_speed_s > 0) {
               $baseRectangleHeight = $actual_speed;
           } else {
               $baseRectangleHeight = $this->speed[$h];
           }

           $baseRectangleArea = $delta_s * $baseRectangleHeight;

           $triangleArea = $delta_s * abs($delta_speed_s) / 2;

           $intervalArea = $baseRectangleArea + $triangleArea;

           $this->intervalAreas[] = $intervalArea * 1000 / 3600;
       }
   }
}

$speed = [0, 20, 30, 34, 40, 40, 40, 40, 30, 10, 20, 30, 30, 32, 31, 30, 20, 10, 20, 40, 70, 73, 73, 73, 40, 20, 0];

$analyzer = new Maps($speed);

echo 'Speeds (km/h): '.implode(', ', $analyzer->getSpeed()).'

'; echo 'Incrementals (km/h per second): '.implode(', ', $analyzer->getIncrementalList()).'

'; echo 'Local Maxima Indexes: '.implode(', ', $analyzer->getLocalMaximaIndexes()).'

'; echo 'Local Maxima (km/h): '.implode(', ', $analyzer->getLocalMaxima()).'

'; echo 'Interval Areas (meters covered in interval): '.implode(', ', $analyzer->getIntervalAreas()).'

'; echo 'Max Speed Index: '.$analyzer->getMaxSpeedIndex().'
'; echo 'Max Speed (km/h): '.$analyzer->getMaxSpeed().'
'; echo 'Max Acceleration Index: '.$analyzer->getMaxAccelerationIndex().'
'; echo 'Max Acceleration: '.$analyzer->getMaxAcceleration().' km/h per second
'; echo 'Max Deceleration Index: '.$analyzer->getMaxDecelerationIndex().'
'; echo 'Max Deceleration: '.$analyzer->getMaxDeceleration().' km/h per second
'; echo 'Area below index 2 and 5 (meters covered in 3 seconds from 8.8... to the first 11.1... in 2 decimals): '. $analyzer->areaBelowCurve(2, 5) . '
';

Note finali e conclusioni

Potete trovare il codice in GitHub nella seguente repository: https://github.com/dade1987/Learning-Math-Through-PHP

PS Il codice è stato validato staticamente con PHPStan a livello massimo. E’ formattato con CSFixer. Affrontare i problemi con saggezza è fondamentale in ogni contesto, sia professionale che personale. 

La disponibilità di strumenti adeguati può essere la chiave per rendere questo processo più agevole ed efficace. Lo studio e l’approfondimento delle materie scolastiche, fornisce gli strumenti intellettuali necessari per comprendere e risolvere i problemi in vari ambiti.

Dedicare tempo ed energie allo studio di tutte le materie a scuola è cruciale per acquisire le competenze necessarie per affrontare le sfide future con successo. 

Davide Cavallini
Davide Cavallini è un esperto sviluppatore senior specializzato in Laravel e JavaScript, con una notevole esperienza come penetration tester. La sua carriera è caratterizzata da un impegno nell'insegnamento e nella condivisione della sua conoscenza, contribuendo alla formazione di nuovi professionisti nel campo dello sviluppo software e della sicurezza informatica. La sua passione per la tecnologia lo spinge a rimanere sempre aggiornato e a esplorare nuove frontiere dell'informatica.