Author Topic: Class Arithmetic  (Read 1428 times)

0 Members and 1 Guest are viewing this topic.

Offline z64555

  • 210
  • Self-proclaimed controls expert
    • Minecraft
    • Steam
So.. yeah. I've got a project going on that I hope to eventually make it open sourced. It's aimed towards making an upgradable auto-pilot for one of them new-fangled multi-rotor drones you keep seeing Youtube movies about.

Previously, I made a really basic version to test the pitch and roll self-stabelization, but it didn't work well, wasn't at all flexible, and has a critical bug in it somewhere that made first-class reservations for the recycle bin.

This time, I'm working in C++ and with a smancy JSF/AV PDF as a guide. I've designed each subsystem to be their own class object, but I've come across a big problem: Vector and Matrix arithmetic. I thought it would be a good idea to declare them as their own classes, as well as make them very dynamic and flexible to have any size they want (so long as it's below the "hardcoded" limit put in the header file).

That is... until I came across the dreaded operator overloading and assignment!  :shaking:

Stuff like A + B is fine, but doing A = B is tricky, and A = b[]; is where I fall get pushed off the boat.

I need a mechanism to be able to initialize the value of Vector and Matrix classes... ideally I'd like to be able to do something like:
Vector A = {0, 1, 2};
Matrix B = { { 0, 1, 2 },
                    { 3, 4, 5 },
                    { 6, 7, 8 } };

And then there's speil about being able to type cast the elements between int, float, and Accum (fixed point)...
Secure the Source, Contain the Code, Protect the Project
chief1983

------------
funtapaz: Hunchon University biologists prove mankind is evolving to new, higher form of life, known as Homopithecus Juche.
z64555: s/J/Do
BotenAlfred: <funtapaz> Hunchon University biologists prove mankind is evolving to new, higher form of life, known as Homopithecus Douche.

 

Offline Polpolion

  • The sizzle, it thinks!
  • 211
    • Minecraft
Assignment should be identical to instantiation with the sole exception that you replace whatever default value you give the data with the values of another of the same type. Or in the literal case, of the type T*.

A = b[] doesn't make sense at all because you're assigning type T to a vector, which you shouldn't be doing. Don't overload the array index operators. If you you absolutely need them, create functions like " T vector::xComp() const", "T vector:: yComp() const", etc, but the idea would be that the user of vector or matrix think of them as a single entity.

You won't need to worry about casting contents to different types if you templatize your class definitions.

The only operators you should be defining are (where a, b are vectors/matrices and c is type T): a=b, a+b, a-b, a*c, a/c +a, -a, a==b, a!=b, a+=b, a-=b, a*=c, a/=c. Every other operator doesn't have a clear meaning for each data type. Eg, does a*b mean dot product or cross product?

I'd also avoid calling it "vector"; it will lead to confusion even if you didn't bring the standard libraries into default scope.

I can't really give you too much more help unless you post some of your code.

 

Offline z64555

  • 210
  • Self-proclaimed controls expert
    • Minecraft
    • Steam
I'm considering scrapping the Vector class once I get the Matrix class up to operational. However, that poses some problems with vector-only algebra such as dot product and cross product. I could otherwise call it a math_vector...
Code: [Select]
#ifndef _matrix_h
#define _matrix_h
// ********************************************************************************************************************
// Matrix and Vector Data Types and Objects Declaration File
// ********************************************************************************************************************
// ToDo:
//  I need a method that can define the value of each element so I can initialize the internal array.
//    I can make the *element and **element public, but that would be dangerous because outside methods could modify it




// Limits
//   These are primarily used for error checking, to prevent the entire stack from becoming one big vector

const int vector_size_limit = 4;
const int matrix_row_limit = 4;
const int matrix_col_limit = 4;

// Vectors

// ***************************** class Vector ****************************** //
// Description:                                                              //
//   Single column or row matrix. Commonly used for geometric points, rays,  //
//   and simple physics data.                                                //
// ************************************************************************* //
class Vector
{
  public:
    void Vector( void );  // Default constructor. Assumes a vector size of 3 elements
    void Vector( int );   // Constructor. Defines a vector with N elements
    void ~Vector( void ); // Destructor. Since the vector's actual sze is dynamic, a destructor is absolutely necassary
  private:
    int *element;         // Points to the first element of a dynamic array
    int size;
};



