Header para matrices y fracciones

Eduardo de Lorenzo Poza

/* Estos son dos headers, mat.h y frac.h, que sirven para el manejo de matrices racionales y fracciones respectivamente. Se incluyen tanto los archivos de cabecera como el código fuente.
He optado por las matrices racionales puesto que el tipo float tiene asociada una imprecisión, y al aplicar Gauss en vez de ceros quedaban números del orden 10^-7. Además se pueden importar y exportar las matrices a ficheros externos. Hay que tener cuidado al introducir los datos de no separar los quebrados (3/2 bien, 3 / 2 mal). Sin más dilación, ahí va el código:
AVISO: No apto para cardíacos. */

frac.h

#ifndef FRAC_H
#define FRAC_H

#include <iostream>
using namespace std;

class frac
{
    public:

        frac();
        frac(int n, int d = 1);

        friend ostream& operator<< (ostream &os, frac &f);
        friend istream& operator>> (istream &is, frac &f);

        friend frac operator- (const frac &f);
        frac& operator+= (const frac &f);
        frac& operator-= (const frac &f);
        frac& operator*= (const frac &f);
        frac& operator/= (const frac &f);
        friend frac operator+ (const frac &f1, const frac &f2);
        friend frac operator- (const frac &f1, const frac &f2);
        friend frac operator* (const frac &f1, const frac &f2);
        friend frac operator/ (const frac &f1, const frac &f2);

        friend bool operator== (const frac &f1, const frac &f2);
        friend bool operator!= (const frac &f1, const frac &f2);
        friend bool operator< (const frac &f1, const frac &f2);
        friend bool operator> (const frac &f1, const frac &f2);
        friend bool operator<= (const frac &f1, const frac &f2);
        friend bool operator>= (const frac &f1, const frac &f2);

    private:

        int num, den;
        frac& simplificar();
};

int mcd(int a, int b);
int mcm(int a, int b);

#endif // FRAC_H

frac.cpp

#include "frac.h"

/** Constructores */

frac::frac() {}

frac::frac(int n, int d) : num(n), den(d) {
    simplificar();
}


/** Operadores */

ostream& operator<< (ostream &os, frac &f) {
    if (f.den == 1) os << f.num;
    else os << f.num << "/" << f.den;
    return os;
}

istream& operator>> (istream &is, frac &f){
    is >> f.num;
    int sig = is.peek();
    if (sig == '/') {
        is.get();
        is >> f.den;
    } else f.den = 1;
    f.simplificar();
    return is;
}



frac operator- (const frac &f) {
    frac res;
    res.num = -f.num;
    res.den = f.den;
    return res;
}

frac& frac::operator+= (const frac &f) {
    int n_den = mcm(den, f.den);
    num = num*(n_den/den)+f.num*(n_den/f.den);
    den = n_den;
    simplificar();
    return *this;
}

frac& frac::operator-= (const frac &f) {
    int n_den = mcm(den, f.den);
    num = num*(n_den/den)-f.num*(n_den/f.den);
    den = n_den;
    simplificar();
    return *this;
}

frac& frac::operator*= (const frac &f) {
    num = num*f.num;
    den = den*f.den;
    simplificar();
    return *this;
}

frac& frac::operator/= (const frac &f) {
    num = num*f.den;
    den = den*f.num;
    simplificar();
    return *this;
}

frac operator+ (const frac &f1, const frac &f2) {
    frac res;
    res.den = mcm(f1.den, f2.den);
    res.num = f1.num*(res.den/f1.den)+f2.num*(res.den/f2.den);
    res.simplificar();
    return res;
}

frac operator- (const frac &f1, const frac &f2) {
    frac res;
    res.den = mcm(f1.den, f2.den);
    res.num = f1.num*(res.den/f1.den)-f2.num*(res.den/f2.den);
    res.simplificar();
    return res;
}

frac operator* (const frac &f1, const frac &f2) {
    frac res;
    res.den = f1.den*f2.den;
    res.num = f1.num*f2.num;
    res.simplificar();
    return res;
}

frac operator/ (const frac &f1, const frac &f2) {
    frac res;
    res.den = f1.den*f2.num;
    res.num = f1.num*f2.den;
    res.simplificar();
    return res;
}



bool operator== (const frac &f1, const frac &f2) {
    if (f1.num==f2.num && f1.den==f2.den) return true;
    else return false;
}

bool operator!= (const frac &f1, const frac &f2) {
    if (f1.num!=f2.num || f1.den!=f2.den) return true;
    else return false;
}

bool operator< (const frac &f1, const frac &f2) {
    if (f1.num/f1.den < f2.num/f2.den) return true;
    else return false;
}

