Blitz Course

IEEE Doppia precisione in Blitz2


Stavo scrivendo un programma di calcoli astronomici (probabilmente lo pubblicherò uno dei prossimi mesi) quando mi sono accorto che l'accuratezza matematica di Blitz2 è terribilmente scarsa: il tipo float può contenere solo numeri bassi e le routine di conversione (ad es.: Val) hanno qualche baco. Quindi ho deciso di implementare i potenti algoritmi della doppia precisione Ieee in ambiente Blitz2. Il mio lavoro è stato ispirato dal modulo "longreal" scritto in AmigaE da EA van Breemen.

Per usare il mio codice non dovete far altro che XINCLUDErlo all'inizio del vostro programma, ed assicurarvi di avere le due librerie "mathieeedoubbas.library" e "mathieeedoubtrans.library" sul vostro disco di sistema.

Il nome del tipo in doppia precisione è "longreal": esso è costituito da due longword. Potete usarlo solo per mezzo dei puntatori: vale a dire, per creare una variabile longreal dovete definirla (DEFTYPE) come un puntatore a longreal e poi inizializzarla utilizzando la funzione dNew{}. Ecco un esempio:

      DEFTYPE.longreal *pippo
      *pippo=dNew{}

e poi potete usare *pippo con le routine a doppia precisione (attenzione a non dimenticare l'asterisco (*)!). Se dimenticate di inizializzare una variabile prima di usarla, la vostra macchina gurerà. Ovviamente potete maneggiare una variabile longreal solo per mezzo delle routine a doppia precisione poiché il tipo longreal non è un tipo primitivo di Blitz2 (è una specie di trucco). Prima di uscire dal programma dovete liberare tutte le variabili longreal che avete precedentemente inizializzato: per far ciò scrivete semplicemente

      dFree{*pippo}
Se dimenticate di liberare una variabile, la memoria allocata per essa verrà persa.

Ora descriverò le routine di conversione. Per inserire un numero a doppia precisione dovete scriverlo in una stringa e poi convertirlo in un longreal utilizzando la funzione a2d{}:

      a2d{stringa$, *longreal}

La variabile *longreal conterrà il vostro numero. La funzione a2d{} accetta anche la notazione scientifica: 12e3 o 12E3. Per riconvertire il numero in stringa vi sono due funzioni: dFormat{} e dLFormat{}. La prima è utilizzata per numeri piccoli e non negativi, mentre la seconda accetta ogni tipo di numero (e permette anche l'output in notazione scientifica). La sintassi è:

      stringa$=dFormat{*longreal, cifre}

      stringa$=dLFormat{*longreal, cifre, potenza_max}
dove: *longreal è il numero da convertire; cifre è il numero di caratteri ascii utilizzati per rappresentare il numero convertito; potenza_max è una specie di soglia: se il numero è maggiore di 10^potenza_max allora la routine userà la notazione scientifica.

Le altre routine costituiscono tutte le operazioni che potete effettuare sul tipo a doppia precisione: in generale, esse accettano uno o due longreal come argomenti e pongono il risultato dell'operazione nel primo argomento, quindi ricordatevi di copiarlo se non volete perderlo. Per copiare un longreal usate

      dCopy{*longreal1, *longreal2}

dove, come dice la regola generale, la variabile destinazione è la prima. Routine insolite, per quanto riguarda la loro sintassi, sono

      long=dFix{*longreal}

converte un longreal in intero;

      dFloat{long, *longreal}

converte un intero in longreal;

      risultato=dTst{*longreal}

confronta *longreal con il valore 0.0: resituisce -1 se *longreal<0, 0 se *longreal=0 e 1 se *longreal>0;

      risultato=dCompare{*longreal1, *longreal2}

confronta i due longreal e restituisce: -1 se *longreal1<*longreal2, 0 se *longreal1=*longreal2 e 1 se *longreal1>*longreal2;

      dDouble{IeeeSingle, *longreal}

converte un valore Ieee singola precisione in un valore a doppia precisione;

      IeeeSingle=dSingle{*longreal}

converte un valore a doppia precisione in un valore a singola precisione;

      dPi{*longreal}

mette il valore di Pi (3.141592...) in *longreal. Esempi di operazioni standard sono

      dAdd{*longreal1, *longreal2}

somma i due numeri e restituisce il risultato in *longreal1;

      dRad{*longreal}

converte i gradi in radianti per essere usati con le funzioni angolari;

      dSqrt{*longreal}

calcola la radice quadrata di *longreal e la pone in *longreal. A proposito: non vi è controllo per errori come passare un argomento negativo a dSqrt{}, dovete farlo voi; e se passate un valore negativo a dSqrt{} la vostra macchina si pianterà senza nemmeno avvisarvi.

Non riporterò tutte le funzioni numeriche implementate: il sorgente è ampiamente commentato e quindi vi invito a dargli un'occhiata.

Per essere sincero devo dire che se convertite, per esempio, il numero "1.23" (con a2d{"1.23",*longreal}) e poi lo riconvertite in stringa (con s$=dFormat{*longreal,10}) vi ritroverete con "1.229999999": probabilmente le routine di conversione possono essere migliorate, ma finora non so se questo è completamente dovuto a me; probabilmente questo è dovuto anche agli errori di arrotondamento del formato Ieee od alla funzione IeeeDPFloor (e/o IeeeDPCeil), inclusa nelle librerie Ieee, che uso durante la conversione.

Per il sorgente in LHA, premere qui.


Pagina Principale


    Scritto da: Andrea Galimberti  e-mail: fsoft@intercom.it
                Via E.Villoresi
                Turbigo (MI)
                ITALY               tel:    (ITA) - (0)331 - 871009