// ***************************** class Matrix ****************************** //
// Description:                                                              //
//   Two-dimensional Matrix (M by N).                                        //
// ************************************************************************* //
class Matrix
{
  public:
    void Matrix( void );      // Default Constructor. Assumes a 3x3 matrix.
    void Matrix( int, int );  // Constructor. Requires input of Rows and Columns   
    void ~Matrix( void );     // Destructor. Absolutely necassary since this has dynamic data
  private:
    int **element;            // Careful! This is a pointer to an array of pointers.
    int row_size;
    int col_size;
};
#endif // _matrix_hpp


Code: [Select]
//matrix.cpp
// ***************************************************************************************************************** //
// Matrix and Vector Data Types and Objects Definition File
// ***************************************************************************************************************** //
// To Do:
//   Find a method for error handling.
//     Currently there's no error checking, in particular there's nothing checking the size of the Vector and Matrix
//   constructors... meaning a run-time error will occur if the incoming value is larger than the defined size limits.
#include "matrix.hpp"

///////////////////////////////////////////////////////////////////////////////////////////////////
///                                       Vector methods                                        ///
///////////////////////////////////////////////////////////////////////////////////////////////////



// ************************ Vector.Vector( void ) ************************** //
// Description:                                                              //
//   Default Constructor. Assumes a vector size of 3 elements                //
// INPUT:                                                                    //
//   None                                                                    //
// OUTPUT:                                                                   //
//   None                                                                    //
// ************************************************************************* //
void Vector::Vector( void )
{
     size = 3;
     element = new int[ size ];   // Allocate RAM for a dynamic array
     
     for(int i = size; i > 0; i-- )
     {
      element[ i ] = 0;
     }
}



// ************************ Vector.Vector( int ) *************************** //
// Description:                                                              //
//   Constructor. Requires input of # of elements.                           //
//   Maximum is defined in matrix.hpp                                        //
// INPUT:                                                                    //
//   int N;   // Number of elements in the vector type                       //
// OUTPUT:                                                                   //
//   None                                                                    //
// ************************************************************************* //
void Vector::Vector( int N )
{
  size = N;   // WARNING: N can be much greater than the limit! The program won't know this is erroneous!
 
  element = new int[ size ];    // Allocate RAM for a dynamic array

// Initialize the array to a value of 0 
  for(int i = size; i > 0; i-- )
  {
    element[ i ] = 0;
  }
}



// *********************** Vector.~Vector( void ) ************************** //
// Description:                                                              //
//   Destructor. Since the Vector datatype uses a dynamic array, this is     //
//   absolutely needed.                                                      //
// INPUT:                                                                    //
//   None                                                                    //
// OUTPUT:                                                                   //
//   None                                                                    //
// ************************************************************************* //
void Vector::~Vector( void )
{
  delete [] element;  // De-Allocate the RAM used by the array
  element = 0;        // Nullify the pointer, just in case
}

///////////////////////////////////////////////////////////////////////////////////////////////////
///                                       Matrix methods                                        ///
///////////////////////////////////////////////////////////////////////////////////////////////////



// *********************** Matrix.Matrix( void ) *************************** //
// Description:                                                              //
//   Default Constructor. Assumes a 3x3 Matrix                               //
// INPUT:                                                                    //
//   None                                                                    //
// OUTPUT:                                                                   //
//   None                                                                    //
// ************************************************************************* //
void Matrix::Matrix( void )
{
  row_size = 3;
  col_size = 3;
 
  // First, creates a row index array. The row's point to columner arrays
  element = new int*[ row_size ];
 
  // Then, creates the column vectors. Each columner array has the same number of elements
  for( int i; i < row_size; i++ )
  {
    element[ i ] = new int[ col_size ];
  }
 
  // Lastly, initializes all elements to a value of 0. Note the use of notation.
  for( int i; i < row_size; i++)
  {
    for( int j; j < col_size; j++ )
    {
      element[ i ][ j ] = 0;
    }
  }
}



