El artículo original lo podeís encontrar aquí
Computacionalmente hablando cuanto más compleja es la operación más mejora de rendimiento se puede llegar a conseguir.
Pues bien, concretamente para la optimización SSE, para el caso de la distancia entre dos vectores (algo más complejo que una simple suma de vectores) se ha conseguido unos valores de tiempo de :
Version sin optimizar Tiempo gastado: 680milisegundos
Version optimizada con SSE Tiempo gastado: 68milisegundos
Es decir se ha CONSEGUIDO MULTIPLICAR POR 10 EL RENDIMIENTO!!!.
Aqui os dejo el código para que veais como lo he hecho:
float LPVector::distanceOld(LPVector vector)
{
float a = 0.0;
float temp = 0.0;
//Si las dimensiones son diferentes , tenemos un problema grave.
if (n != vector.n)
{
cout << "ERROR DIMENSIONAL ENTRE VECTORES\n";
return (-1.0);
}
for(int i = 0 ; i < n ; ++i)
{
temp = (v[i] - vector.v[i]);
a += ( temp * temp ) ;
}
return sqrt(a);
}
float LPVector::distanceSSE(LPVector vector)
{
//Fast SSE code when float specified
float b[4];
float* const row0 = (float*) &v[0];
float* const row1 = (float*) &(vector.v[0]);
float* const a = (float*) &b[0];
float temp = 0.0;
int i = 0;
//Si las dimensiones son diferentes , tenemos un problema grave.
if (n != vector.n)
{
cout << "ERROR DIMENSIONAL ENTRE VECTORES\n";
return (-1.0);
}
__asm
{
// Carga trozos de los vectores de 4 en 4
// La carga se hace "desordenada para que siempre haya una instrucción como mínimo entre uso y uso de registros."
mov edx, row0
mov esi, row1
mov edi, a
//Al hacer una XOR ponemos el registro a 0 más rapidamente que hacciendo un mov de 0
//El registro xmm7 (el último) lo ponemos de variable acumuladora de resultado
xorps xmm7, xmm7
}
i = n;
while( i >= 12 )
{
__asm
{
//Cargamos la info en los registros SSE
movups xmm0, [edx]
movups xmm1, [esi]
//Aumentamos los contadores en 16 = 4 elementos * 4 bytes por elemento (float)
add edx,16
add esi,16
//Cargamos la info en los registros SSE(tenemos 8 registros donde guardar info)
movups xmm2, [edx]
movups xmm3, [esi]
//Aumentamos los contadores en 16 = 4 elementos * 4 bytes por elemento (float)
add edx,16
add esi,16
//Cargamos la info en los registros SSE(tenemos 8 registros donde guardar info)
movups xmm4, [edx]
movups xmm5, [esi]
//Aumentamos los contadores en 16 = 4 elementos * 4 bytes por elemento (float)
add edx,16
add esi,16
//Hacemos la operación que toca, en nuestro caso, restar , elevar el resultado al cuadrado y acumular el resultado
subps xmm0 , xmm1 //Restamos de 4 en 4
subps xmm2 , xmm3 //Restamos de 4 en 4
subps xmm4 , xmm5 //Restamos de 4 en 4
//Elevamos al cuadrado la diferencia
mulps xmm0,xmm0
mulps xmm2,xmm2
mulps xmm4,xmm4
//Sumamos resultados parciales al total (xmm7)
addps xmm7,xmm0
addps xmm7,xmm2
addps xmm7,xmm4
}
i -= 12;
}
__asm
{
movups [edi], xmm7
}
b[0] += (b[1] + b[2] + b[3]);
//Los flecos los rematamos de la manera tradicional
for(int j = n-i ; j < n ; ++j)
{
temp = (v[i] - vector.v[i]);
b[0] += temp*temp;
}
return sqrt(b[0]);
}
int main (int argc, char* argv[])
{
LPVector v1,v2;
float d1,d2;
clock_t timer;
float delay;
//Creamos los vectores aleatorios
v1.random(DIM,0.0f,100.0f);
v2.random(DIM,0.0f,100.0f);
//Sumamos los vectores
cout << "Version sin optimizar\n";
timer = clock();
for(int i=0 ; i < 100000 ; i++ )
d1 = v1.distanceOld ( v2 );
delay = ( clock() - timer ) ;
cout << "Tiempo gastado: " << delay << "milisegundos\n";
cout << "Version optimizada con SSE\n";
timer = clock();
for(int i=0 ; i < 100000 ; i++ )
d2 = v1.distanceSSE ( v2 );
delay = ( clock() - timer ) ;
cout << "Tiempo gastado: " << delay << "milisegundos\n";
if ( d1 != d2)
cout << "Error: La operacion da diferente resultado!!!\n";
if ( d1 == d2)
cout << "Calculo correcto\n";
//Eliminamos los vectores
v1.Delete();
v2.Delete();
system("PAUSE");
}
Si hay algo que no entendais o quereis que implemente en SSE alguna función en especial no dudeis en hacerme llegar vuestras sugerencias o preocupaciones...
Espero que os haya gustado y que hayais aprendido...
Nos vemos
Math Engine
Blog spin-off de http://lordpakus.blogspot.com/ donde nos centraremos en la creación y uso de un math engine (motor de cálculo) basado en la paralelización multicore mediante threads y las instrucciones de ensamblador SSE. Los primeros articulos al menos serán reposteos del blog original, espero que os guste.
Adicionalmente, si estais interesados en la programación de videojuegos, motores de juegos y matemáticas y demás frikadas podeis echarle un ojo a mi otro blog : http://lordpakus.blogspot.com.es/
jueves, 8 de septiembre de 2011
Math Engine : Capitulo 5. LPVector con SSE(I).
El artículo original lo podeís encontrar aquí
Hola a todos....
Aquí os dejo la implementación de la suma de vectores mediante SSE.
int main (int argc, char* argv[])
{
LPVector v1,v2,v3;
clock_t timer;
float delay;
//Creamos los vectores aleatorios
v1.random(DIM,0.0f,500.0f);
v2.random(DIM,0.0f,500.0f);
v3 = v1;
//Sumamos los vectores
cout << "Version sin optimizar\n";
timer = clock();
v1.addOld ( v2 );
delay = ( clock() - timer ) ;
cout << "Tiempo gastado: " << delay << "milisegundos\n";
cout << "Version optimizada con SSE\n";
timer = clock();
v3.addSSE ( v2 );
delay = ( clock() - timer ) ;
cout << "Tiempo gastado: " << delay << "milisegundos\n";
if ( v1 != v3)
cout << "Error: La operacion da diferente resultado!!!\n";
if ( v1 == v3)
cout << "Calculo correcto\n";
//Eliminamos los vectores
v1.Delete();
v2.Delete();
v3.Delete();
system("PAUSE");
}
void LPVector::addOld(LPVector vector) //Operación de += modo antiguo (solo C)
{
//Si las dimensiones son diferentes , tenemos un problema grave.
if (n != vector.n)
{
cout << "ERROR DIMENSIONAL ENTRE VECTORES\n";
return;
}
for(int i = 0 ; i < n ; ++i)
v[i] += vector.v[i];
}
void LPVector::addSSE(LPVector vector) //Operación de += modo ensamblador SSE
{
//Fast SSE code when float specified
float* const row0 = (float*) &v[0];
float* const row1 = (float*) &(vector.v[0]);
int i = 0;
//Si las dimensiones son diferentes , tenemos un problema grave.
if (n != vector.n)
{
cout << "ERROR DIMENSIONAL ENTRE VECTORES\n";
return;
}
__asm
{
// Carga trozos de los vectores de 4 en 4
// La carga se hace "desordenada para que siempre haya una instrucción como mínimo entre uso y uso de registros."
mov edx, row0
mov esi, row1
}
i = n;
while( i >= 8 )
{
__asm
{
//Copiamos el puntero al vector v donde almacenaremos el valor final
mov edi, edx
//Cargamos la info en los registros SSE
movups xmm0, [edx]
movups xmm1, [esi]
//Aumentamos los contadores en 16 = 4 elementos * 4 bytes por elemento (float)
add edx,16
add esi,16
//Cargamos la info en los registros SSE(tenemos 8 registros donde guardar info)
movups xmm2, [edx]
movups xmm3, [esi]
//Hacemos la operación que toca, en nuestro caso, sumar
addps xmm0 , xmm1 //Sumamos de 4 en 4
addps xmm2 , xmm3 //Sumamos de 4 en 4
//En edi y edx es donde teniamos cargado los trozo de vector v y es donde pondremos el resultado
movups [edi], xmm0
movups [edx], xmm2
//Aumentamos los contadores en 16 = 4 elementos * 4 bytes por elemento (float)
add edx,16
add esi,16
}
i -= 8;
}
//Los flecos los rematamos de la manera tradicional
for(int j = n-i ; j < n ; ++j)
v[j] += vector.v[j];
}
Al ejecutar todo este código tendreis una salida de este estilo:
Version sin optimizar
Tiempo gastado: 321 milisegundos
Version optimizada con SSE
Tiempo gastado : 240 milisegundos
Calculo correcto.
Podreis observar que la ganancia no es comparable a multiplicar por 4 la velocidad como predicen las operaciones SSE sino que se queda en un 25-30% de mejora. Esto es debido a que las operaciones de entrada-salida (movups) gastan muchos recursos y hacen que las operaciones sencillas ( por ejemplo un suma sencilla ) se vean menos mejoradas que las operaciones complicadas ( muchos cálculos y pocos accesos a memoria ).
Espero que os guste, nos vemos
Hola a todos....
Aquí os dejo la implementación de la suma de vectores mediante SSE.
int main (int argc, char* argv[])
{
LPVector v1,v2,v3;
clock_t timer;
float delay;
//Creamos los vectores aleatorios
v1.random(DIM,0.0f,500.0f);
v2.random(DIM,0.0f,500.0f);
v3 = v1;
//Sumamos los vectores
cout << "Version sin optimizar\n";
timer = clock();
v1.addOld ( v2 );
delay = ( clock() - timer ) ;
cout << "Tiempo gastado: " << delay << "milisegundos\n";
cout << "Version optimizada con SSE\n";
timer = clock();
v3.addSSE ( v2 );
delay = ( clock() - timer ) ;
cout << "Tiempo gastado: " << delay << "milisegundos\n";
if ( v1 != v3)
cout << "Error: La operacion da diferente resultado!!!\n";
if ( v1 == v3)
cout << "Calculo correcto\n";
//Eliminamos los vectores
v1.Delete();
v2.Delete();
v3.Delete();
system("PAUSE");
}
void LPVector::addOld(LPVector vector) //Operación de += modo antiguo (solo C)
{
//Si las dimensiones son diferentes , tenemos un problema grave.
if (n != vector.n)
{
cout << "ERROR DIMENSIONAL ENTRE VECTORES\n";
return;
}
for(int i = 0 ; i < n ; ++i)
v[i] += vector.v[i];
}
void LPVector::addSSE(LPVector vector) //Operación de += modo ensamblador SSE
{
//Fast SSE code when float specified
float* const row0 = (float*) &v[0];
float* const row1 = (float*) &(vector.v[0]);
int i = 0;
//Si las dimensiones son diferentes , tenemos un problema grave.
if (n != vector.n)
{
cout << "ERROR DIMENSIONAL ENTRE VECTORES\n";
return;
}
__asm
{
// Carga trozos de los vectores de 4 en 4
// La carga se hace "desordenada para que siempre haya una instrucción como mínimo entre uso y uso de registros."
mov edx, row0
mov esi, row1
}
i = n;
while( i >= 8 )
{
__asm
{
//Copiamos el puntero al vector v donde almacenaremos el valor final
mov edi, edx
//Cargamos la info en los registros SSE
movups xmm0, [edx]
movups xmm1, [esi]
//Aumentamos los contadores en 16 = 4 elementos * 4 bytes por elemento (float)
add edx,16
add esi,16
//Cargamos la info en los registros SSE(tenemos 8 registros donde guardar info)
movups xmm2, [edx]
movups xmm3, [esi]
//Hacemos la operación que toca, en nuestro caso, sumar
addps xmm0 , xmm1 //Sumamos de 4 en 4
addps xmm2 , xmm3 //Sumamos de 4 en 4
//En edi y edx es donde teniamos cargado los trozo de vector v y es donde pondremos el resultado
movups [edi], xmm0
movups [edx], xmm2
//Aumentamos los contadores en 16 = 4 elementos * 4 bytes por elemento (float)
add edx,16
add esi,16
}
i -= 8;
}
//Los flecos los rematamos de la manera tradicional
for(int j = n-i ; j < n ; ++j)
v[j] += vector.v[j];
}
Al ejecutar todo este código tendreis una salida de este estilo:
Version sin optimizar
Tiempo gastado: 321 milisegundos
Version optimizada con SSE
Tiempo gastado : 240 milisegundos
Calculo correcto.
Podreis observar que la ganancia no es comparable a multiplicar por 4 la velocidad como predicen las operaciones SSE sino que se queda en un 25-30% de mejora. Esto es debido a que las operaciones de entrada-salida (movups) gastan muchos recursos y hacen que las operaciones sencillas ( por ejemplo un suma sencilla ) se vean menos mejoradas que las operaciones complicadas ( muchos cálculos y pocos accesos a memoria ).
Espero que os guste, nos vemos
Math Engine : Capitulo 4. Clase LPData
El artículo original lo podeís encontrar aquí
Bienvenidos a un nuevo capitulo de como crear tu propio math engine. El capitulo de hoy es la presentación del tercer (y si no estoy equivocado, último) tipo de dato que se usará en el math engine: el LPData es decir, series de datos. Con series de datos se representarán tanto muestreo de señales (con lo que se podrán realizar FFT y otras transformaciones, de audio sobretodo) como series de datos estadísticos o muestreo de funciones. (maximos, mínimos, medias, rectas de regresión, integración, derivación,etc....)
Por ahora solo os pongo la estructura, que funciones se irán implementando lo dejo para vosotros para que me lo vayais diciendo a medida que las vayais necesitando.
LPData.h:
/**************************************************************************************************/
// Código creado por F.Bordas (LordPakus) como ejemplo de creación de un math engine
// para el blog LordPakus (http://lordpakus.blogspot.com/).
// Prohibida la distribución fuera de este blog sin el permiso expreso del autor
/**************************************************************************************************/
/**************************************************************************************************/
// LPData.h
/**************************************************************************************************/
#ifndef __LPData__
#define __LPData__
class LPData
{
public:
LPData();
~LPData();
//Funciones anexas.
void Set(int t, float* vector); //Funcion para inicializar un vector de n elementos
void Delete(); //Función para limpiar la variable vector
void print(); //Función para imprimir el vector por la consola
void random(int t,float min, float max); //Función para rellenar de random un vector de t posiciones
float Max();
float Min();
float Average();
//OPERACIONES DE AMULACIÓN DE RESULTADO (+=,-=,etc...), devuelven void como norma general
//Operaciones vectoriales
void operator +=(LPData vector);
void operator -=(LPData vector);
//Operaciones con escalares ( sumar , restar , etc ... todo un vector por un escalar)
void operator +=(float scal);
void operator -=(float scal);
void operator *=(float scal);
void operator /=(float scal);
//OPERACIONES QUE DEVUELVEN ALGO (NO ACUMULADORES: +,-,*, etc...)
public:
int n; //número de elementos del vector
float *v; //puntero a memoria dinámica
};
#endif
LPData.cpp:
/**************************************************************************************************/
// Código creado por F.Bordas (LordPakus) como ejemplo de creación de un math engine
// para el blog LordPakus (http://lordpakus.blogspot.com/).
// Prohibida la distribución fuera de este blog sin el permiso expreso del autor
/**************************************************************************************************/
#include "LPData.h"
#include <math.h>
#include <iostream> //Usada para imprimir por consola
using namespace std;
//Constructor
LPData::LPData()
{
n = 0;
v = NULL;
}
//Destructor
LPData::~LPData()
{
//if (n)
//{
// if( v != NULL )
// free(v);
//}
}
//Funcion para inicializar una serie de datos de n elementos
void LPData::Set(int t, float* vector)
{
n = t; //Inicializamos el número de elementos del vector
//Creamos un vector de memoria dinámica.
v = (float*) malloc( sizeof(float) * n );
//Copiamos el vector externo en el vector interno
memcpy(v,vector,sizeof(float) * n );
}
//Función para limpiar la variable vector
void LPData::Delete()
{
n=0;
free(v);
}
//Imprimimos el valor del vector
void LPData::print()
{
for(int i = 0 ; i < n ; ++i)
{
cout << (float) v[i] << " ";
}
}
void LPData::random(int t, float min, float max)
{
n = t; //Inicializamos el número de elementos del vector
//Creamos un vector de memoria dinámica.
v = (float*) malloc( sizeof(float) * n );
for(int i = 0 ; i < n ; ++i)
v[i] = (float)(rand()%(int)(max*1000 - min*1000))/1000 + min;
}
float LPData::Max()
{
float max;
max = v[0];
for(int i = 1 ; i < n ; ++i)
if( v[i] > max )
max = v[i];
return max;
}
float LPData::Min()
{
float min;
min = v[0];
for(int i = 1 ; i < n ; ++i)
if( v[i] < min )
min = v[i];
return min;
}
float LPData::Average()
{
float ave = 0;
for(int i = 0 ; i < n ; ++i)
ave += v[i];
ave /= n;
return ave;
}
//Sobrecarga operador +=
void LPData::operator +=(LPData vector)
{
//Si las dimensiones son diferentes , tenemos un problema grave.
if (n != vector.n)
{
cout << "ERROR DIMENSIONAL ENTRE SERIES DE DATOS\n";
return;
}
for(int i = 0 ; i < n ; ++i)
v[i] += vector.v[i];
}
//Sobrecarga operador -=
void LPData::operator -=(LPData vector)
{
//Si las dimensiones son diferentes , tenemos un problema grave.
if (n != vector.n)
{
cout << "ERROR DIMENSIONAL ENTRE SERIES DE DATOS\n";
return;
}
for(int i = 0 ; i < n ; ++i)
v[i] -= vector.v[i];
}
//Sobrecarga operador +=
void LPData::operator +=(float scal)
{
for(int i = 0 ; i < n ; ++i)
v[i] += scal;
}
//Sobrecarga operador -=
void LPData::operator -=(float scal)
{
for(int i = 0 ; i < n ; ++i)
v[i] -= scal;
}
//Sobrecarga operador *=
void LPData::operator *=(float scal)
{
for(int i = 0 ; i < n ; ++i)
v[i] *= scal;
}
//Sobrecarga operador /=
void LPData::operator /=(float scal)
{
for(int i = 0 ; i < n ; ++i)
v[i] /= scal;
}
Salvo fallo de planificación a partir de ahora solo es ir "rellenando" la estructura que tenemos con nuevas funcionalidades e implementaciones más eficientes.
Espero que os haya gustado,
Nos vemos
Bienvenidos a un nuevo capitulo de como crear tu propio math engine. El capitulo de hoy es la presentación del tercer (y si no estoy equivocado, último) tipo de dato que se usará en el math engine: el LPData es decir, series de datos. Con series de datos se representarán tanto muestreo de señales (con lo que se podrán realizar FFT y otras transformaciones, de audio sobretodo) como series de datos estadísticos o muestreo de funciones. (maximos, mínimos, medias, rectas de regresión, integración, derivación,etc....)
Por ahora solo os pongo la estructura, que funciones se irán implementando lo dejo para vosotros para que me lo vayais diciendo a medida que las vayais necesitando.
LPData.h:
/**************************************************************************************************/
// Código creado por F.Bordas (LordPakus) como ejemplo de creación de un math engine
// para el blog LordPakus (http://lordpakus.blogspot.com/).
// Prohibida la distribución fuera de este blog sin el permiso expreso del autor
/**************************************************************************************************/
/**************************************************************************************************/
// LPData.h
/**************************************************************************************************/
#ifndef __LPData__
#define __LPData__
class LPData
{
public:
LPData();
~LPData();
//Funciones anexas.
void Set(int t, float* vector); //Funcion para inicializar un vector de n elementos
void Delete(); //Función para limpiar la variable vector
void print(); //Función para imprimir el vector por la consola
void random(int t,float min, float max); //Función para rellenar de random un vector de t posiciones
float Max();
float Min();
float Average();
//OPERACIONES DE AMULACIÓN DE RESULTADO (+=,-=,etc...), devuelven void como norma general
//Operaciones vectoriales
void operator +=(LPData vector);
void operator -=(LPData vector);
//Operaciones con escalares ( sumar , restar , etc ... todo un vector por un escalar)
void operator +=(float scal);
void operator -=(float scal);
void operator *=(float scal);
void operator /=(float scal);
//OPERACIONES QUE DEVUELVEN ALGO (NO ACUMULADORES: +,-,*, etc...)
public:
int n; //número de elementos del vector
float *v; //puntero a memoria dinámica
};
#endif
LPData.cpp:
/**************************************************************************************************/
// Código creado por F.Bordas (LordPakus) como ejemplo de creación de un math engine
// para el blog LordPakus (http://lordpakus.blogspot.com/).
// Prohibida la distribución fuera de este blog sin el permiso expreso del autor
/**************************************************************************************************/
#include "LPData.h"
#include <math.h>
#include <iostream> //Usada para imprimir por consola
using namespace std;
//Constructor
LPData::LPData()
{
n = 0;
v = NULL;
}
//Destructor
LPData::~LPData()
{
//if (n)
//{
// if( v != NULL )
// free(v);
//}
}
//Funcion para inicializar una serie de datos de n elementos
void LPData::Set(int t, float* vector)
{
n = t; //Inicializamos el número de elementos del vector
//Creamos un vector de memoria dinámica.
v = (float*) malloc( sizeof(float) * n );
//Copiamos el vector externo en el vector interno
memcpy(v,vector,sizeof(float) * n );
}
//Función para limpiar la variable vector
void LPData::Delete()
{
n=0;
free(v);
}
//Imprimimos el valor del vector
void LPData::print()
{
for(int i = 0 ; i < n ; ++i)
{
cout << (float) v[i] << " ";
}
}
void LPData::random(int t, float min, float max)
{
n = t; //Inicializamos el número de elementos del vector
//Creamos un vector de memoria dinámica.
v = (float*) malloc( sizeof(float) * n );
for(int i = 0 ; i < n ; ++i)
v[i] = (float)(rand()%(int)(max*1000 - min*1000))/1000 + min;
}
float LPData::Max()
{
float max;
max = v[0];
for(int i = 1 ; i < n ; ++i)
if( v[i] > max )
max = v[i];
return max;
}
float LPData::Min()
{
float min;
min = v[0];
for(int i = 1 ; i < n ; ++i)
if( v[i] < min )
min = v[i];
return min;
}
float LPData::Average()
{
float ave = 0;
for(int i = 0 ; i < n ; ++i)
ave += v[i];
ave /= n;
return ave;
}
//Sobrecarga operador +=
void LPData::operator +=(LPData vector)
{
//Si las dimensiones son diferentes , tenemos un problema grave.
if (n != vector.n)
{
cout << "ERROR DIMENSIONAL ENTRE SERIES DE DATOS\n";
return;
}
for(int i = 0 ; i < n ; ++i)
v[i] += vector.v[i];
}
//Sobrecarga operador -=
void LPData::operator -=(LPData vector)
{
//Si las dimensiones son diferentes , tenemos un problema grave.
if (n != vector.n)
{
cout << "ERROR DIMENSIONAL ENTRE SERIES DE DATOS\n";
return;
}
for(int i = 0 ; i < n ; ++i)
v[i] -= vector.v[i];
}
//Sobrecarga operador +=
void LPData::operator +=(float scal)
{
for(int i = 0 ; i < n ; ++i)
v[i] += scal;
}
//Sobrecarga operador -=
void LPData::operator -=(float scal)
{
for(int i = 0 ; i < n ; ++i)
v[i] -= scal;
}
//Sobrecarga operador *=
void LPData::operator *=(float scal)
{
for(int i = 0 ; i < n ; ++i)
v[i] *= scal;
}
//Sobrecarga operador /=
void LPData::operator /=(float scal)
{
for(int i = 0 ; i < n ; ++i)
v[i] /= scal;
}
Salvo fallo de planificación a partir de ahora solo es ir "rellenando" la estructura que tenemos con nuevas funcionalidades e implementaciones más eficientes.
Espero que os haya gustado,
Nos vemos
Math Engine : Capitulo 3. Clase LPMatrix
El artículo original lo podeís encontrar aquí
Bienvenidos a un nuevo capitulo de como crear un math engine. El capitulo de hoy se encargará de mostrar el tipo de variable que seguramente más se usará en las aplicaciones de cálculo, las matrices.
Dado que es totalmente imposible poner todas las funciones que afectan a matrices (solamente con factorizaciones podria llenar miles de lineas de código) este capitulo lo dejaré totalmente abierto (como el del LPVector) para que me vayais proponiendo las funciones que querais que introduzcamos en este módulo.
No obstante, si quereis ir probando código aquí os dejo lo que he implementado hasta el momento:
LPMatrix.h:
/**************************************************************************************************/
// Código creado por F.Bordas (LordPakus) como ejemplo de creación de un math engine
// para el blog LordPakus (http://lordpakus.blogspot.com/).
// Prohibida la distribución fuera de este blog sin el permiso expreso del autor
/**************************************************************************************************/
/**************************************************************************************************/
// LPMatrix.h
/**************************************************************************************************/
#ifndef __LPMatrix__
#define __LPMatrix__
class LPMatrix
{
public:
LPMatrix();
~LPMatrix();
//Funciones anexas.
void Set(int t, int k, float* vector); //Funcion para inicializar una matriz de t*k elementos
void Delete(); //Función para limpiar la variable matriz
void print(); //Función para imprimir la matriz por la consola
//OPERACIONES DE ACUMULACIÓN DE RESULTADO (+=,-=,etc...), devuelven void como norma general
//Operaciones vectoriales
void operator +=(LPMatrix matrix);
void operator -=(LPMatrix matrix);
//Operaciones con escalares ( sumar , restar , etc ... todo una matriz por un escalar)
void operator +=(float scal);
void operator -=(float scal);
void operator *=(float scal);
void operator /=(float scal);
public:
int m,n; //dimensiones de la matriz
float **p; //puntero a memoria dinámica para matrices
};
#endif
LPMatrix.cpp:
/**************************************************************************************************/
// Código creado por F.Bordas (LordPakus) como ejemplo de creación de un math engine
// para el blog LordPakus (http://lordpakus.blogspot.com/).
// Prohibida la distribución fuera de este blog sin el permiso expreso del autor
/**************************************************************************************************/
#include "LPMatrix.h"
#include <math.h>
#include <iostream> //Usada para imprimir por consola
using namespace std;
//Constructor
LPMatrix::LPMatrix()
{
n = 0;
m = 0;
p = NULL;
}
//Destructor
LPMatrix::~LPMatrix()
{
}
//Funciones anexas.
void LPMatrix::Set(int t, int k, float* vector) //Funcion para inicializar una matriz de t*k elementos
{
//Inicializamos el número de elementos del vector
n = t;
m = k;
//Creamos un vector de memoria dinámica donde almacenaremos los punteros subsiguientes.
p = (float**) malloc( sizeof(float *) * n );
//Creamos cada una de las filas o columnas (como queramos verlo) de la matriz
for(int i = 0 ; i < n ; ++i )
p[i] = (float*) malloc( sizeof(float) * m );
//Copiamos el vector externo en el vector interno
for(int i = 0 ; i < n*m ; ++i )
p[i/m][i%m] = vector[i];
}
void LPMatrix::Delete() //Función para limpiar la variable matriz
{
for(int i = 0 ; i < n ; ++i )
free(p[i]);
n=0;
m=0;
free(p);
}
void LPMatrix::print() //Función para imprimir la matriz por la consola
{
for(int i = 0 ; i < n*m ; ++i)
{
if(!(i%m))
cout << "\n";
cout << (float) p[i/m][i%m] << " ";
}
}
//OPERACIONES DE ACUMULACIÓN DE RESULTADO (+=,-=,etc...), devuelven void como norma general
//Operaciones vectoriales
void LPMatrix::operator +=(LPMatrix matrix)
{
//Si las dimensiones son diferentes , tenemos un problema grave.
if ( (n != matrix.n) || (m != matrix.m) )
{
cout << "ERROR DIMENSIONAL ENTRE MATRICES\n";
return;
}
for(int i = 0 ; i < n ; ++i)
for(int j = 0 ; j < m ; ++j)
p[i][j] += matrix.p[i][j];
}
void LPMatrix::operator -=(LPMatrix matrix)
{
//Si las dimensiones son diferentes , tenemos un problema grave.
if ( (n != matrix.n) || (m != matrix.m) )
{
cout << "ERROR DIMENSIONAL ENTRE MATRICES\n";
return;
}
for(int i = 0 ; i < n ; ++i)
for(int j = 0 ; j < m ; ++j)
p[i][j] -= matrix.p[i][j];
}
//Operaciones con escalares ( sumar , restar , etc ... todo una matriz por un escalar)
void LPMatrix::operator +=(float scal)
{
for(int i = 0 ; i < n ; ++i)
for(int j = 0 ; j < m ; ++j)
p[i][j] += scal;
}
void LPMatrix::operator -=(float scal)
{
for(int i = 0 ; i < n ; ++i)
for(int j = 0 ; j < m ; ++j)
p[i][j] -= scal;
}
void LPMatrix::operator *=(float scal)
{
for(int i = 0 ; i < n ; ++i)
for(int j = 0 ; j < m ; ++j)
p[i][j] *= scal;
}
void LPMatrix::operator /=(float scal)
{
for(int i = 0 ; i < n ; ++i)
for(int j = 0 ; j < m ; ++j)
p[i][j] /= scal;
}
main.cpp
int main (int argc, char* argv[])
{
LPMatrix m1,m2;
float mat1[15] = { 1.0f ,1.1f ,1.5f , 1.0f ,1.1f ,1.5f , 1.0f ,1.1f ,1.5f , 1.0f ,1.1f ,1.5f , 1.0f ,1.1f ,1.5f };
float mat2[15] = { 3.0f ,4.1f ,0.5f , 3.0f ,4.1f ,0.5f , 3.0f ,4.1f ,0.5f , 3.0f ,4.1f ,0.5f , 3.0f ,4.1f ,0.5f };
m1.Set(3,5,mat1);
m2.Set(3,5,mat2);
cout << "Matriz 1:";
m1.print();
cout << "\n";
cout << "Matriz 2:";
m2.print();
cout << "\n";
cout << "Suma de matrices:";
m2 += m1;
m2.print();
cout << "\n";
//Eliminamos las matrices
m1.Delete();
m2.Delete();
system("PAUSE");
}
Espero que os haya servido y os haya gustado.
Nos vemos
Bienvenidos a un nuevo capitulo de como crear un math engine. El capitulo de hoy se encargará de mostrar el tipo de variable que seguramente más se usará en las aplicaciones de cálculo, las matrices.
Dado que es totalmente imposible poner todas las funciones que afectan a matrices (solamente con factorizaciones podria llenar miles de lineas de código) este capitulo lo dejaré totalmente abierto (como el del LPVector) para que me vayais proponiendo las funciones que querais que introduzcamos en este módulo.
No obstante, si quereis ir probando código aquí os dejo lo que he implementado hasta el momento:
LPMatrix.h:
/**************************************************************************************************/
// Código creado por F.Bordas (LordPakus) como ejemplo de creación de un math engine
// para el blog LordPakus (http://lordpakus.blogspot.com/).
// Prohibida la distribución fuera de este blog sin el permiso expreso del autor
/**************************************************************************************************/
/**************************************************************************************************/
// LPMatrix.h
/**************************************************************************************************/
#ifndef __LPMatrix__
#define __LPMatrix__
class LPMatrix
{
public:
LPMatrix();
~LPMatrix();
//Funciones anexas.
void Set(int t, int k, float* vector); //Funcion para inicializar una matriz de t*k elementos
void Delete(); //Función para limpiar la variable matriz
void print(); //Función para imprimir la matriz por la consola
//OPERACIONES DE ACUMULACIÓN DE RESULTADO (+=,-=,etc...), devuelven void como norma general
//Operaciones vectoriales
void operator +=(LPMatrix matrix);
void operator -=(LPMatrix matrix);
//Operaciones con escalares ( sumar , restar , etc ... todo una matriz por un escalar)
void operator +=(float scal);
void operator -=(float scal);
void operator *=(float scal);
void operator /=(float scal);
public:
int m,n; //dimensiones de la matriz
float **p; //puntero a memoria dinámica para matrices
};
#endif
LPMatrix.cpp:
/**************************************************************************************************/
// Código creado por F.Bordas (LordPakus) como ejemplo de creación de un math engine
// para el blog LordPakus (http://lordpakus.blogspot.com/).
// Prohibida la distribución fuera de este blog sin el permiso expreso del autor
/**************************************************************************************************/
#include "LPMatrix.h"
#include <math.h>
#include <iostream> //Usada para imprimir por consola
using namespace std;
//Constructor
LPMatrix::LPMatrix()
{
n = 0;
m = 0;
p = NULL;
}
//Destructor
LPMatrix::~LPMatrix()
{
}
//Funciones anexas.
void LPMatrix::Set(int t, int k, float* vector) //Funcion para inicializar una matriz de t*k elementos
{
//Inicializamos el número de elementos del vector
n = t;
m = k;
//Creamos un vector de memoria dinámica donde almacenaremos los punteros subsiguientes.
p = (float**) malloc( sizeof(float *) * n );
//Creamos cada una de las filas o columnas (como queramos verlo) de la matriz
for(int i = 0 ; i < n ; ++i )
p[i] = (float*) malloc( sizeof(float) * m );
//Copiamos el vector externo en el vector interno
for(int i = 0 ; i < n*m ; ++i )
p[i/m][i%m] = vector[i];
}
void LPMatrix::Delete() //Función para limpiar la variable matriz
{
for(int i = 0 ; i < n ; ++i )
free(p[i]);
n=0;
m=0;
free(p);
}
void LPMatrix::print() //Función para imprimir la matriz por la consola
{
for(int i = 0 ; i < n*m ; ++i)
{
if(!(i%m))
cout << "\n";
cout << (float) p[i/m][i%m] << " ";
}
}
//OPERACIONES DE ACUMULACIÓN DE RESULTADO (+=,-=,etc...), devuelven void como norma general
//Operaciones vectoriales
void LPMatrix::operator +=(LPMatrix matrix)
{
//Si las dimensiones son diferentes , tenemos un problema grave.
if ( (n != matrix.n) || (m != matrix.m) )
{
cout << "ERROR DIMENSIONAL ENTRE MATRICES\n";
return;
}
for(int i = 0 ; i < n ; ++i)
for(int j = 0 ; j < m ; ++j)
p[i][j] += matrix.p[i][j];
}
void LPMatrix::operator -=(LPMatrix matrix)
{
//Si las dimensiones son diferentes , tenemos un problema grave.
if ( (n != matrix.n) || (m != matrix.m) )
{
cout << "ERROR DIMENSIONAL ENTRE MATRICES\n";
return;
}
for(int i = 0 ; i < n ; ++i)
for(int j = 0 ; j < m ; ++j)
p[i][j] -= matrix.p[i][j];
}
//Operaciones con escalares ( sumar , restar , etc ... todo una matriz por un escalar)
void LPMatrix::operator +=(float scal)
{
for(int i = 0 ; i < n ; ++i)
for(int j = 0 ; j < m ; ++j)
p[i][j] += scal;
}
void LPMatrix::operator -=(float scal)
{
for(int i = 0 ; i < n ; ++i)
for(int j = 0 ; j < m ; ++j)
p[i][j] -= scal;
}
void LPMatrix::operator *=(float scal)
{
for(int i = 0 ; i < n ; ++i)
for(int j = 0 ; j < m ; ++j)
p[i][j] *= scal;
}
void LPMatrix::operator /=(float scal)
{
for(int i = 0 ; i < n ; ++i)
for(int j = 0 ; j < m ; ++j)
p[i][j] /= scal;
}
main.cpp
int main (int argc, char* argv[])
{
LPMatrix m1,m2;
float mat1[15] = { 1.0f ,1.1f ,1.5f , 1.0f ,1.1f ,1.5f , 1.0f ,1.1f ,1.5f , 1.0f ,1.1f ,1.5f , 1.0f ,1.1f ,1.5f };
float mat2[15] = { 3.0f ,4.1f ,0.5f , 3.0f ,4.1f ,0.5f , 3.0f ,4.1f ,0.5f , 3.0f ,4.1f ,0.5f , 3.0f ,4.1f ,0.5f };
m1.Set(3,5,mat1);
m2.Set(3,5,mat2);
cout << "Matriz 1:";
m1.print();
cout << "\n";
cout << "Matriz 2:";
m2.print();
cout << "\n";
cout << "Suma de matrices:";
m2 += m1;
m2.print();
cout << "\n";
//Eliminamos las matrices
m1.Delete();
m2.Delete();
system("PAUSE");
}
Espero que os haya servido y os haya gustado.
Nos vemos
Math Engine : Capitulo 2. Clase LPVector
El artículo original lo podeís encontrar aquí
El capitulo de hoy trata sobre la clase LPVector que es la que se encarga de almacenar un vector de cualquier tamaño y poder operar con el.
La lista de operaciones que he considerado imprescindibles son las siguientes, todas las que querais que pongamos adicionales las ponemos... a la que tengamos una lista estable de operaciones nos dedicaremos a optimizarlas con SSE.:
//Funciones anexas.
void Set(int t, float* vector); //Funcion para inicializar un vector de n elementos
void Delete(); //Función para limpiar la variable vector
void print(); //Función para imprimir el vector por la consola
//OPERACIONES DE AMULACIÓN DE RESULTADO (+=,-=,etc...), devuelven void como norma general
//Operaciones vectoriales
void operator +=(LPVector vector);
void operator -=(LPVector vector);
void sqrt_vec(); //Calculamos la raíz cuadrada de todo los elementos del vector
void normalize(); //Normaliza el vector (hace que el módulo sea 1)
//Operaciones con escalares ( sumar , restar , etc ... todo un vector por un escalar)
void operator +=(float scal);
void operator -=(float scal);
void operator *=(float scal);
void operator /=(float scal);
//OPERACIONES QUE DEVUELVEN ALGO (NO ACUMULADORES: +,-,*, etc...)
//Operaciones vectoriales que devuelven escalares
float operator ^(LPVector vector); //Operador producto escalar.
float module(); //Calcula el módulo del vector
El código se organiza en dos archivos LPVector (.cpp y .h) junto con los cambios del main para demostrar que funcionan:
main.cpp:
/**************************************************************************************************/
// Código creado por F.Bordas (LordPakus) como ejemplo de creación de un math engine
// para el blog LordPakus (http://lordpakus.blogspot.com/).
// Prohibida la distribución fuera de este blog sin el permiso expreso del autor
/**************************************************************************************************/
/**************************************************************************************************/
// main.cpp : Main de nuestro MathEngine
/**************************************************************************************************/
//Include del Math engine
#include "LPMath.h"
//Delete console
//#pragma comment(linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"")
#include <iostream> //Usada para imprimir por consola
using namespace std;
int main (int argc, char* argv[])
{
LPVector v1,v2;
float vec1[4] = { 1.0f ,1.1f ,1.5f ,2.5f };
float vec2[4] = { 3.0f ,4.1f ,0.5f ,0.4f };
float n;
//Creamos los vectores
v1.Set(4,vec1);
v2.Set(4,vec2);
cout << "Vector 1: ";
v1.print();
cout << "\n";
cout << "Vector 2: ";
v2.print();
cout << "\n";
n = v1^v2;
cout << "Producto escalar: " << n << "\n";
n = v1.module();
cout << "Modulo vector 1: " << n << "\n";
n = v2.module();
cout << "Modulo vector 2: " << n << "\n";
v1.normalize();
n = v1.module();
cout << "Modulo vector 1 normalizado: " << n << "\n";
v2.normalize();
n = v2.module();
cout << "Modulo vector 2 normalizado: " << n << "\n";
v2 += v1;
cout << "Suma de vectores: ";
v2.print();
cout << "\n";
n = v2.module();
cout << "Modulo de suma de vectores: " << n << "\n";
v2.normalize();
n = v2.module();
cout << "Modulo de suma de vectores normalizado: " << n << "\n";
//Eliminamos los vectores
v1.Delete();
v2.Delete();
system("PAUSE");
}
LPVector.cpp
/**************************************************************************************************/
// Código creado por F.Bordas (LordPakus) como ejemplo de creación de un math engine
// para el blog LordPakus (http://lordpakus.blogspot.com/).
// Prohibida la distribución fuera de este blog sin el permiso expreso del autor
/**************************************************************************************************/
#include "LPVector.h"
#include <math.h>
#include <iostream> //Usada para imprimir por consola
using namespace std;
//Constructor
LPVector::LPVector()
{
n = 0;
v = NULL;
}
//Destructor
LPVector::~LPVector()
{
//if (n)
//{
// if( v != NULL )
// free(v);
//}
}
//Funcion para inicializar un vector de n elementos
void LPVector::Set(int t, float* vector)
{
n = t; //Inicializamos el número de elementos del vector
//Creamos un vector de memoria dinámica.
v = (float*) malloc( sizeof(float) * n );
//Copiamos el vector externo en el vector interno
memcpy(v,vector,sizeof(float) * n );
}
//Función para limpiar la variable vector
void LPVector::Delete()
{
n=0;
free(v);
}
//Imprimimos el valor del vector
void LPVector::print()
{
for(int i = 0 ; i < n ; ++i)
{
cout << (float) v[i] << " ";
}
}
void LPVector::random(int t, float min, float max)
{
n = t; //Inicializamos el número de elementos del vector
//Creamos un vector de memoria dinámica.
v = (float*) malloc( sizeof(float) * n );
for(int i = 0 ; i < n ; ++i)
v[i] = (float)(rand()%(int)(max*1000 - min*1000))/1000 + min;
}
void LPVector::cross(LPVector vector)
{
//POR IMPLEMENTAR
}
void LPVector::sqrt_vec()
{
for(int i = 0 ; i < n ; ++i)
v[i] = sqrt(v[i]);
}
void LPVector::normalize()
{
//Dividimos cada componente por el módulo
*this /= this->module();
}
//Sobrecarga operador +=
void LPVector::operator +=(LPVector vector)
{
//Si las dimensiones son diferentes , tenemos un problema grave.
if (n != vector.n)
{
cout << "ERROR DIMENSIONAL ENTRE VECTORES\n";
return;
}
for(int i = 0 ; i < n ; ++i)
v[i] += vector.v[i];
}
//Sobrecarga operador -=
void LPVector::operator -=(LPVector vector)
{
//Si las dimensiones son diferentes , tenemos un problema grave.
if (n != vector.n)
{
cout << "ERROR DIMENSIONAL ENTRE VECTORES\n";
return;
}
for(int i = 0 ; i < n ; ++i)
v[i] -= vector.v[i];
}
//Sobrecarga operador +=
void LPVector::operator +=(float scal)
{
for(int i = 0 ; i < n ; ++i)
v[i] += scal;
}
//Sobrecarga operador -=
void LPVector::operator -=(float scal)
{
for(int i = 0 ; i < n ; ++i)
v[i] -= scal;
}
//Sobrecarga operador *=
void LPVector::operator *=(float scal)
{
for(int i = 0 ; i < n ; ++i)
v[i] *= scal;
}
//Sobrecarga operador /=
void LPVector::operator /=(float scal)
{
for(int i = 0 ; i < n ; ++i)
v[i] /= scal;
}
//Sobrecarga operador *= //Este operador es el que nos devolverá matrices como resultado del producto de una columna por un fila.
//Es decir, es el producto vectorial. Ya lo veremos a su momento
/*void LPVector::operator *=(LPVector vector)
{
//Si las dimensiones son diferentes , tenemos un problema grave.
if (n != vector.n)
{
cout << "ERROR DIMENSIONAL ENTRE VECTORES\n";
return;
}
for(int i = 0 ; i < n ; ++i)
v[i] += vector.v[i];
}
*/
//Sobrecarga operador ^ A partir de ahora se entederá que es el producto escalar.
float LPVector::operator ^(LPVector vector)
{
float a = 0.0;
//Si las dimensiones son diferentes , tenemos un problema grave.
if (n != vector.n)
{
cout << "ERROR DIMENSIONAL ENTRE VECTORES\n";
return 0.0;
}
for(int i = 0 ; i < n ; ++i)
a += v[i] * vector.v[i];
return a;
}
float LPVector::module()
{
float a = 0.0;
for(int i = 0 ; i < n ; ++i)
a += v[i] * v[i];
return sqrt(a);
}
float LPVector::distance(LPVector vector)
{
float a = 0.0;
float temp = 0.0;
//Si las dimensiones son diferentes , tenemos un problema grave.
if (n != vector.n)
{
cout << "ERROR DIMENSIONAL ENTRE VECTORES\n";
return (-1.0);
}
for(int i = 0 ; i < n ; ++i)
{
temp = (v[i] - vector.v[i]);
a+=temp*temp;
}
return sqrt(a);
}
LPVector.h
/**************************************************************************************************/
// Código creado por F.Bordas (LordPakus) como ejemplo de creación de un math engine
// para el blog LordPakus (http://lordpakus.blogspot.com/).
// Prohibida la distribución fuera de este blog sin el permiso expreso del autor
/**************************************************************************************************/
/**************************************************************************************************/
// LPVector.h
/**************************************************************************************************/
#ifndef __LPVector__
#define __LPVector__
class LPVector
{
public:
LPVector();
~LPVector();
//Funciones anexas.
void Set(int t, float* vector); //Funcion para inicializar un vector de n elementos
void Delete(); //Función para limpiar la variable vector
void print(); //Función para imprimir el vector por la consola
void random(int t,float min, float max); //Función para rellenar de random un vector de t posiciones
//OPERACIONES DE AMULACIÓN DE RESULTADO (+=,-=,etc...), devuelven void como norma general
//Operaciones vectoriales
void operator +=(LPVector vector);
void operator -=(LPVector vector);
void cross(LPVector vector); //Calculamos el producto vectorial (cross) POR HACER
void sqrt_vec(); //Calculamos la raíz cuadrada de todo los elementos del vector
void normalize(); //Normaliza el vector (hace que el módulo sea 1)
//Operaciones con escalares ( sumar , restar , etc ... todo un vector por un escalar)
void operator +=(float scal);
void operator -=(float scal);
void operator *=(float scal);
void operator /=(float scal);
//OPERACIONES QUE DEVUELVEN ALGO (NO ACUMULADORES: +,-,*, etc...)
//Operaciones vectoriales que devuelven escalares
float operator ^(LPVector vector); //Operador producto escalar.
float module(); //Calcula el módulo del vector
float distance(LPVector vector);
public:
int n; //número de elementos del vector
float *v; //puntero a memoria dinámica
};
#endif
Cualquier otra cosa que se os ocurra que le pongamos o cualquier fallo que veais, hacedmelo llegar
Espero que os haya gustado,
Nos vemos
El capitulo de hoy trata sobre la clase LPVector que es la que se encarga de almacenar un vector de cualquier tamaño y poder operar con el.
La lista de operaciones que he considerado imprescindibles son las siguientes, todas las que querais que pongamos adicionales las ponemos... a la que tengamos una lista estable de operaciones nos dedicaremos a optimizarlas con SSE.:
//Funciones anexas.
void Set(int t, float* vector); //Funcion para inicializar un vector de n elementos
void Delete(); //Función para limpiar la variable vector
void print(); //Función para imprimir el vector por la consola
//OPERACIONES DE AMULACIÓN DE RESULTADO (+=,-=,etc...), devuelven void como norma general
//Operaciones vectoriales
void operator +=(LPVector vector);
void operator -=(LPVector vector);
void sqrt_vec(); //Calculamos la raíz cuadrada de todo los elementos del vector
void normalize(); //Normaliza el vector (hace que el módulo sea 1)
//Operaciones con escalares ( sumar , restar , etc ... todo un vector por un escalar)
void operator +=(float scal);
void operator -=(float scal);
void operator *=(float scal);
void operator /=(float scal);
//OPERACIONES QUE DEVUELVEN ALGO (NO ACUMULADORES: +,-,*, etc...)
//Operaciones vectoriales que devuelven escalares
float operator ^(LPVector vector); //Operador producto escalar.
float module(); //Calcula el módulo del vector
El código se organiza en dos archivos LPVector (.cpp y .h) junto con los cambios del main para demostrar que funcionan:
main.cpp:
/**************************************************************************************************/
// Código creado por F.Bordas (LordPakus) como ejemplo de creación de un math engine
// para el blog LordPakus (http://lordpakus.blogspot.com/).
// Prohibida la distribución fuera de este blog sin el permiso expreso del autor
/**************************************************************************************************/
/**************************************************************************************************/
// main.cpp : Main de nuestro MathEngine
/**************************************************************************************************/
//Include del Math engine
#include "LPMath.h"
//Delete console
//#pragma comment(linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"")
#include <iostream> //Usada para imprimir por consola
using namespace std;
int main (int argc, char* argv[])
{
LPVector v1,v2;
float vec1[4] = { 1.0f ,1.1f ,1.5f ,2.5f };
float vec2[4] = { 3.0f ,4.1f ,0.5f ,0.4f };
float n;
//Creamos los vectores
v1.Set(4,vec1);
v2.Set(4,vec2);
cout << "Vector 1: ";
v1.print();
cout << "\n";
cout << "Vector 2: ";
v2.print();
cout << "\n";
n = v1^v2;
cout << "Producto escalar: " << n << "\n";
n = v1.module();
cout << "Modulo vector 1: " << n << "\n";
n = v2.module();
cout << "Modulo vector 2: " << n << "\n";
v1.normalize();
n = v1.module();
cout << "Modulo vector 1 normalizado: " << n << "\n";
v2.normalize();
n = v2.module();
cout << "Modulo vector 2 normalizado: " << n << "\n";
v2 += v1;
cout << "Suma de vectores: ";
v2.print();
cout << "\n";
n = v2.module();
cout << "Modulo de suma de vectores: " << n << "\n";
v2.normalize();
n = v2.module();
cout << "Modulo de suma de vectores normalizado: " << n << "\n";
//Eliminamos los vectores
v1.Delete();
v2.Delete();
system("PAUSE");
}
LPVector.cpp
/**************************************************************************************************/
// Código creado por F.Bordas (LordPakus) como ejemplo de creación de un math engine
// para el blog LordPakus (http://lordpakus.blogspot.com/).
// Prohibida la distribución fuera de este blog sin el permiso expreso del autor
/**************************************************************************************************/
#include "LPVector.h"
#include <math.h>
#include <iostream> //Usada para imprimir por consola
using namespace std;
//Constructor
LPVector::LPVector()
{
n = 0;
v = NULL;
}
//Destructor
LPVector::~LPVector()
{
//if (n)
//{
// if( v != NULL )
// free(v);
//}
}
//Funcion para inicializar un vector de n elementos
void LPVector::Set(int t, float* vector)
{
n = t; //Inicializamos el número de elementos del vector
//Creamos un vector de memoria dinámica.
v = (float*) malloc( sizeof(float) * n );
//Copiamos el vector externo en el vector interno
memcpy(v,vector,sizeof(float) * n );
}
//Función para limpiar la variable vector
void LPVector::Delete()
{
n=0;
free(v);
}
//Imprimimos el valor del vector
void LPVector::print()
{
for(int i = 0 ; i < n ; ++i)
{
cout << (float) v[i] << " ";
}
}
void LPVector::random(int t, float min, float max)
{
n = t; //Inicializamos el número de elementos del vector
//Creamos un vector de memoria dinámica.
v = (float*) malloc( sizeof(float) * n );
for(int i = 0 ; i < n ; ++i)
v[i] = (float)(rand()%(int)(max*1000 - min*1000))/1000 + min;
}
void LPVector::cross(LPVector vector)
{
//POR IMPLEMENTAR
}
void LPVector::sqrt_vec()
{
for(int i = 0 ; i < n ; ++i)
v[i] = sqrt(v[i]);
}
void LPVector::normalize()
{
//Dividimos cada componente por el módulo
*this /= this->module();
}
//Sobrecarga operador +=
void LPVector::operator +=(LPVector vector)
{
//Si las dimensiones son diferentes , tenemos un problema grave.
if (n != vector.n)
{
cout << "ERROR DIMENSIONAL ENTRE VECTORES\n";
return;
}
for(int i = 0 ; i < n ; ++i)
v[i] += vector.v[i];
}
//Sobrecarga operador -=
void LPVector::operator -=(LPVector vector)
{
//Si las dimensiones son diferentes , tenemos un problema grave.
if (n != vector.n)
{
cout << "ERROR DIMENSIONAL ENTRE VECTORES\n";
return;
}
for(int i = 0 ; i < n ; ++i)
v[i] -= vector.v[i];
}
//Sobrecarga operador +=
void LPVector::operator +=(float scal)
{
for(int i = 0 ; i < n ; ++i)
v[i] += scal;
}
//Sobrecarga operador -=
void LPVector::operator -=(float scal)
{
for(int i = 0 ; i < n ; ++i)
v[i] -= scal;
}
//Sobrecarga operador *=
void LPVector::operator *=(float scal)
{
for(int i = 0 ; i < n ; ++i)
v[i] *= scal;
}
//Sobrecarga operador /=
void LPVector::operator /=(float scal)
{
for(int i = 0 ; i < n ; ++i)
v[i] /= scal;
}
//Sobrecarga operador *= //Este operador es el que nos devolverá matrices como resultado del producto de una columna por un fila.
//Es decir, es el producto vectorial. Ya lo veremos a su momento
/*void LPVector::operator *=(LPVector vector)
{
//Si las dimensiones son diferentes , tenemos un problema grave.
if (n != vector.n)
{
cout << "ERROR DIMENSIONAL ENTRE VECTORES\n";
return;
}
for(int i = 0 ; i < n ; ++i)
v[i] += vector.v[i];
}
*/
//Sobrecarga operador ^ A partir de ahora se entederá que es el producto escalar.
float LPVector::operator ^(LPVector vector)
{
float a = 0.0;
//Si las dimensiones son diferentes , tenemos un problema grave.
if (n != vector.n)
{
cout << "ERROR DIMENSIONAL ENTRE VECTORES\n";
return 0.0;
}
for(int i = 0 ; i < n ; ++i)
a += v[i] * vector.v[i];
return a;
}
float LPVector::module()
{
float a = 0.0;
for(int i = 0 ; i < n ; ++i)
a += v[i] * v[i];
return sqrt(a);
}
float LPVector::distance(LPVector vector)
{
float a = 0.0;
float temp = 0.0;
//Si las dimensiones son diferentes , tenemos un problema grave.
if (n != vector.n)
{
cout << "ERROR DIMENSIONAL ENTRE VECTORES\n";
return (-1.0);
}
for(int i = 0 ; i < n ; ++i)
{
temp = (v[i] - vector.v[i]);
a+=temp*temp;
}
return sqrt(a);
}
LPVector.h
/**************************************************************************************************/
// Código creado por F.Bordas (LordPakus) como ejemplo de creación de un math engine
// para el blog LordPakus (http://lordpakus.blogspot.com/).
// Prohibida la distribución fuera de este blog sin el permiso expreso del autor
/**************************************************************************************************/
/**************************************************************************************************/
// LPVector.h
/**************************************************************************************************/
#ifndef __LPVector__
#define __LPVector__
class LPVector
{
public:
LPVector();
~LPVector();
//Funciones anexas.
void Set(int t, float* vector); //Funcion para inicializar un vector de n elementos
void Delete(); //Función para limpiar la variable vector
void print(); //Función para imprimir el vector por la consola
void random(int t,float min, float max); //Función para rellenar de random un vector de t posiciones
//OPERACIONES DE AMULACIÓN DE RESULTADO (+=,-=,etc...), devuelven void como norma general
//Operaciones vectoriales
void operator +=(LPVector vector);
void operator -=(LPVector vector);
void cross(LPVector vector); //Calculamos el producto vectorial (cross) POR HACER
void sqrt_vec(); //Calculamos la raíz cuadrada de todo los elementos del vector
void normalize(); //Normaliza el vector (hace que el módulo sea 1)
//Operaciones con escalares ( sumar , restar , etc ... todo un vector por un escalar)
void operator +=(float scal);
void operator -=(float scal);
void operator *=(float scal);
void operator /=(float scal);
//OPERACIONES QUE DEVUELVEN ALGO (NO ACUMULADORES: +,-,*, etc...)
//Operaciones vectoriales que devuelven escalares
float operator ^(LPVector vector); //Operador producto escalar.
float module(); //Calcula el módulo del vector
float distance(LPVector vector);
public:
int n; //número de elementos del vector
float *v; //puntero a memoria dinámica
};
#endif
Cualquier otra cosa que se os ocurra que le pongamos o cualquier fallo que veais, hacedmelo llegar
Espero que os haya gustado,
Nos vemos
Math Engine : Capitulo 1. Sobrecarga de operadores
El artículo original lo podeís encontrar aqui
En este capitulo no haremos mucho más que iniciar las bases del proyecto.
Conceptos fundamentales:
1. Todo el código se escribirá en un inicio en C/C++
2. Todo el código se intentará encapsular en clases (aunque en prinicipio no habrá gestores como en el game engine, usease el MathEngine será una colección de funcionalidades matematicas no un motor que correrá de fondo gestionandolo todo).
3. Todas las optimizaciones irán con ifdef (así se podrán hacer diferentes compilaciones optimizadas en función de la arquitectura en que se trabaje : tipo de ensamblador, tipo de procesador, etc...). Las optimizaciones mínimas que se tienen en cuenta ahora mismo son paralelización multicore y ensamblador vectorial SSE.
4. El código que gestione el usuario ha de ser mínimo , claro y sencillo.
5. Habrá 3 grandes bloques de trabajo: operaciones entre vectores, operaciones entre matrices y operaciones vector-matriz.
6. Las operaciones se irán implementado a medida que vosotros las vayais pidiendo así que si os interesa algún función en particular no dudeis en pedirla.
Dicha toda esta parrafada, expondremos el capitulo como tal.
Lo primero será crear el proyecto. Deberiais saber hacerlo pero si no teneis mucha memoria :D, podeis mirar como se creó el proyecto en el game engine (http://lordpakus.blogspot.com/2011/05/gameengine-capitulo-1.html).
Una vez tengais el proyecto creado cread los siguientes archivos y copiad el siguiente código. Vereis que no es más un código muy sencillo de operación entre vectores.
main.cpp:
/**************************************************************************************************/
// Código creado por F.Bordas (LordPakus) como ejemplo de creación de un math engine
// para el blog LordPakus (http://lordpakus.blogspot.com/).
// Prohibida la distribución fuera de este blog sin el permiso expreso del autor
/**************************************************************************************************/
/**************************************************************************************************/
// main.cpp : Main de nuestro MathEngine
/**************************************************************************************************/
//Include del Math engine
#include "LPMath.h"
//Delete console
//#pragma comment(linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"")
#include <iostream> //Usada para imprimir por consola
using namespace std;
int main (int argc, char* argv[])
{
LPVector4 v1,v2;
v1.Set(0.0f,1.0f,2.0f,3.0f);
v2.Set(1.1f,1.2f,1.3f,1.4f);
v1 += v2;
cout << "Vector 1: ";
v1.print();
cout << "\n";
cout << "Vector 2: ";
v2.print();
}
LPMath.h
/**************************************************************************************************/
// Código creado por F.Bordas (LordPakus) como ejemplo de creación de un math engine
// para el blog LordPakus (http://lordpakus.blogspot.com/).
// Prohibida la distribución fuera de este blog sin el permiso expreso del autor
/**************************************************************************************************/
//Lista de todos los includes necesarios para el math engine.
#include "LPVector4.h"
LPVector4.h
/**************************************************************************************************/
// Código creado por F.Bordas (LordPakus) como ejemplo de creación de un math engine
// para el blog LordPakus (http://lordpakus.blogspot.com/).
// Prohibida la distribución fuera de este blog sin el permiso expreso del autor
/**************************************************************************************************/
/**************************************************************************************************/
// LPVector.h
/**************************************************************************************************/
#ifndef __LPVector4__
#define __LPVector4__
class LPVector4
{
public:
void Set(float x, float y , float z , float t); //Funcion para inicializar un vector de 4 elementos
void print(); //Función para imprimir el vector por la consola
void operator +=(const LPVector4 v); //Sobrecarga de operador +=
public:
float xv,yv,zv,tv;
};
#endif
LPVector4.cp
/**************************************************************************************************/
// Código creado por F.Bordas (LordPakus) como ejemplo de creación de un math engine
// para el blog LordPakus (http://lordpakus.blogspot.com/).
// Prohibida la distribución fuera de este blog sin el permiso expreso del autor
/**************************************************************************************************/
#include "LPVector4.h"
#include <iostream> //Usada para imprimir por consola
using namespace std;
void LPVector4::Set(float x, float y , float z , float t) //Funcion para inicializar un vector de 4 elementos
{
xv = x;
yv = y;
zv = z;
tv = t;
}
//Imprimimos el valor del vector
void LPVector4::print()
{
cout << "x: " << xv << " y: " << yv << " z: " << zv << " t: " << tv;
}
//Sobrecarga operador +=
void LPVector4::operator +=(const LPVector4 v)
{
xv += v.xv;
yv += v.yv;
zv += v.zv;
tv += v.tv;
}
Para probar el ejecutable debereis hacerlo desde una consola para que os permita ver el resultado.
Por ahora lo único que os debe interesar es como se ha hecho la sobrecarga del operador += aplicado a los vectores ya que esta sobrecarga es de lo que más se usara en el MathEngine para hacer que el código quede limpio de cara al usuario.
Sin más, aqui os dejo, espero que os lo hayais pasado bien y hayais aprendido
Nos vemos
En este capitulo no haremos mucho más que iniciar las bases del proyecto.
Conceptos fundamentales:
1. Todo el código se escribirá en un inicio en C/C++
2. Todo el código se intentará encapsular en clases (aunque en prinicipio no habrá gestores como en el game engine, usease el MathEngine será una colección de funcionalidades matematicas no un motor que correrá de fondo gestionandolo todo).
3. Todas las optimizaciones irán con ifdef (así se podrán hacer diferentes compilaciones optimizadas en función de la arquitectura en que se trabaje : tipo de ensamblador, tipo de procesador, etc...). Las optimizaciones mínimas que se tienen en cuenta ahora mismo son paralelización multicore y ensamblador vectorial SSE.
4. El código que gestione el usuario ha de ser mínimo , claro y sencillo.
5. Habrá 3 grandes bloques de trabajo: operaciones entre vectores, operaciones entre matrices y operaciones vector-matriz.
6. Las operaciones se irán implementado a medida que vosotros las vayais pidiendo así que si os interesa algún función en particular no dudeis en pedirla.
Dicha toda esta parrafada, expondremos el capitulo como tal.
Lo primero será crear el proyecto. Deberiais saber hacerlo pero si no teneis mucha memoria :D, podeis mirar como se creó el proyecto en el game engine (http://lordpakus.blogspot.com/2011/05/gameengine-capitulo-1.html).
Una vez tengais el proyecto creado cread los siguientes archivos y copiad el siguiente código. Vereis que no es más un código muy sencillo de operación entre vectores.
main.cpp:
/**************************************************************************************************/
// Código creado por F.Bordas (LordPakus) como ejemplo de creación de un math engine
// para el blog LordPakus (http://lordpakus.blogspot.com/).
// Prohibida la distribución fuera de este blog sin el permiso expreso del autor
/**************************************************************************************************/
/**************************************************************************************************/
// main.cpp : Main de nuestro MathEngine
/**************************************************************************************************/
//Include del Math engine
#include "LPMath.h"
//Delete console
//#pragma comment(linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"")
#include <iostream> //Usada para imprimir por consola
using namespace std;
int main (int argc, char* argv[])
{
LPVector4 v1,v2;
v1.Set(0.0f,1.0f,2.0f,3.0f);
v2.Set(1.1f,1.2f,1.3f,1.4f);
v1 += v2;
cout << "Vector 1: ";
v1.print();
cout << "\n";
cout << "Vector 2: ";
v2.print();
}
LPMath.h
/**************************************************************************************************/
// Código creado por F.Bordas (LordPakus) como ejemplo de creación de un math engine
// para el blog LordPakus (http://lordpakus.blogspot.com/).
// Prohibida la distribución fuera de este blog sin el permiso expreso del autor
/**************************************************************************************************/
//Lista de todos los includes necesarios para el math engine.
#include "LPVector4.h"
LPVector4.h
/**************************************************************************************************/
// Código creado por F.Bordas (LordPakus) como ejemplo de creación de un math engine
// para el blog LordPakus (http://lordpakus.blogspot.com/).
// Prohibida la distribución fuera de este blog sin el permiso expreso del autor
/**************************************************************************************************/
/**************************************************************************************************/
// LPVector.h
/**************************************************************************************************/
#ifndef __LPVector4__
#define __LPVector4__
class LPVector4
{
public:
void Set(float x, float y , float z , float t); //Funcion para inicializar un vector de 4 elementos
void print(); //Función para imprimir el vector por la consola
void operator +=(const LPVector4 v); //Sobrecarga de operador +=
public:
float xv,yv,zv,tv;
};
#endif
LPVector4.cp
/**************************************************************************************************/
// Código creado por F.Bordas (LordPakus) como ejemplo de creación de un math engine
// para el blog LordPakus (http://lordpakus.blogspot.com/).
// Prohibida la distribución fuera de este blog sin el permiso expreso del autor
/**************************************************************************************************/
#include "LPVector4.h"
#include <iostream> //Usada para imprimir por consola
using namespace std;
void LPVector4::Set(float x, float y , float z , float t) //Funcion para inicializar un vector de 4 elementos
{
xv = x;
yv = y;
zv = z;
tv = t;
}
//Imprimimos el valor del vector
void LPVector4::print()
{
cout << "x: " << xv << " y: " << yv << " z: " << zv << " t: " << tv;
}
//Sobrecarga operador +=
void LPVector4::operator +=(const LPVector4 v)
{
xv += v.xv;
yv += v.yv;
zv += v.zv;
tv += v.tv;
}
Para probar el ejecutable debereis hacerlo desde una consola para que os permita ver el resultado.
Por ahora lo único que os debe interesar es como se ha hecho la sobrecarga del operador += aplicado a los vectores ya que esta sobrecarga es de lo que más se usara en el MathEngine para hacer que el código quede limpio de cara al usuario.
Sin más, aqui os dejo, espero que os lo hayais pasado bien y hayais aprendido
Nos vemos
Etiquetas:
math engine,
operaciones matriz-matriz,
operaciones matriz-vector,
operaciones vector-matriz,
operaciones vector-vector,
sobrecarga de operadores
Math Engine : Capitulo 0. Esquema de un math engine
El artículo original lo podeís encontrar en : aquí
Hola a todos...
Igual que hice con el game engine aquí os dejo un esquema del math engine para que podais entender y acceder más facilmente a cada una de sus partes.
El LP Math Engine tiene tres clases principales
Vector: La clase vector contiene un vector de floats de tamaño arbitrario y todas las funciones asociadas de intereacción entre vector-vector y vector-escalar. http://lordpakus.blogspot.com/2011/08/math-engine-capitulo-2-clase-lpvector.html
Matriz: La clase matriz contiene un matriz de floats de dimensiones arbiarias y todas las funciones asociadas de interacción entre matriz-matriz, matriz-vector y matriz-escalar.http://lordpakus.blogspot.com/2011/08/math-engine-capitulo-3-clase-lpmatrix.html
Serie de datos: La clase serie de datos contiene un vector de datos de longitud arbitraria que se pueden interpretar como una serie estadistica, una discretización de señal, un muestreo de función matemática,etc.. Incorpora funciones de tratamiento de la señal (FFT por ejemplo), de tratamiento de funciones (derivación e integración) y de tratamiento estadístico (medias, varianzas, modelos estadisticos,rectas de regresión) http://lordpakus.blogspot.com/2011/08/math-engine-capitulo-4-clase-lpdata.html
Aparte de estas clases el math engine tiene dos caracteristicas importantes:
-> Sobrecarga de operadores: Es decir, se basa en esta caracteristica de la POO para facilitar el trabajo al programador de aplicaciones matematicas, escondiendo cientos o miles de lineas de código en operciones sencillas de entender conceptualmente http://lordpakus.blogspot.com/2011/08/math-engine-capitulo-1-sobrecarga-de.html
-> Uso de optimizaciones:
- Ensamblador SSE: El ensamblador SSE es un conjunto de operaciones que tienen la mayoria de procesadores actuales que permiten realizar numerosas operaciones en paralelo. Para más información podeis mirar: http://lordpakus.blogspot.com/2011/08/curso-de-programacion-capitulo-7.html
Ejemplo de SSE en la suma de vectores: http://lordpakus.blogspot.com/2011/09/math-engine-capitulo-5-lpvector-con.html
Ejemplo de SSE en la distancia entre vectores: http://lordpakus.blogspot.com/2011/09/math-engine-capitulo-6-vectordistance.html
- Paralelización multicore: WORKING. En breve tendremos tutoriales de paralelización
Espero que os haya gustado y que os haya ayudado a organizar la información
Nos vemos
Hola a todos...
Igual que hice con el game engine aquí os dejo un esquema del math engine para que podais entender y acceder más facilmente a cada una de sus partes.
El LP Math Engine tiene tres clases principales
Vector: La clase vector contiene un vector de floats de tamaño arbitrario y todas las funciones asociadas de intereacción entre vector-vector y vector-escalar. http://lordpakus.blogspot.com/2011/08/math-engine-capitulo-2-clase-lpvector.html
Matriz: La clase matriz contiene un matriz de floats de dimensiones arbiarias y todas las funciones asociadas de interacción entre matriz-matriz, matriz-vector y matriz-escalar.http://lordpakus.blogspot.com/2011/08/math-engine-capitulo-3-clase-lpmatrix.html
Serie de datos: La clase serie de datos contiene un vector de datos de longitud arbitraria que se pueden interpretar como una serie estadistica, una discretización de señal, un muestreo de función matemática,etc.. Incorpora funciones de tratamiento de la señal (FFT por ejemplo), de tratamiento de funciones (derivación e integración) y de tratamiento estadístico (medias, varianzas, modelos estadisticos,rectas de regresión) http://lordpakus.blogspot.com/2011/08/math-engine-capitulo-4-clase-lpdata.html
Aparte de estas clases el math engine tiene dos caracteristicas importantes:
-> Sobrecarga de operadores: Es decir, se basa en esta caracteristica de la POO para facilitar el trabajo al programador de aplicaciones matematicas, escondiendo cientos o miles de lineas de código en operciones sencillas de entender conceptualmente http://lordpakus.blogspot.com/2011/08/math-engine-capitulo-1-sobrecarga-de.html
-> Uso de optimizaciones:
- Ensamblador SSE: El ensamblador SSE es un conjunto de operaciones que tienen la mayoria de procesadores actuales que permiten realizar numerosas operaciones en paralelo. Para más información podeis mirar: http://lordpakus.blogspot.com/2011/08/curso-de-programacion-capitulo-7.html
Ejemplo de SSE en la suma de vectores: http://lordpakus.blogspot.com/2011/09/math-engine-capitulo-5-lpvector-con.html
Ejemplo de SSE en la distancia entre vectores: http://lordpakus.blogspot.com/2011/09/math-engine-capitulo-6-vectordistance.html
- Paralelización multicore: WORKING. En breve tendremos tutoriales de paralelización
Espero que os haya gustado y que os haya ayudado a organizar la información
Nos vemos
Suscribirse a:
Entradas (Atom)