Newsgroup: it.comp.lang.c++
Titolo: Contenitore matrix 2 (e vector)

Allora... stavo riprendendo la mia "template<class T> class matrix"
( vedi post l5JU7.2638$
db7.6...@twister2.libero.it
 )
il fatto e' che avevo fatto, fin'ora, test usando come T i float.
Beh... sembrava funzionare...
Adesso ho provato a usare elementi interi e mi da risultati
sballatissimi.
Perché?
Ah... sotto Natale avevo anche chiesto che senso aveva
questa cosa:
#ifndef vector
#define vector vector
#endif
nel file che implementa il <vector> per il Borland C++ Compiler 5.5.1
Qualcuno ne sa qualcosa?
--
Gerolamo

 Qualcuno ne sa qualcosa?
Non ne ho idea. Forse per compatibilità con un'altra libreria borland
che definiva vector in qualche modo (come macro).
--
Andrea Ferro
---------
Brainbench C++ Master. Scored higher than 97% of previous takers
Scores: Overall 4.46, Conceptual 5.0, Problem-Solving 5.0
More info 
http://www.brainbench.com/transcript.jsp?pid=2522556

 Non pensi di aver fornito un po troppo poche informazioni?
ehm... no :-)
il fatto e' che avevo gia' postato tutto il codice e mi pareva inutile
ripostarlo...
...effettivamente, però, e' piu' comodo se lo faccio.
Ecco:
#include <valarray>
#include <iostream>
template<class T> class matrix
{
    typedef std::valarray<T> righe; // righe...
    std::valarray<righe> colonna; // colonna (di righe)
    // ridimensiona Colonne e Righe
    void setSize(int numero_righe, int numero_colonne)
    {
        colonna.resize(0); // getta tutto
        colonna.resize(numero_righe); // riparte
        for(int i=0; i<numero_righe; ++i)
        {
            colonna[i].resize(0); // questa riga e' inutile, giusto?
            colonna[i].resize(numero_colonne);
        }
    }
    public:
    // ----------- COSTRUTTORI ----------- //
    matrix() {}
    matrix(int righe, int colonne) { setSize(righe, colonne); }
    // ----------- CAPACITA' ----------- //
    // questo è legale o rischio un overflow di size_t ??
    size_t size() const { return (colonna.size() * colonna[0].size()); }
    size_t max_size()
    {
        return (colonna.max_size() * colonna[0].max_size());
    }
    void resize(size_t righe, size_t colonne)
    {
        colonna.resize(righe);
        for(unsigned int i=0; i < colonna.size();  ++i)
        {
            colonna[i].resize(colonne);
        }
    }
    void resize(size_t righe, size_t colonne, T valore)
    {
        colonna.resize(righe, valore);
        for(unsigned int i=0; i < body.size();  ++i)
        {
            colonna[i].resize(colonne, valore);
        }
    }
    bool empty(){ return (colonna.empty() || colonna[0].empty()); }
    // ----------- OPERATORI UNARI ----------- //
    // ----------- Operatore [] ----------- //
    std::valarray<T>& operator[](int i) { return colonna[i]; }
    const std::valarray<T>& operator[](int i) const { return colonna[i];}
    // ----------- Operatore += ----------- //
    matrix<T>& operator+= (const matrix& matrice)
    {
        if( (colonna.size() == matrice.colonna.size() ) &&
            (colonna[0].size() == matrice.colonna[0].size()) )
        {
            for (unsigned int i=0; i < colonna.size(); ++i)
            {
                colonna[i] += matrice.colonna[i]; // somma membro a membro
            }
        }
        return *this;
    }
    // ----------- Operatore *= ----------- //
    matrix<T>& operator*= (const matrix& matrice)
    {
        // se sono moltiplicabili
        if( colonna[0].size() == matrice.colonna.size() )
        {
            // per tutta la lunghezza delle colonne di this
            // ( == per tutte le righe)
            for (unsigned int i=0; i< colonna.size(); ++i)
            {
                // crea una riga temporanea per i risultati
                righe riga_temp( matrice.colonna[i].size() );
                // per tutta la lunghezza delle righe di matrice
                // ( == per ogni elemento della colonna)
                for (unsigned int j=0; j < matrice.colonna[i].size(); ++j)
                {
                    // fa il prodotto vettoriale riga*colonna
                    for (unsigned int k=0; k< colonna[i].size(); ++k)
                    {
                        riga_temp[j] +=
                        colonna[i][k] * matrice.colonna[k][j];
                    }
                }
                // ridimensiona la riga calcolata
                colonna[i].resize( matrice.colonna[i].size() );
                // e vi copia il risultato
                colonna[i] = riga_temp;
            }
            return *this; // restituisce la matrice cambiata
        }
        // se invece le colonne della prima matrice non sono tante
        //  quante le colonne della seconda matrice
        else
        {
            // stampa un messaggio di errore (ecco l' <iostream> )
            std::cout << "Errore dimensioni!" << std::endl;
            std::cout << "Lunghezza Colonne    prima     matrice: ";
            std::cout << colonna.size() << std::endl;
            std::cout << "Lunghezza Righe prima     matrice: ";
            std::cout << colonna[0].size() << std::endl;
            std::cout << "Lunghezza Colonne seconda    matrice: ";
            std::cout  << matrice.colonna.size() << std::endl;
            std::cout << "Lunghezza Righe seconda matrice: ";
            std::cout  << matrice.colonna[0].size() << std::endl;
            return *this;   // e ritorna la matrice senza averla cambiata
        }
    }
};
L'altro dubbio che avevo era su come gestire il caso di matrici non
moltiplicabili/sommabili a causa di dimensioni errate.
Direi che il messaggio di errore qui sopra non e' molto soddisfacente...
--
Gerolamo

 Ecco:

--


 di errore. Lui si deve limitare a segnalarlo. Quindi usa le eccezioni.
ok.
allora rimando a dopo questo problema perche' non so ancora
usare degnamente le eccezioni.
Per il resto dei commenti ti dico solo: Sei un mito!
...ma mi serve tempo per ragionarci sopra.
Poi provo ad applicare i consigli e mi faccio risentire.
Intanto grazie!
--
Gerolamo

     matrix<float> n22(3,4);
seeee... buonanotte... (in effetti, data l'ora...)
intendevo:
matrix<int> m22(2,3);
matrix<int> n22(3,4);
--
Gerolamo

 di errore. Lui si deve limitare a segnalarlo. Quindi usa le eccezioni.
ok
Adesso finisco di modificare il codice, poi lo posto.
Grazie
--
Gerolamo

> Adesso finisco di modificare il codice, poi lo posto.
eccolo:
#ifndef IT_COMP_LANG_C++__GEO__MATRIX2D_TEMPLATE
#define IT_COMP_LANG_C++__GEO__MATRIX2D_TEMPLATE
#include <valarray>
template<class T> class matrix
{
    typedef std::valarray<T> row_type; // vettore riga
    std::valarray<row_type> first_column; // indica, sostanzialmente,
                         //  la prima colonna e, per estensione,
                         // le righe che partono da essa
    public:
    // ----------- COSTRUTTORI ----------- //
    matrix() {}
    matrix(int rows, int columns) { resize(rows, columns); }
    // ----------- CAPACITA' ----------- //
    size_t columns() const
    {
        return first_column[0].size();
    }
    size_t rows() const
    {
        return columns()!=0 ? first_column.size() : 0;
    }
    void sizes( size_t& r, size_t& c ) const
    {
        c=columns();
        r=rows();
        // nota: la chiamata a rows implica una seconda chiamata
        // a columns e quindi il codice non è ottimale in prestazioni.
        // però la differenza è minima e matrix::sizes non viene certo
        // chiamata ripetutamente. Inoltre un buon compilatore espande
        // il tutto inline e riesce ad ottimizzare il codice rendendolo
        // di fatto ottimale. Quindi la leggibilità deve avere la priorità.
    }
    size_t size() const
    {
        // stesso discorso di prima sulla leggibilità e sull'ottimizzazione
        // l'overflow non avviene per come implementeremo la resize.
        return rows()*columns();
    }
    // dentro e' commentata perche' il compilatore sostiene che
    // valarray<T>.max_size() non esiste... alternative?
    size_t max_size()
    {
        // return (first_column.max_size() * first_column[0].max_size());
    }
    void resize(size_t r, size_t c, const T& v = T() )
    {
        size_t sz = r*c;
        if ( sz==0 ) // se una delle due dimensioni e' a zero
        {
            r=1;
            c=0;
        }
        else if ( sz > max_size() ) // se invece sforo i limiti gestibili
        {
            // gestire tramite eccezioni
        }
        // se invece le dimensioni sono "gestibili"
        first_column.resize(r); // ridimensiono la prima colonna
        for( size_t i=0; i < r; ++i ) // e poi tutte le righe
            first_column[i].resize(c);
    }
    bool empty() { return size()==0; }
    // ----------- OPERATORI UNARI ----------- //
    // ----------- Operatore [] ----------- //
    std::valarray<T>& operator[](int i) { return first_column[i]; }
    const std::valarray<T>& operator[](int i) const { return
first_column[i];}
    // ----------- Operatore += ----------- //
    matrix<T>& operator+= (const matrix& m)
    {
        size_t r = rows(); // questo mi evita una chiamata a
                    // columns() ogni volta che chiamo rows()
        if( (r != m.rows()) || (columns() != m.columns()) )
        {
            // gestire tramite eccezioni
        }
        else // lo so che e' inutile, ma mi piace di piu' cosi'
        {
            for ( size_t i=0; i < r; ++i )
                first_column[i] += m.first_column[i];
        }
        return *this;
    }
    // ----------- Operatore *= ----------- //
    matrix<T>& operator*= (const matrix& m)
    {
        size_t this_rows = rows(); // questo mi evita una chiamata a
        size_t m_rows = m.rows(); // columns() ogni volta che chiamo rows()
        if( columns() != m_rows ) // se non sono moltiplicabili
        {
            // gestire tramite eccezioni
        }
        else // se le dimensioni sono ok
        {
            // per tutta la lunghezza delle colonne di this
            // ( == per tutte le righe)
            for (unsigned int i=0; i< this_rows; ++i)
            {
                // crea una riga temporanea per i risultati
                row_type row_temp( m.columns() );
                // per tutta la lunghezza delle righe di matrice
                // ( == per ogni elemento della colonna)
                for (unsigned int j=0; j < m.columns(); ++j)
                {
                    // fa il prodotto vettoriale riga*colonna
                    for (unsigned int k=0; k< m_rows; ++k)
                    {
                        row_temp[j] += first_column[i][k] *
m.first_column[k][j];
                    }
                }
                // ridimensiona la riga calcolata
                first_column[i].resize( m.columns() );
                // e vi copia il risultato
                first_column[i] = row_temp;
            }
         }
         return *this; // restituisce la matrice cambiata
    }
};
#endif
va bene? (vabbe'... diciamo... va meglio?)
I problemi/dubbi:
1-
Mi sono accorto di un "piccolo particolare"
Valarray.max_size(); non esiste nell'implementazione della borland...
...e a dire il vero sullo Stroustrup non l'ho trovato...
mi viene il "vaghissimo sospetto" che per questo contenitore
max_size() non sia definita... perche'?
e a questo punto... che faccio delle max_size() che ho nel mio codice?
2-
Il borland c++ compiler 5.5.1 mi da quest questi warning:
Warning W8027 matrice.cpp 74: Functions containing for are not expanded
inline
Warning W8027 matrice.cpp 98: Functions containing for are not expanded
inline
Warning W8027 matrice.cpp 119: Functions containing for are not expanded
inline
riferiti, ad esempio al ciclo for di resize(...).
E' normale?
E' un problema?
3-
Warning W8057 matrice.cpp 76: Parameter 'v' is never used in function
matrix<float>::resize(unsigned int,unsigned int,const float &)
Allora non sono io che non ho capito! non viene realmente usato!
Mi spieghi come volevi fare il resize(r,c,const T& v = T() ) ?
4-
sempre warning del compilatore:
Warning W8008 C:\Programmi\BCC55\Include\rw/valimp.cc 86: Condition is
always true in function _RW_array<float>::_copy_memory_array(const
_RW_array<float> &)
Warning W8066 C:\Programmi\BCC55\Include\rw/valimp.cc 89: Unreachable code
in function _RW_array<float>::_copy_memory_array(const _RW_array<float> &)
Warning W8066 C:\Programmi\BCC55\Include\rw/valimp.cc 90: Unreachable code
in function _RW_array<float>::_copy_memory_array(const _RW_array<float> &)
Ma e' normale che succedano queste cose? a me non pare di aver
fatto nulla di anormale, tanto da avere dei pezzi di codice irraggiungibile
(nelle librerie!), oppure delle condizioni sempre verificate...
boh... ne sapete qualcosa?
--
Gerolamo (che bello postare quasi tutto un thread da solo :-)

 Grazie
Prego


 boh... ne sapete qualcosa?
Sono warnings e probabilmente sono correlati: la "condition always true"
usata in un if può provocare l'irraggiungibilità del codice presente
nell'else (o qualche cosa di simile).
Non è una cosa molto "elegante" e credo che dipenda dall'implementazione
della STL del borland. Prova a vedere come è fatto il codice del metodo.
Curioso anche il fatto che usino un file con estensione .cc laddove mi
aspetterei un include (stiamo parlando di templates!).


 Prego
ri-grazie!
--
Gerolamo

 codice. E' una limitazione dell'ottimizzatore di borland.
Chiaro.
nel frattempo ho risolto anche il problema che si verificava con gli interi:
nell' operatore *= creavo una riga temporanea cosi':
row_type row_temp(m.columns());
beh... ovviamente (ma non per me :-) andava messa cosi':
row_type row_temp(T(), m.columns());
in modo da inizializzare correttamente gli elementi...
ok.
Adesso sono a posto con i problemi e posso proseguire ad implementare
il resto.
Se interessa vi faccio sapere come prosegue.
Intanto grazie.
--
Gerolamo

 > elementi, sei sempre sicuro che esista anche colonna[0].
Tra l'altro: varrebbe la pena di metter un commento in merito.


 in modo da inizializzare correttamente gli elementi...
Yup. Come ti ho detto non avevo guardato il codice. Però se non erro lo
stesso errore lo avevi fatto anche da un'altra parte e te lo avevo
segnalato.


 Hai varie alternative.
Io direi anche di non usare piu' i vallarray visto che sembra usciranno
dallo standard.

 ha scritto nel messaggio
news:a1kgha$fo3$1...@newsreader.mailgate.org...

D'oh!!!
E perche' mai?
--
Gerolamo

 E perche' mai?
Perche' sembra che non li usi nessuno escluso tu e pochi altri.
--
Ciao
Gaetano
--
#exclude <windows>
printf("\t\t\b\b\b\b\b\b");.
printf("\t\t\b\b\b\b\b\b");

 wrote in message
news:a1kgha$fo3$1...@newsreader.mailgate.org...

A parte che non usciranno certo dallo standard prima che questo venga
cambiato, e ci vuole ancora un bel pezzo, non vedo perchè non usarli
dato che puoi sempre cambiare DOPO. Ovvero quando non sono più standard.
Oppure, se e quando usciranno dallo standard, ti pigli una qualunque
implentazione esistente che ti soddisfi e la rendi parte del tuo codice.
Oppure ancora ... ti rifai tu l'implementazione.
Comunque ho una domanda: dove hai sentito che usciranno dallo standard?
Non mi sembra una cosa sensata e farò tutto il possibile perchè non
avvenga (ovvero se dovesse essere confermata questa notizia scriverò a
tutti i membri del comitato che si occupano della libreria chiedendogli
di opporsi fermamente).


 Perche' sembra che non li usi nessuno escluso tu e pochi altri.
Non mi sembra un valido motivo.
Ci sono molte altre parti della libreria (soprattutto legacy C) che
restano anche se non le usa nessuno.


 Perche' sembra che non li usi nessuno escluso tu e pochi altri.
Anche i <locale> mi sembra che li usino in pochi... tolgono pure
quelli? :-)))
Comunque, boh... a me appena ho scoperto i valarray, mi sono parsi
subito interessanti (magari con qualche modifica...).
Ho fatto dei test e mi pare poter concludere che abbiano pure
delle ottime prestazioni, computazionalmente parlando.
Assolutamente comparabili gli array C (a volte mi davano
addirittura tempi migliori)
Per cui mi pare assurdo che li usino in pochi, ma di sicuro tu ne
sai piu' di me.
Io, nel frattempo, rimango in ascolto...
--
Lo spam è un problema! Informati su: 
http://www.collinelli.net/antispam
Abbonati a un ISP decente che utilizzi tecniche per combattere lo spam
Non usare una mailbox e-nonima. Se hai paura dello spam usa servizi come
Despammed, Sneakemail, 
Vene.dave.it
, ecc...   ----    Ciao, Gerolamo.

 di opporsi fermamente).
Nell'editoriale di C/C++ User Journal mi sembra di aver
capito questo non e' stato molto esplicito.


 addirittura tempi migliori)
Oltre al fatto che sono interessanti, una delle ragioni per averli messi
è aprire la strada a eventuali ottimizzazioni in termini di calcolo
parallelo (soprattutto con tecniche SIMD).