// ********************* Matrix.Matrix( int, int ) ************************* //
// Description:                                                              //
//   Constructor. Takes input of 2 int's for the number of rows and columns  //
// INPUT:                                                                    //
//   int number_of_rows;                                                     //
//   int number_of_columns;                                                  //
// OUTPUT:                                                                   //
//   None                                                                    //
// ************************************************************************* //
void Matrix::Matrix( int number_of_rows,
                     int number_of_columns )
{
  row_size = number_of_rows;
  col_size = number_of_columns;
 
  // First, creates a row index array. The row's point to columner arrays
  element = new int*[ row_size ];
 
  // Then, creates the column vectors. Each columner array has the same number of elements
  for( int i; i < row_size; i++ )
  {
    element[ i ] = new int[ col_size ];
  }
 
  // Lastly, initializes all elements to a value of 0. Note the use of notation.
  for( int i; i < row_size; i++ )
  {
    for( int j; j < col_size; j++ )
    {
      element[ i ][ j ] = 0;
    }
  } 
}



// *********************** Matrix.~Matrix( void ) ************************** //
// Description:                                                              //
//   Destructor. Deallocates memory taken from the stack.                    //
// INPUT:                                                                    //
//   None                                                                    //
// OUTPUT:                                                                   //
//   None                                                                    //
// ************************************************************************* //
void Matrix::~Matrix( void )
{
  // Deallocation is the reverse of allocation, so we first start with the rightmost column and work left
  for( int j = col_size; j > 0; j-- )
  {
    delete [] element[ j ];
  } 
 
  // Next, deallocate the memory used for the row index
  delete [] element;
 
  // Finally, nullify the pointer
  element = 0; 
}



As you can tell, I'm a big fan of adequate documentation.  :nod:

(It's mostly because I have a poor memory, Lol.)
Secure the Source, Contain the Code, Protect the Project
chief1983

------------
funtapaz: Hunchon University biologists prove mankind is evolving to new, higher form of life, known as Homopithecus Juche.
z64555: s/J/Do
BotenAlfred: <funtapaz> Hunchon University biologists prove mankind is evolving to new, higher form of life, known as Homopithecus Douche.

 

Offline Polpolion

  • The sizzle, it thinks!
  • 211
    • Minecraft
I was going to make post but then I accidentally hit the back button, hopefully I'll get around to it later. :nervous:

 

Offline z64555

  • 210
  • Self-proclaimed controls expert
    • Minecraft
    • Steam
Hate it when that happens.  :rolleyes:

Brushed up a bit more on C++, but couldn't really find any pointers aside from "use & to pass by reference" and "use const at the end of a function declaration that doesn't modify the class/ADT's members."
Secure the Source, Contain the Code, Protect the Project
chief1983

------------
funtapaz: Hunchon University biologists prove mankind is evolving to new, higher form of life, known as Homopithecus Juche.
z64555: s/J/Do
BotenAlfred: <funtapaz> Hunchon University biologists prove mankind is evolving to new, higher form of life, known as Homopithecus Douche.

 

Offline CP5670

  • Dr. Evil
  • Global Moderator
  • 212
  • 142857
Look into the NIST TNT package instead of making your own classes. I use that and it takes care of a lot of the basic grunt work with matrix operations.

 

Offline The E

  • He's Ebeneezer Goode
  • Global Moderator
  • 213
  • Nothing personal, just tech support.
    • Steam
    • Twitter
Yeah, there are a few vector/matrix math classes available, like AMD's LibM.
Let there be light
Let there be moon
Let there be stars and let there be you
Let there be monsters and let there be pain
Let us begin to feel again
--Devin Townsend, Genesis

 

Offline z64555

  • 210
  • Self-proclaimed controls expert
    • Minecraft
    • Steam
Thanks, but this is for an embedded system... so I need static libraries that arn't optimized for any particular architecture.

Look into the NIST TNT package instead of making your own classes. I use that and it takes care of a lot of the basic grunt work with matrix operations.

That looks like it was made for standard PC's, so if I where to be able to use it for my HCS12 I would have to heavily modify it. I could learn a trick or two from it, though... thanks!
Secure the Source, Contain the Code, Protect the Project
chief1983

------------
funtapaz: Hunchon University biologists prove mankind is evolving to new, higher form of life, known as Homopithecus Juche.
z64555: s/J/Do
BotenAlfred: <funtapaz> Hunchon University biologists prove mankind is evolving to new, higher form of life, known as Homopithecus Douche.