bool operator> (const frac &f1, const frac &f2) {
    if (f1.num/f1.den > f2.num/f2.den) return true;
    else return false;
}

bool operator<= (const frac &f1, const frac &f2) {
    if (!(f1>f2)) return true;
    else return false;
}

bool operator>= (const frac &f1, const frac &f2) {
    if (!(f1<f2)) return true;
    else return false;
}


/** Otras funciones */

frac& frac::simplificar() {
    if (num == 0) {den = 1; return *this;}
    int gcd = mcd(num, den);
    if (gcd == 1) return *this;
    else {
        num = num/gcd;
        den = den/gcd;
    }
    return *this;
}

int mcd(int a, int b) {
    if (a < 0) a = -a;
    if (b < 0) b = -b;
    if (a < b) {
        int aux;
        aux = a;
        a = b;
        b = aux;
    }
    if (a%b == 0) return b;
    else return mcd(b, a%b);
}

int mcm(int a, int b) {
    if (a < 0) a = -a;
    if (b < 0) b = -b;
    int res = a/(mcd(a, b))*b;
    return res;
}

mat.h

#ifndef MAT_H
#define MAT_H

#include <iostream>
#include "frac.h"
using namespace std;

class mat
{
    public:

        mat();
        mat(int f, int c);
        mat(const mat &m);

        bool esCuadrada() const;
        friend frac det(const mat M);
        mat traspuesta();
        mat inversa();

        friend istream& operator>> (istream &is, mat &M);
        friend ostream& operator<< (ostream &os, mat &M);

        mat& operator= (const mat &M);

        friend mat operator+ (const mat &M1, const mat &M2);
        friend mat operator- (const mat &M1, const mat &M2);
        friend mat operator* (const mat &M1, const mat &M2);
        friend mat operator* (const mat &M, const frac &f);
        friend mat operator* (const frac &f, const mat &M);

        mat& operator+= (const mat &M);
        mat& operator-= (const mat &M);
        mat& operator*= (const mat &M);


    private:

        frac pos[7][7];
        int filas, columnas;
        bool cuadrada;
};



#endif // MAT_H

mat.cpp

#include "mat.h"

/** Constructores */

mat::mat() {}

mat::mat(int f, int c) : filas(f), columnas(c) {
    for (int i=0; i<f; i++) {
        for (int j=0; j<c; j++) {
            if (i==j) pos[i][j] = 1;
            else pos[i][j] = 0;
        }
    }
}

mat::mat(const mat &M) {
    filas = M.filas;
    columnas = M.columnas;
    for (int i=0; i<filas; i++) {
        for (int j=0; j<columnas; j++) {
            pos[i][j] = M.pos[i][j];
        }
    }
}

/** Operadores */


istream& operator>> (istream &is, mat &M) {
    for (int i=0; i<M.filas; i++) {
        for (int j=0; j<M.columnas; j++) {
            is >> M.pos[i][j];
        }
    }
    return is;
}

ostream& operator<< (ostream &os, mat &M) {
    os << endl << "\t";
    for (int i=0; i<M.filas; i++) {
        for (int j=0; j<M.columnas; j++) {
            os << M.pos[i][j] << "\t";
            if ((j+1) % M.columnas == 0 && (i+1) != M.filas) os << endl << endl << "\t";
        }
    }
    os << endl;
    return os;
}



mat& mat::operator= (const mat &M) {
    filas = M.filas;
    columnas = M.columnas;
    for (int i=0; i<filas; i++) {
        for (int j=0; j<columnas; j++) {
            pos[i][j] = M.pos[i][j];
        }
    }
    return *this;
}



mat operator+ (const mat &M1, const mat &M2) {
    mat aux;
    if (M1.filas==M2.filas && M1.columnas==M2.columnas) {
        aux.filas = M1.filas;
        aux.columnas = M1.columnas;
        for (int i=0; i<aux.filas; i++) {
            for (int j=0; j<aux.columnas; j++) {
                aux.pos[i][j] = M1.pos[i][j] + M2.pos[i][j];
            }
        }
    }
    return aux;
}

mat operator- (const mat &M1, const mat &M2) {
    mat aux;
    if (M1.filas==M2.filas && M1.columnas==M2.columnas) {
        aux.filas = M1.filas;
        aux.columnas = M1.columnas;
        for (int i=0; i<aux.filas; i++) {
            for (int j=0; j<aux.columnas; j++) {
                aux.pos[i][j] = M1.pos[i][j] - M2.pos[i][j];
            }
        }
    }
    return aux;
}

