Mathscript
Premetto che è solo da qualche mese che utilizzo
il linguaggio Javascript, anche se è dal
1983 che mi occupo di programmazione. Non
potrò mai dimenticare il primo programma
che implementai, con il mitico Commodore
64: la risoluzione di equazioni di secondo
grado. Poi all'università (1990) un docente
particolarmente illuminato svolse un corso
di programmazione in Basic finalizzato alla
realizzazione di una simulazione grafica
di alcuni argomenti della disciplina (Meccanica
Superiore: ovvero studio del movimento dei
corpi). Io scelsi di trattare le leggi di
Keplero e la loro applicazione nella determinazione
analitica e grafica delle orbite dei corpi
celesti, date le loro condizioni iniziali
(sarà arduo, ma credo che sarà il mio prossimo
script!).
Solo da un anno ho "messo le mani"
su Internet e, come già detto, da qualche
mese su Javascript e debbo assicurare che
ho trovato tale linguaggio, nella sua estrema
semplicità, potente e versatile nel campo
delle implementazioni matematiche. Non mi
ritengo un "classico" esperto di
Javascript perché, se darete un'occhiata
ai file sorgenti dei miei script, noterete
una certa approssimazione formale.
Con il primo script, che ho implementato
per Internet Explorer e che poi è sfociato
in GeoSript, ho cercato di risolvere la gestione
dei pixel in Javascript. Problema non indifferente
per tracciare, per esempio, una curva nel
piano cartesiano e che nei linguaggi "tradizionali"
(persino in Java!) viene risolto con i banali
point, line, circle ecc. In Javascript: niente! Così ho pensato
che l'unico strumento che poteva consentirmi
di gestire i punti dello schermo (e quindi
di una curva da tracciare) era il tag HTML
<DIV>. Ecco cosa ne è uscito:
…
<SCRIPT language="JavaScript">
var i=-400;
var x;
var y;
colore="black";
x0=400;
y0=300;
di=0.2;
while (i>=-400 && i<=400 )
{
x=i+x0;
y=-(i*i)+y0;
document.write("<DIV style='background-color:"+colore+";
position:absolute; left:"+x+";
top:"+y+"; width:1px; height:1px;'><img
SRC='punto.gif' border=0 width=1 height=1></DIV>");
i=i+di;
}
</SCRIPT>
…
Quello che si ottiene è il grafico della
parabola y=x2.
Osservate che la definizione dello stile
per il tag <DIV> non ha valore puramente
estetico ma è necessaria per gestire la dimensione
e la posizione del punto da tracciare.
Il valore delle costanti x0 e y0, così come
il segno negativo di y=-(x*x)+y0, credo che
si possa intuire: trasformare l'orientamento
delle coordinate assolute (0,0)-(800,600)
dello schermo (ho utilizzato una risoluzione
video 800x600) nelle coordinate cartesiane
(-400,300)-(400,-300).
Dopo aver risolto questo problema fondamentale,
ho sviluppato lo script per tracciare il
grafico di qualsiasi retta, parabola o circonferenza
con la possibilità, attraverso un campo <FORM>,
di introdurre i coefficienti delle equazioni.
Ho inoltre creato una pagina con tre frames
che consentivano di utilizzare un'interfaccia
utente funzionale. Vediamo come è strutturata
la funzione grafico() che lo script utilizza
per tracciare le rette:
…
function grafico()
{
indice=document.dati.colori.selectedIndex;
colore=document.dati.colori.options[indice].value;
scala=36;
ar=document.dati.a1.value;
br=document.dati.b1.value;
cr=document.dati.c1.value;
y=0;
x=0;
a=ar;
b=br;
c=cr*scala; //per rendere il grafico proporzionato
i=-range;
while (i>=-range && i<=range
){
if (b == 0) //controlla quando la retta è
parallela all'asse y
{
x=-c/a+x0;
y=-i+y0;
}
else
{
x=i+x0;
y=-(-i*a/b-c/b)+y0
}
if( y<=2*y0 && y>=0) //controlla
che il grafico non venga tracciato fuori
dallo schermo
{
parent.destro.document.write("<DIV
style='background-color :"+colore+";
position:absolute; left:"+x+";
top:"+y+"; width:1px; height:1px;'><img
SRC='punto.gif' border=0 width=1 height=1></DIV>");
i=i+di;
}
else
{
i=i+5;
}
}
}
…
Alcune variabili e funzioni, comuni a tutti
gli script, sono state dichiarate in un file
esterno .js
Credevo di aver fatto un buon lavoro fino
a quando un amico, cui avevo fatto provare
gli script, non mi mise la pulce nell'orecchio:
perché non provare a implementare uno script
che consenta di tracciare QUALSIASI FUNZIONE?
In fondo lo script che avevo implementato
non era molto versatile e consentiva di tracciare
curve già predefinite e con la semplice introduzione
di coefficienti numerici. Lui mi disse che
in rete aveva trovato dei siti, soprattutto
uno francese, che facevano miracoli. Mi accorsi
che tutti utilizzavano degli applet Java
oppure programmi CGI (ovviamente nessuno
era implementato in Javascript!). Accettai
la sfida.
Nel frattempo ero anche riuscito a trovare
un manuale di Javascript su carta: M. Moncur,
Imparare Javascript 1.3 in 24 ore, Tecniche Nuove.
Per prima cosa mi occorreva una funzione
Javascript che "leggesse" la funzione
matematica introdotta dall'esterno (ovviamente
con una precisa sintassi) e un'altra che
la "trasformasse" in una espressione
compatibile con l'oggetto Math di Javascript.
…
function init()
{
immessa=document.dati.input.value;
lunghezza=immessa.length;
if(lunghezza < 1)
{
window.alert("Non è stata inserita nessuna
funzione.");
return;
}
for (t=0; t<lunghezza; t++)
{
ch[t]=immessa.charAt(t);
}
scan();
if(ok)
{
convalida();
}
else
{
simbolica="";
ok=true;
return;
}
}
.......
.......
function scan()
{
simbolica = "";
variabile="(i/scala)"
arc=false;
j=0;
do
{
switch(ch[j])
{
case "x" : simbolica +=variabile;
break;
case "s" : if (ch[j+1]=="i"
&& ch[j+2]=="n")
{
if (arc)
{
simbolica += "Math.asin";
arc=false;
j=j+2;
}
else
{
simbolica += "Math.sin";
j=j+2;
arc=false;
}
}
else
{
sconosciuta();
}
break;
……
……
case "p" : simbolica +="Math.PI";
break;
case "(" : simbolica +="(";
break;
case ")" : simbolica +=")";
break;
case "+" : simbolica +="+";
break;
case "-" : simbolica +="-";
break;
case "*" : simbolica +="*";
break;
case "/" : simbolica +="/";
break;
default : window.alert("Carattere "+ch[j]+"
sconosciuto!");
ok=false;
return false;
}
j=j+1
}
while (j<lunghezza)
}
…
Per esempio introducendo la stringa p*sin(x)/arcsin(x), essa viene trasformata in Math.PI*Math.sin(i/scala)/Math.asin(i/scala)
A questo mi mancava il passaggio dalla stringa
simbolica alla funzione numerica. Quasi per
caso riuscii a scoprire che il metodo eval() faceva al caso mio. Ecco il risultato:
…
function fun(valore)
{
this.valore=valore;
}
funzione=new fun();
function traccia()
{
indice=document.dati.colori.selectedIndex;
colore=document.dati.colori.options[indice].value;
i=inf;
while (i>=inf && i<=sup)
{
funzione.valore = eval(simbolica);
if (funzione.valore && funzione.valore*scala>y0-460
&& funzione.valore*scala<y0)
{
grafico();
}
else
{
i=i+di;
}
}
info.style.visibility="hidden";
info2.style.visibility="visible";
return;
}
function grafico()
{
i=i+di;
x=i+x0;
y=-funzione.valore*scala+y0;
parent.destro.document.write("<DIV
style='background-color :"+colore+";
position:absolute; left:"+x+";
top:"+y+"; width:1px; height:1px;'><img
SRC='punto.gif' border=0 width=1 height=1></DIV>");
}
…
Dopo di che lo script era quasi completo.
Successivamente ho elaborato lo stesso script
per Netscape (solo qualche cambiamento) e
ho aggiunto, solo nella versione per Internet
Explorer, qualche piccolo particolare: la
scala di rappresentazione, le coordinate
del puntatore del mouse, la possibilità di
spostare il grafico, tutta la parte grafica
(pulsanti con effetti rollover, la calcolatrice,
ecc.)
Con qualche piccola modifica, ho poi utilizzato
lo stesso script per implementare quelli
riguardanti il calcolo di derivata e integrale,
le curve in coordinate parametriche e polari.
Ecco come è nato Mathscript.