I wrote a simple multiplication function for matrices. Originally my matrices are stored in a single array in format (row, column):
(row0, col0), (row0, col1), (row0, colN), (row1, col0), ... (rowN, col0).
so a 2x2 identity matrix would look like
float eye[4] = {1, 0, 0, 1};
In the actual function I put the 2 array matrices being multiplied into 2d arrays (easy human readable) and then do the multiplication to get the new matrix output. Then convert back to single array. I am only dealing with 3x3, 3x1, and 1x3 matrices. So my code is not be 100% compatible with every matrix possibility. I have global arrays temp3 for my 3x1 and 1x3 matrices, and temp3x3 to hold 3x3 matrices. I use a global bool squared to determine which one the new output will go to.
I get that my code is not perfect, but my question is, why do I get overflow for simple operations? My code is as follows:
#include <math.h>
#include <WString.h>
#define FLOAT sizeof(float)
void multiplyMatrixAxB(const uint8_t rows1, const uint8_t cols1, const uint8_t size1, float matrix1[], const uint8_t rows2, const uint8_t cols2, const uint8_t size2, float matrix2[]);
float K[3]; // 3x1
float dgdn[3]; // 1x3
bool squared = false;
// Temp Variable to hold matrixes
float temp3x3[9];
float temp3[3];
void setup()
{
Serial.begin(115200);
Serial.println(F("Starting Matrix Test Program\n"));
uint8_t i;
K[0] = 1.0;
K[1] = 2.0;
K[2] = 3.0;
dgdn[0] = 0.0;
dgdn[1] = 0.0;
dgdn[2] = 1.0;
Serial.println(F("Matrix K setup as:"));
for(i = 0; i < sizeof(K)/FLOAT; i++)
{
Serial.print(K[i]);
Serial.print(F("\n"));
}
Serial.println(F("Matrix dgdn setup as:"));
for(i = 0; i < sizeof(dgdn)/FLOAT; i++)
{
Serial.print(dgdn[i]);
Serial.print(F("\t"));
}
}
void loop()
{
squared = true;
Serial.println(F("\n\nA 3x1 times a 1x3 should give 3x3"));
multiplyMatrixAxB(3,1, sizeof(K)/FLOAT, K, 1, 3, sizeof(dgdn)/FLOAT, dgdn);
for(i = 0; i < 9; i++)
{
Serial.print(*(temp3x3 + i), 6);
if(!((i+1)%3))
{
Serial.println();
}
else
{
Serial.print(F("\t"));
}
}
Serial.print(F("\n\n"));
Serial.println(F("End of Test"));
while(1){delay(1000);}
}
void multiplyMatrixAxB(const uint8_t rows1, const uint8_t cols1, const uint8_t size1, float matrix1[], const uint8_t rows2, const uint8_t cols2, const uint8_t size2, float matrix2[])
{
if(cols1 != rows2)
{
Serial.println(F("Multiplying Invalid Matrixes. Check ColsA and RowsB"));
while(1){delay(1000);}
}
if(size1 != rows1*cols1)
{
Serial.println(F("rows and columns do not match size of matrix A"));
while(1){delay(1000);}
}
if(size2 != rows2*cols2)
{
Serial.println(F("rows and columns do not match size of matrix B"));
while(1){delay(1000);}
}
uint8_t row, column, k, i;
double mat1[rows1][cols1];
double mat2[rows2][cols2];
double newMat[rows1][cols2];
// place matrix1 into 2d array
row = 0;
for(row = 0; row < rows1; row++)
{
column = 0;
for(column = 0; column < cols1; column++)
{
mat1[row][column] = matrix1[row*cols1 + column];
}
}
// place matrix2 into 2d array
row = 0;
for(row = 0; row < rows2; row++)
{
column = 0;
for(column = 0; column < cols2; column++)
{
mat2[row][column] = matrix2[row*cols2 + column];
}
}
// get new array with multiplied values
row = 0;
for(row = 0; row < rows1; row++)
{
column = 0;
for(column = 0; column < cols2; column++)
{
k = 0;
for(k = 0; k < cols1; k++)
{
newMat[row][column] += mat1[row][k]*mat2[k][column];
}
}
}
row = 0;
i = 0;
// Place new matrix into single array format
for(row = 0; row < rows1; row++)
{
column = 0;
for(column = 0; column < cols2; column++)
{
if(squared)
{
temp3x3[i] = newMat[row][column];
}
else
{
temp3[i] = newMat[row][column];
}
i++;
}
}
}
Hopefully that covered everything. I have more code, but it is all mostly commented out. At worst I missed a variable declaration here, but I will mention that in the IDE it compiles fine and runs. My output looks like this:
Starting Matrix Test Program
Matrix K setup as:
1.00
2.00
3.00
Matrix dgdn setup as:
0.00 0.00 1.00
A 3x1 times a 1x3 should give 3x3
0.000000 0.000000 1.000000
ovf 0.000000 2.000000
0.000000 0.000000 3.000000
End of Test
Where does this ovf come from? I have tried printing out in the multiplication statement in the for loop the index of mat1 x the index of mat2 = "result". This will actually print out exactly what I expect to see and then my output in the main loop will be ok. What is going on? I tried some delays to see if that was the issue between calculations as well. No good.
what I mean is placing in the inner most for loop (k loop):
''' Serial.print(mat1[row][k]); Serial.print(" x "); Serial.print(mat2[k][column]); Serial.print(" + "); ''' And then just outside it,
''' Serial.print(" = "); Serial.println(newMat[row][column]); '''
I will not get any overflow in this scenario.
newMat[row][column] += mat1[row][k]*mat2[k][column];
– Majenko♦ Oct 16 '20 at 15:22