Newsgroup: it.comp.lang.c++
Titolo: float, double e qualcos'altro

Riprendendo il tread di Tempesta e le varie risposte, mi è venuta in mente
una cosa: Tra qualche giorno dovrò affrontare una lezione su come
rappresentare un numero grande su due o più porzioni di byte (più
precisamente stiamo affrontando gli overflow che si presentano quando si
sommano, sottraggono o moltiplicano numeri abbastanza grandi da rendere i
risultati più grandi del previsto); il docente ha anticipato che esiste il
modo  di ovviare al problema (e meno male, altrimenti lasciavo la facoltà di
Informatica e andavo a Psicologia).
Qualcuno vorrebbe gentilmente scrivere un algoritmo (non necessariamente
perfetto e operativo) per mostrarmi come si possa creare un tipo di dato che
andrebbe oltre i double?
Grazie
--
San Vegeta from Hell
http://www.geocities.com/Area51/Dungeon/8436
http://come.to/Fantasy.it

andrebbe oltre i double?
class Intero {
    typedef unsigned char cifra;
    bool negativo;
    typedef std::vector<cifra> cont;
    cont cifre;    // little-endian x comodita`
    cifra cif(unsigned int N) { return N&0xFF; }
    void shifta(unsigned int& N) { N >>= 8; }
public:
    Intero(long L=0): negativo(L<0)
    {
        L=abs(L);
        while(L) {
            cifre.push_back(cif(L));
            shifta(L);
        }
    }
    // stampa esadecimale big-endian:
    void emitHex(std::ostream& o) const {
        using std::ios_base;
        ios_base::fmtflags f = o.setf(ios_base:: hex, ios_base:: basefield);
        cont::const_reverse_iterator cri;
        for(cri=cifre.rbegin(); cri!=cifre.rend(); ++cri)
            o<<*cri;
        o.setf(f, ios_base::basefield);
    }
    // meno unario (cambio di segno)
    Intero operator-() const {
        Intero result(*this);
        result.negativo = !negativo;
        return result;
    }
    // NB: naturalmente non ha senso fare questo
    // inline, lo scrivo qui solo x semplicita`:
    Intero& operator+=(const Intero& a) {
        if(a.negativo!=negativo)
            return operator-=(-a);
        cont::cost_iterator ci = a.cifre.begin();
        cont::iterator i = cifre.begin();
        unsigned int riporto = 0;
        while(i!=cifre.end() &&
            (riporto || (ci!=a.cifre.end()))) {
                if(ci!=a.cifre.end()) 
                    riporto += *ci++;
                riporto += *i;
                *i++ = cif(riporto);
                shifta(riporto);
        }
        while(riporto || (ci!=a.cifre.end())) {
                if(ci!=a.cifre.end()) 
                    riporto += *ci++;
                cifre.push_back(cif(riporto));
                shifta(riporto);
        }
        return *this;
    }
    // ecc ecc x gli altri operatori aritmetici + interessanti!
};
// operatori ausiliari x comodita`:
inline ostream& 
operator<<(ostream &o, const Intero& i)
    { i.emitHex(o); return o; }
inline Intero
operator+(const Intero&a, const Intero&b) {
    Intero result(a);
    result += b;
    return result;
}
// eccetera
Le varie operazioni intere possono essere definite con algoritmi
che bene o male abbiamo imparato alle elementari (con la piccola
differenza che qui si lavora in base 256 invece che in base 10, ma
nulla impedisce, volendo, di lavorare invece in base 10, o 100,
per avere comodamente I/O decimale a prezzo di operazioni un
poco piu` lente; basta ridefinire opportunamente cif e shifta con
uso degli operatori % e / fra interi).
Se interessa gestire numeri non interi, si possono scegliere per
essi varie rappresentazioni (basate magari sulla classe Intero):
ad esempio, frazioni (presumibilmente da mantenersi ridotte ai
minimi termini, con una coppia di Intero come numeratore e
denominatore), numeri a "virgola fissa" (parte intera e parte
frazionaria, ma quest'ultima dovra` allora avere precisione
prefissata e non illimitata), significando+esponente (il primo
un Intero, per il secondo, soprattuto in base 256, potrebbe
anche bastare un unsigned long, comunque si puo` sempre
usare un Intero anche li`...).  L'onere computazionale delle varie
operazioni elementari, e la difficolta` di scriverle, varia, come
e` ovvio, a seconda della rappresentazione scelta.
Si trovano in rete vari pacchetti preconfezionati per l'aritmetica
con numero indefinito di cifre, sia intera sia non-intera, ma questo
e` certo un campo dove chi abbia un qualche interesse per i
fondamenti dell'aritmetica computazionale puo` esercitarsi con
frutto.  Molto consigliato, naturalmente, il primo volume di Knuth,
"The Art of Numeric Programming", vera Bibbia (pero` molto
difficile e avanzata!!!) di questo tipo di problematiche (e varie
altre, naturalmente:-).
Alex

 andrebbe oltre i double?
Brevemente, potresti utilizzare non una ma più variabili (un vettore?)
per contenere il tuo numero e gestirne la suddivisione nelle varie parti
sia nelle operazioni che nella rappresentazione esterna (come stringhe?)
e relative conversioni da rappresentazione interna a esterna e
viceversa. Il tutto, ovviamente, con una bella classe, simile alla quale
però già ne esistono disponibili.
EMG

SNIP
Wow, mi bastava una semplice spiegazione per chiarirmi il concetto.
Grazie mille, ora ho un bell'algoritmo da studiare e imparare.
P.S. Stavolta ho snippato tutto, contento? :-P