In passato ho parlato a più riprese sia dell'opportunità di introdurre nuovi formati standard di numeri "floating point" con lunghezza "ottimale" di 48 o 52 bit, sia della necessità di estendere l'intervallo di valori codificati dagli standard FPF tramite il ricorso a varie tecniche, in particolare quella del "variable exponent" da me ideata. Questo ennesimo lavoro presenta una via particolarmente appetibile per ottenere questo scopo, in quanto semplice e molto efficiente; essa è stata pensata per essere applicata a uno standard di precisione "ottimale" con 52 bit ma, come vedremo, può essere facilmente estesa a formati di lunghezza diversa, in particolare 48 bit e 64 bit (quest'ultimo diventerebbe una sorta di "doppia precisione" modificata, come descritto verso fine articolo).
Il formato "variable exponent" originale consisteva nel dedicare alcuni bit della parola che rappresenta un numero floating ad un nuovo campo detto “exponent lenght” (EL) ; il suo valore esprime il numero dei bit che vengono dedicati all'esponente, a scapito dei restanti bit destinati ad esprimere la mantissa. In questo modo, quando è necessario esprimere numeri estremamente grandi o estremamente piccoli, questo avviene al costo di una precisione numerica ridotta, un compromesso che può risultare utile per evitare fenomeni di "overflow" quando non è richiesta una grande accuratezza nel risultato.
Una importante controindicazione a questo sistema risiede però nel sacrificio di alcuni preziosi bit, che vanno utilizzati per esprimere la lunghezza dell'esponente EL, sottraendo ulteriormente precisione al risultato. Tale sacrificio può essere evitato se il valore di EL viene reso implicito, ri-codificando semplicemente il significato dell'esponente stesso, quando esso si avvicina ai valori estremi (minimo e massimo).
Per capirci, consideriamo la tabella nella figura d'apertura, che prende in esame un sistema con 10 bit di esponente (compreso il segno dell'esponente stesso); tale lunghezza è quella ideale per un formato "optimal floating" da 52 bit che, normalmente, codificherebbe numeri con 12 cifre decimali significative ed esponente nel range ±154, valori già di per se' eccellenti perchè capaci di soddisfare praticamente ogni necessità concreta (da cui l'aggettivo "ottimale").
Come si vede, esistono tre fasce. Quella centrale (sfondo verde) corrisponde dalla classica codifica FP con una lunghezza fissa dell'esponente e della mantissa con segno (10 e 42 bit rispettivamente), mentre le due fasce in azzurro e arancione mostrano che i 13 valori più bassi o più alti del campo "esponente" vengono "reinterpretati" come una indicazione sull'effettiva lunghezza dell'esponente, il quale è in realtà annidato dentro la mantissa. Tale EL, come si vede, cresce progressivamente ed il valore corrispondente dell'esponente è "additivo", nel senso che ad ogni incremento del numero di bit il valore corrispondente ha un bias diverso che corrisponde al valore massimo della codifica precedente. Questo naturalmente lo si fa per evitare ridondanze e rendere il sistema più efficiente; i valori di esponente che è possibile raggiungere sono davvero notevoli, pari a circa ±1,26 milioni espressi in decimale.
Da notare, in fondo alla tabella, la riga (in rosa) relativa al caso in cui l'esponente è formato da una sequenza di "1" e quindi serve a codificare altre informazioni, come avviene già nei formati FPF tradizionali; qui oltre ai valori ±0, ±∞ e le segnalazioni "Not a Number", ho aggiunto anche l'opzione dei numeri razionali già illustrata in passato. Qualche attento osservatore, a questo punto, potrebbe obiettare che manca, ad inizio tabella, la riga dedicata ai numeri de-normalizzati; ricordiamo che, nei formati FPF classici, questi sono numeri a virgola fissa e precisione decrescente, codificati da un esponente nullo e pensati per migliorare la precisione di calcolo quando ci sono operazioni con residui molto piccoli altrimenti approssimati a zero. In realtà non è una dimenticanza ma una conseguenza diretta del fatto che adesso, grazie al sistema di "variable exponent" codificato, riusciamo a rappresentare numeri molto più piccoli di quelli denormalizzati e con una precisione mediamente migliore! Questa omissione, tra l'altro, consente di avere un numero dispari di codifiche numeriche e quindi realizzare un sistema perfettamente simmetrico rispetto al valore centrale (unità); in questo modo, esponente massimo e minimo sono identici, a parte il segno; invece, nei sistemi FPF classici c'è una fastidiosa asimmetria a favore degli esponenti negativi.
Lo scotto da pagare, naturalmente, è la precisione che, dai 12,64 decimali significativi di base, arriva praticamente a dimezzarsi quando l'esponente è massimo in valore assoluto; questo non è un caso ma è esattamente il criterio con cui ho deciso di realizzare lo schema di codifica per numeri a 52 bit. L'altro trascurabile sacrificio sarebbe quello di non poter sfruttare, con la precisione massima, i valori con esponente estremo (da 151 a 154 in valore assoluto) ma si tratta davvero di un sacrificio marginale con esponenti che già sono esagerati per un utilizzo "normale". Naturalmente, il sistema può essere rimodulato per recuperare alcuni di questi valori o, al contrario, per estendere le due regioni di "recodifica" in modo da raggiungere esponenti ancora più grandi; la scelta qui presentata era dettata dalla decisione di mantenere la precisione delle mantisse comunque non inferiore alla metà di quella nominale.
Detto questo, è ovvio che lo stesso metodo può essere applicato proficuamente anche ad altri standard floating, con lunghezze differenti. In effetti, le ultime due colonne nella tabella qui sopra illustrano cosa succede alla precisione di sistemi FPF a 48 e 64 bit se implementiamo "tout-court" la soluzione adottata per i 52 bit, cioè un esponente da 10 bit con ri-codifica agli estremi. Naturalmente, in questi casi, il criterio di dimezzamento della precisione numerica agli estremi non è più valido e la perdita di precisione appare più drastica su 48 bit e decisamente contenuta su 64 bit; vediamo cosa succede volendo ottimizzare il metodo a questi altri due formati.
Il sistema a 48 bit, in competizione con quello a 52, presenta delle debolezze perchè affetto da una sindrome da "coperta corta": adottando infatti 9 bit di esponente e 39 di (mantissa+segno), la sua capacità di soddisfare i requisiti di precisione e di ampiezza necessari alla stragrande maggioranza delle applicazioni risulta marginale. In effetti, le 11 cifre significative sulla mantissa e l'esponente compreso tra -77 e +77 potrebbero risultare insufficienti in qualche caso pratico, in cui si effettuano calcoli al limite di precisione oggi ottenibile oppure su quantità davvero "astronomiche". L'uso di un esponente variabile potrebbe effettivamente risolvere queste criticità, a patto di non dover soddisfare contemporaneamente entrambe le necessità. Tuttavia, per farlo si rende necessario un uso estremo della tecnica, partendo da una mantissa con 12 cifre significative (41 bit segno compreso).
Di seguito, sono presentate due opzioni possibili; la prima, sulla falsariga di quanto già presentato in precedenza, fa uso di EL sempre più lunghi e raggiunge di conseguenza valori di esponenti molto elevati in valore assoluto, anche se non tanto quanto nell'esempio precedente. Questo perchè il numero di combinazioni a disposizione è oggettivamente inferiore e si deve partire con una EL inizialmente contenuta, quindi la ricodifica riguarda soltanto gli 11 valori più alti o bassi dell'esponente.
Tab.2) Codifica 41+7 bit con EL crescente agli estremi (primi ed ultimi 11 valori dell'esponente)
La seconda opzione illustrata di seguito privilegia invece la precisione anche quando l'esponente è codificato, anche se le 12 cifre significative adesso sono raggiunte con un margine minimo; la EL non cresce e l'esponente massimo è contenuto, comunque nettamente maggiore rispetto al classico FPF a 39+9 bit e con una precisione mai inferiore a 10 cifre significative; naturalmente si possono formulare innumerevoli varianti e questi sono giusto degli esempi...
Tab.3) Codifica 40+8 bit con EL fisso (primi ed ultimi 11 valori dell'esponente)
Qualunque sia la variante scelta, questo metodo è decisamente efficace per ovviare alle limitazioni del formato FPF a 48 bit e lo rende davvero competitivo non solo rispetto ai 52 bit ma anche in confronto al formato "doppia precisione" classico, della cui versione modificata stiamo andando a parlare.
Il formato classico a 64 bit non ha i problemi di quello a 48 ma può comunque beneficiare dell'esponente codificato per diventare ancora più preciso e versatile. In effetti, la soluzione illustrata nella figura d'apertura è già molto appetibile, in quanto da un lato la riduzione di 1 bit nella lunghezza dell'esponente in regime normale consente l'effettivo raggiungimento delle 16 cifre significative, anche se con un margine contenuto; quella di 16 cifre è una precisione altrimenti sfiorata ma non raggiunta dal formato tradizionale. D'altro canto, l'esponente massimo e minimo non si fermano poco oltre 300 (in valore assoluto) ma vanno ben oltre il milione, leggermente di più di quanto riesce al sistema a precisione ottupla da me proposto in passato (235+21 bit). E si potrebbe facilmente fare ancora di meglio, anticipando solo di poche posizioni l'inizio della codifica dell'esponente e sacrificandone la precisione (che si manterrebbe comunque sempre elevata).
Qui riportiamo invece la soluzione opposta, più conservativa in termini di precisione e analoga a quella formulata in Tab.3. Il vantaggio è duplice ed evidente: mentre la precisione raggiunge i 16 bit reali (sebbene con un margine contenuto), l'esponente massimo subisce un raddoppio rispetto al formato classico, con una contenuta riduzione di precisione (comunque ben 14 cifre significative e solo sui 24 esponenti estremi) è anch'essa una soluzione sicuramente interessante perchè rispetta abbastanza i requisiti di precisione per cui è nato questo formato, però potenziandolo su entrambi i fronti!
Tab.4) Codifica 54+10 bit con EL fisso (primi ed ultimi 12 valori dell'esponente)
Nota: in data 10/9/20, le tabelle 3,4 sono state modificate perchè contenti alcuni errori; anche gli standard corrispondenti sono stati leggermente modificati per renderli più aderenti alla filosofia per cui sono stati ideati. Analoghe correzioni e miglioramenti sono stati reiterati il 10/4/23 solo nella porzione finale riguardante il formato 64 bit.