mat operator* (const mat &M1, const mat &M2) {
    mat aux;
    if (M1.columnas==M2.filas) {
        aux.filas = M1.filas;
        aux.columnas = M2.columnas;
        frac suma = 0;
        for (int i=0; i<aux.filas; i++) {
            for (int j=0; j<aux.columnas; j++) {
                for (int k=0; k<M1.columnas; k++) {
                    suma += M1.pos[i][k]*M2.pos[k][j];
                }
                aux.pos[i][j] = suma;
                suma = 0.0;
            }
        }
    }
    return aux;
}

mat operator* (const mat &M, const frac &f) {
    mat aux(M);
    for (int i=0; i<aux.filas; i++) {
        for (int j=0; j<aux.columnas; j++) {
            aux.pos[i][j] *= f;
        }
    }
    return aux;
}

mat operator* (const frac &f, const mat &M) {
    mat aux(M);
    for (int i=0; i<aux.filas; i++) {
        for (int j=0; j<aux.columnas; j++) {
            aux.pos[i][j] *= f;
        }
    }
    return aux;
}



mat& mat::operator+= (const mat &M) {
    if (filas==M.filas && columnas==M.columnas) {
        for (int i=0; i<filas; i++) {
            for (int j=0; j<columnas; j++) {
                pos[i][j] += M.pos[i][j];
            }
        }
    }
    return *this;
}

mat& mat::operator-= (const mat &M) {
    if (filas==M.filas && columnas==M.columnas) {
        for (int i=0; i<filas; i++) {
            for (int j=0; j<columnas; j++) {
                pos[i][j] -= M.pos[i][j];
            }
        }
    }
    return *this;
}



/** Otras funciones */

bool mat::esCuadrada() const {
    if (filas == columnas) return true;
    else return false;
}

mat mat::traspuesta() {
    mat aux(columnas, filas);
        for (int i=0; i<filas; i++) {
            for (int j=0; j<columnas; j++) {
                aux.pos[j][i] = pos[i][j];
            }
        }
        return aux;
}

frac det(const mat M) {
    frac determinante = 1;
    if (M.esCuadrada()) {
        mat aux = M;

        //Algoritmo de eliminación de Gauss
        for (int i=0; i<aux.filas-1; i++) {
            for (int j=i+1; j<aux.filas; j++) {
                frac factor;
                if (aux.pos[i][i]!=0) {
                    factor = aux.pos[j][i]/aux.pos[i][i];
                } else continue;
                for (int k=i; k<aux.columnas; k++) {
                    aux.pos[j][k] -= factor*aux.pos[i][k];
                }
            }
        }
        for (int i=0; i<aux.filas; i++) determinante *= aux.pos[i][i];
    }
    return determinante;
}

mat mat::inversa() {
    if (esCuadrada() && det(*this)!=0) {
        mat aux(*this);
        mat I(filas, columnas);

        //Algoritmo de eliminación de Gauss (quedan todos 1 ó 0 en la diagonal)
        for (int x=0; x<aux.filas; x++) {
            for (int i=x; i<aux.filas; i++) {
                if (aux.pos[i][x]!=0) {
                    frac pivote = aux.pos[i][x];
                    for (int k=0; k<aux.columnas; k++) {
                        aux.pos[i][k] /= pivote;
                        I.pos[i][k] /= pivote;
                    }
                    for (int j=i+1; j<aux.filas; j++) {
                        frac factor = aux.pos[j][i];
                        for (int k=0; k<aux.columnas; k++) {
                            aux.pos[j][k] -= aux.pos[i][k]*factor;
                            I.pos[j][k] -= I.pos[i][k]*factor;
                        }
                    }
                    break;
                }
            }
        }

        //Volvemos a aplicar el algoritmo pero ahora comenzando desde la última fila
        for (int x=aux.filas-1; x>=0; x--) {
            for (int i=x; i>=0; i--) {
                if (aux.pos[i][x]!=0) {
                    frac pivote = aux.pos[i][x];
                    for (int k=aux.columnas; k>=0; k--) {
                        aux.pos[i][k] /= pivote;
                        I.pos[i][k] /= pivote;
                    }
                    for (int j=i-1; j>=0; j--) {
                        frac factor = aux.pos[j][i];
                        for (int k=0; k<aux.columnas; k++) {
                            aux.pos[j][k] -= aux.pos[i][k]*factor;
                            I.pos[j][k] -= I.pos[i][k]*factor;
                        }
                    }
                    break;
                }
            }
        }

        //Finalmente el resultado queda en I
        return I;
    }
    return *this;
}
Esta entrada fue publicada en Informática e Internet. Guarda el enlace permanente.

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s