I have found on the internet (here and here), that the inheritance doesn't affect the performance of the class. I have become curious about that as I have been writing a matrices module for a render engine, and the speed of this module is very important for me.
After I have written:
Base: general matrix class
Derived from the base: square implementation
Derived from derived: 3-dim and 4-dim implementations of the square matrix
I decided to test them and faced performance issues with instantiation
And so the main questions are:
What's the reason of these performance issues in my case and why may they happen in general?
Should I forget about inheritance in such cases?
This is how these classes look like in general:
template <class t>
class Matrix
{
protected:
union {
struct
{
unsigned int w, h;
};
struct
{
unsigned int n, m;
};
};
/** Changes flow of accessing `v` array members */
bool transposed;
/** Matrix values array */
t* v;
public:
~Matrix() {
delete[] v;
};
Matrix() : v{}, transposed(false) {};
// Copy
Matrix(const Matrix<t>& m) : w(m.w), h(m.h), transposed(m.transposed) {
v = new t[m.w * m.h];
for (unsigned i = 0; i < m.g_length(); i++)
v[i] = m.g_v()[i];
};
// Constructor from array
Matrix(unsigned _w, unsigned _h, t _v[], bool _transposed = false) : w(_w), h(_h), transposed(_transposed) {
v = new t[_w * _h];
for (unsigned i = 0; i < _w * _h; i++)
v[i] = _v[i];
};
/** Gets matrix array */
inline t* g_v() const { return v; }
/** Gets matrix values array size */
inline unsigned g_length() const { return w * h; }
// Other constructors, operators, and methods.
}
template<class t>
class SquareMatrix : public Matrix<t> {
public:
SquareMatrix() : Matrix<t>() {};
SquareMatrix(const Matrix<t>& m) : Matrix<t>(m) {};
SquareMatrix(unsigned _s, t _v[], bool _transpose) : Matrix<t>(_s, _s, _v, _transpose) {};
// Others...
}
template<class t>
class Matrix4 : public SquareMatrix<t> {
public:
Matrix4() : SquareMatrix<t>() {};
Matrix4(const Matrix<t>& m) : SquareMatrix<t>(m) {}
Matrix4(t _v[16], bool _transpose) : SquareMatrix<t>(4, _v, _transpose) {};
// Others...
}
To conduct tests I used this
void test(std::ofstream& f, char delim, std::function<void(void)> callback) {
auto t1 = std::chrono::high_resolution_clock::now();
callback();
auto t2 = std::chrono::high_resolution_clock::now();
f << std::chrono::duration_cast<std::chrono::microseconds>(t2 - t1).count() << delim;
//std::cout << "test took " << std::chrono::duration_cast<std::chrono::microseconds>(t2 - t1).count() << " microseconds\n";
}
Performance problems
With single class initialization, there're no problems - it goes under 5 microseconds almost every time for every class.
But then I decided to scale up the number of initializations and their several troubles occurred
I ran every test 100 times, with arrays of length 500
1. Class initialization with the default constructor
Raw results
I just tested the initialization of arrays
The results were (avg time in microseconds):
Matrix 25.19
SquareMatrix 40.37 (37.60% loss)
Matrix4 58.06 (30.47% loss from SquareMatrix)
And here we can already see a huge difference
Here's the code
int main(int argc, char** argv)
{
std::ofstream f("test.csv");
f << "Matrix\t" << "SquareMatrix\t" << "Matrix4\n";
for (int k = 0; k < 100; k++) {
test(f, '\t', []() {
Matrix<long double>* a = new Matrix<long double>[500];
});
test(f, '\t', []() {
SquareMatrix<long double>* a = new SquareMatrix<long double>[500];
});
test(f, '\n', []() {
Matrix4<long double>* a = new Matrix4<long double>[500];
});
}
f.close();
return 0;
}
2. Class initialization with default constructor and filling
Raw results
Tested the initialization of arrays of class instances and filling them after with custom matrices
The results (avg time in microseconds):
Matrix 402.8
SquareMatrix 475 (15.20% loss)
Matrix4 593.86 (20.01% loss from SquareMatrix)
Code
int main(int argc, char** argv)
{
long double arr[16] = {
1, 2, 3, 4,
5, 6, 7, 8,
9, 10, 11, 12,
13, 14,15,16
};
std::ofstream f("test.csv");
f << "Matrix\t" << "SquareMatrix\t" << "Matrix4\n";
for (int k = 0; k < 100; k++) {
test(f, '\t', [&arr]() {
Matrix<long double>* a = new Matrix<long double>[500];
for (int i = 0; i < 500; i++)
a[i] = Matrix<long double>(4, 4, arr);
});
test(f, '\t', [&arr]() {
SquareMatrix<long double>* a = new SquareMatrix<long double>[500];
for (int i = 0; i < 500; i++)
a[i] = SquareMatrix<long double>(4, arr);
});
test(f, '\n', [&arr]() {
Matrix4<long double>* a = new Matrix4<long double>[500];
for (int i = 0; i < 500; i++)
a[i] = Matrix4<long double>(arr);
});
}
f.close();
return 0;
}
3. Filling vector with class instances
Raw results
Pushed back custom matrices to vector
The results (avg time in microseconds):
Matrix 4498.1
SquareMatrix 4693.93 (4.17% loss)
Matrix4 4960.12 (5.37% loss from its SquareMatrix)
Code
int main(int argc, char** argv)
{
long double arr[16] = {
1, 2, 3, 4,
5, 6, 7, 8,
9, 10, 11, 12,
13, 14,15,16
};
std::ofstream f("test.csv");
f << "Matrix\t" << "SquareMatrix\t" << "Matrix4\n";
for (int k = 0; k < 100; k++) {
test(f, '\t', [&arr]() {
std::vector<Matrix<long double>> a = std::vector<Matrix<long double>>();
for (int i = 0; i < 500; i++)
a.push_back(Matrix<long double>(4, 4, arr));
});
test(f, '\t', [&arr]() {
std::vector<SquareMatrix<long double>> a = std::vector<SquareMatrix<long double>>();
for (int i = 0; i < 500; i++)
a.push_back(SquareMatrix<long double>(4, arr));
});
test(f, '\n', [&arr]() {
std::vector<Matrix4<long double>> a = std::vector<Matrix4<long double>>();
for (int i = 0; i < 500; i++)
a.push_back(Matrix4<long double>(arr));
});
}
f.close();
return 0;
}
If you need all the source code, you can look here into matrix.h and matrix.cpp
Does inheritance really not affect performance?
Yes. Inheritance won't affect runtime performance as long as virtual method isn't involved. (Cuz only then will you have to deduce the type at runtime and call corresponding virtual method override). In fact, if you have a sight into lower details, you will know that c++ inheritance is mostly just static things, that is, done at compilation time.
What's the reason of these performance issues in my case and why may they happen in general?
It seems these work well when optimization is enabled?
Should I forget about inheritance in such cases?
The only thing you need to do in such performance-sensitive cases is to avoid virtual method.
Something not related to this question. I have read your code. Perhaps it will be better to implement your templates in header file?
Related
I have a set of Arguments defined as struct for a set of operations (mean, minmax etc.)
struct Arguments {
double *data;
int num_data;
Arguments(double *data, int num_data) : data(data), num_data(num_data) {}
};
struct MeanOperationArguments: Arguments {
MeanOperationArguments(double *data, int num_data) : Arguments(data, num_data) {}
};
struct MinmaxOperationArguments: Arguments {
bool is_min_op;
MinmaxOperationArguments(double *data, int num_data, bool is_min_op) : is_min_op(is_min_op), Arguments(data, num_data) {}
};
I need to define an Operation class as follows:
class Operation {
public:
virtual void execute() = 0;
}
class MeanOperation: public Operation {}
// an operation that can be told to display either the minimum or the maximum.
class MinmaxOperation: public Operation {}
Also, I have an operation factory with returns the specifc operation object instance based on the type of operation:
class OperationFactory {
public:
Operation *get(OP_TYPE t, Arguments *args) {
switch(t) {
case MEAN:
return new MeanOperation(args);
case MINMAX:
return args->is_min_op ? // ERROR: Because struct downcasts to `Arguments`
new MinOperation(args):
new MaxOperation(args);
}
}
};
I need to be able to run my operation based on the type of argument struct like this:
int main() {
double data[] = { 1, 2, 3, 4 };
int num_data = 4;
OperationFactory operations;
Arguments *mean_args = new MeanOperationArguments(data, num_data);
Operation *mean_op = operations.get(MEAN, mean_args);
mean_op->execute();
Arguments *min_args = new MinmaxOperationArguments(data, num_data, true);
Operation *min_op = operations.get(MINMAX, min_args);
min_op->execute();
return 0;
}
How can I initialize my operation with require arguments based on the use case?
If you put a single virtual method in the base class, preferably the destructor, you could use dynamic_cast to convert the pointer to an instance of the derived class. If the conversion fails you have your answer, if it succeeds you can call any of the derived class methods on it.
There are multiple things I have to address. First, avoid structure parent / child relationships. It adds unnecessary dependencies. Look at structures like custom data structures. Data is data at the end of the day. It only has meaning when you interpret it. Going off that logic, your argument structure could be simplified as an array with an unsigned integer that tells how long is that array (similar to a vector, so maybe you could look into using a vector instead of a struct). Going off this logic, the best approach you can take is having multiple functions with different names that take in the same arguments but return different result based on whatever it is that you want it to do. Here is what I am talking about:
#include <iostream>
struct DataSet {
public:
double* data;
int size;
DataSet(double* data, unsigned int size) {
this->data = new double[size];
this->size = size;
for (unsigned int i = 0; i < size; i++)
this->data[i] = data[i];
}
};
double mean(const DataSet& dataSet) {
double mean = 0;
for (unsigned int i = 0; i < dataSet.size; i++)
mean += dataSet.data[i];
mean = mean / dataSet.size;
return mean;
}
double min(const DataSet& dataSet) {
double min = dataSet.data[0];
for (unsigned int i = 1; i < dataSet.size; i++)
if (dataSet.data[i] < min)
min = dataSet.data[i];
return min;
}
double max(const DataSet& dataSet) {
double min = dataSet.data[0];
for (unsigned int i = 1; i < dataSet.size; i++)
if (dataSet.data[i] > min)
min = dataSet.data[i];
return min;
}
int main() {
double data[5] = { 1, 2, 3, 4, 5 };
unsigned int size = 5;
DataSet dataSet = DataSet(data, size);
double result = 0;
result = mean(dataSet);
std::cout << "Mean: " << result << std::endl;
result = min(dataSet);
std::cout << "Min: " << result << std::endl;
result = max(dataSet);
std::cout << "Max: " << result << std::endl;
}
I included everything in one .cpp file for convenience. If you are trying to implement a system, I would suggest making an enum class, store an enum value that represents what operation the user wants to perform, make a switch statement that points to these functions.
Note, be careful with passing pointers around because you might end up with memory leaks. If you notice in the code implementation, I am doing a deep copy, therefore passing memory ownership to the structure to DataSet.
Edit for better system design fit
#include <iostream>
class DataSet {
public:
double* data;
int size;
DataSet() {
data = nullptr;
size = 0;
}
DataSet(double* data, unsigned int size) {
this->data = new double[size];
this->size = size;
for (unsigned int i = 0; i < size; i++)
this->data[i] = data[i];
}
~DataSet() {
if (data != nullptr)
delete(data);
}
};
class Operation {
protected:
DataSet dataSet;
public:
Operation(double* data, unsigned int size) : dataSet(data, size) {
}
virtual double execute() = 0;
};
class Mean : public Operation {
public:
Mean(double* data, unsigned int size) : Operation(data, size) {
}
~Mean() {
}
double execute() {
double mean = 0;
for (unsigned int i = 0; i < dataSet.size; i++)
mean += dataSet.data[i];
mean = mean / dataSet.size;
return mean;
}
};
class MinMax : public Operation {
public:
bool useMin;
MinMax(double* data, unsigned int size) : useMin(true), Operation(data, size) {
}
~MinMax() {
}
double execute() {
if (useMin) {
double min = dataSet.data[0];
for (unsigned int i = 1; i < dataSet.size; i++)
if (dataSet.data[i] < min)
min = dataSet.data[i];
return min;
}
else {
double min = dataSet.data[0];
for (unsigned int i = 1; i < dataSet.size; i++)
if (dataSet.data[i] > min)
min = dataSet.data[i];
return min;
}
}
};
int main() {
double data[5] = { 1, 2, 3, 4, 5 };
unsigned int size = 5;
DataSet dataSet = DataSet(data, size);
double result = 0;
Mean mean = Mean(data, size);
std::cout << "Mean: " << mean.execute() << std::endl;
MinMax minMax = MinMax(data, size);
std::cout << "MinMax: " << minMax.execute() << std::endl;
minMax.useMin = false;
std::cout << "MinMax: " << minMax.execute() << std::endl;
}
For better fit your system, I worked out a better solution. I still got rid of your struct hierarchy but kept the hierarchy in your classes. MinMax will return min or max depending on the useMin boolean value. You said you are printing it in the comments, so you would just have to change it to void and instead of returning the value, just print it. I hope this points you into a better direction.
Something like:
case MINMAX:
return dynamic_cast<MinmaxOperationArguments*>(args)->is_min_op ?
new MinOperation(args):
new MaxOperation(args);
}
Note, that result of cast should be checked before use or it may crash in case of incorrect argument.
RTTI has to be enabled.
The question
I am writing a software in c++17 for which performances are absolutely critical. I would like available in a few key functions constants in arrays themselves in arrays. It matters that both these array are accessible by a integer value in such (or similar) manner :
int main()
{
for (int i = 0; i < size_of_A ; i++)
{
for (int j = 0; j < size_of_B_in_A(i); j++)
{
std::cout << A[i][j];
}
}
}
This would be the kind of array we would like to create assuming some function int f(a, b)
A
{
// B1
{
f(1, 1),
f(1, 2),
f(1, 3),
...
f(1, large number)
},
// B2
{
f(2, 1),
...
f(2, some other large number)
},
... etc
}
The Twist
Each inner array may be of different size which we have will stored elsewhere, we have to find the size at compile time. I would rather not use std::vector for they are assumed
slightly slower
.
Also an I suppose a std::vector would be stored on the heap which would be a performance issue in my specific case.
Furthermore,
std::vector cannot be used as "inline constexpr"
which would be necessary as I expect to have a large amount of value in those array never going to change. I am fine with recompiling all those values each time but not keeping them in an external file by policy as I am to follow a strict coding style.
What I Have Tried
brace initializer
// A.hh
#pragma once
#include <iostream>
void test1();
void test2();
inline constexpr int B1[1] = {1};
inline constexpr int B2[2] = {2, 3};
inline constexpr int B3[3] = {4, 5, 6};
inline constexpr const int *A[3] = {B1, B2, B3};
// main.cc
#include "A.hh"
int main()
{
std::cout << "values : ";
for (int i = 0; i < 3; i++)
{
for (int j = 0; j <= i; j++)
{
std::cout << A[i][j];
}
}
std::cout << "\n\naddress test : \n";
std::cout << &A << '\n';
test1();
test2();
}
// somewhere.cc
#include "A.hh"
void test1()
{
std::cout << &A << '\n';
}
// elsewhere.cc
#include "A.hh"
void test2()
{
std::cout << &A << '\n';
}
which prints :
./a.out
values : 123456
address test :
0x56180505cd70
0x56180505cd70
0x56180505cd70
Therefore A has not been copied in main.cc, somewhere.cc and elsewhere.cc which is good. I would like to go further and be able to create a huge amount of values.
struct with constexpr
using tips found
here
, I do this to be able to perform operations during array construction.
// B.hh
#pragma once
#include <iostream>
template <int N>
struct X
{
int arr[N];
constexpr X(): arr()
{
for (int i = 0; i < N; i++)
{
arr[i] = i % 3;
}
}
};
inline constexpr auto A = X<500>();
// main.cc
#include "B.hh"
int main()
{
for (int i = 0; i < 500; i++)
{
std::cout << A.arr[i];
}
}
Which unsuspectingly prints out
012012 (etc)...
Finally an array of array
And this where I am stuck
#pragma once
#include <iostream>
template <int N>
struct sub_array
{
int arr[N];
constexpr sub_array() : arr()
{
for (int i = 0; i < N; i++)
{
arr[i] = i;
}
}
};
struct array
{
sub_array</*what here ?*/> arr[100];
constexpr array() : arr()
{
for (int i = 0; i < 100; i++)
{
int size = i * 2; // a very large number
// the value of 'size' is not usable in a constant expression
//
// I see why it is, but I can't think of any other way
arr[i] = sub_array<size>;
}
}
};
inline constexpr array A = array();
How can I build such kind of array ?
Thank you for your time and consideration.
Just use std::array<std::span<int>, N>, which is a fixed size array of spans of different sizes. To generate this, use an std::index_sequence
Header:
constexpr std::size_t size_of_A = 500;
extern const std::array<const std::span<const int>, size_of_A>& A;
Implementation:
constexpr std::size_t size_of_B_in_A(std::size_t i) { return i%10+1;}
constexpr int f(std::size_t i, std::size_t j) {return static_cast<int>(i%(j+1));}
template <int I, int N>
struct B
{
std::array<int,N> arr;
explicit constexpr B()
{
for (int j = 0; j < N; j++)
arr[j] = f(I, j);
}
constexpr operator const std::span<const int>() const {return {arr};}
};
template<class index_sequence>
class BGen;
template<std::size_t... I>
struct BGen<std::integer_sequence<std::size_t,I...>> {
static constexpr std::tuple<B<I, size_of_B_in_A(I)>...> bs{};
static constexpr std::array<const std::span<const int>, sizeof...(I)> A {std::get<I>(bs)...};
};
const std::array<const std::span<const int>, size_of_A>& A
= BGen<decltype(std::make_index_sequence<size_of_A>{})>::A;
Usage:
int main()
{
for (unsigned i = 0; i < A.size() ; i++)
{
for (unsigned j = 0; j < A[i].size(); j++)
{
std::cout << A[i][j];
}
}
}
http://coliru.stacked-crooked.com/a/d68b0e9fd6142f86
However, stepping back: This solution is NOT the normal way to go about solving this problem. Since it's all constexpr, this is all data not code. Ergo, the most performant solution is two programs. One generates the data and saves it to a file that ships with (inside?) your program. Then your program simply maps the file into memory, and uses the data directly.
Here's a way of implementing a constexpr jagged array which can be initialized without intermediates. It does require listing the row sizes as template arguments, but there are ways to make that easier too, depending on how the row sizes can be known at compile time.
#include <tuple>
#include <array>
#include <utility>
template <std::size_t ...Sizes>
struct jagged_array
{
const std::tuple<std::array<int,Sizes>...> data;
static constexpr std::size_t num_rows = sizeof...(Sizes);
static constexpr std::size_t length[num_rows]{Sizes...};
int const* const row_ptr[num_rows];
template <std::size_t ...I>
constexpr jagged_array(std::index_sequence<I...>,
const std::array<int, Sizes>& ...arrs)
: data{arrs...}, row_ptr{&std::get<I>(data)[0]...} {}
constexpr jagged_array(const std::array<int, Sizes>& ...arrs)
: jagged_array(std::make_index_sequence<num_rows>{}, arrs...)
{}
constexpr int const* operator[](std::size_t idx) const
{ return row_ptr[idx]; }
};
inline constexpr jagged_array<2,4> jarr = {{2,3}, {4,5,6,7}};
I have a class like this:
#define MYNUM 4
class myClass {
private:
char myData[MYNUM];
public:
myClass(char myArr[MYNUM]) {
for (int i = 0; i < MYNUM; i++) myData[i] = myArr[i];
}
};
I want to initialize an array of myClass objects like so:
static myClass obj_arr[5] = { {1, 1, 1, 1}, {2, 2, 2, 2}, {3, 3, 3, 3}, {4, 4, 4, 4}, {5, 5, 5, 5} };
But I am getting error: too many initializers. Is there a way that I can initialize the obj_arr array in the way that I want?
First, in your existing constructor, the char myArr[MYNUM] parameter is the same as passing char myArr[] which is the same as char *myArr. IOW, the constructor takes a simple pointer as input, so it does not actually ensure the input array is really MYNUM elements. To do that, you need to pass the array by reference instead of by pointer.
As for the kind of initialization that you want, add a constructor that takes a std::initializer_list as input.
Try this:
#include <initializer_list>
class myClass {
private:
char myData[MYNUM];
public:
myClass(char (&myArr)[MYNUM]) {
for (size_t i = 0; i < MYNUM; ++i) myData[i] = myArr[i];
}
myClass(std::initializer_list<char> myList) {
for (size_t i = 0; (i < myList.size()) && (i < MYNUM); ++i) myData[i] = myList.begin()[i];
for (size_t i = myList.size(); i < MYNUM; ++i) myData[i] = 0;
}
};
Live Demo
You cannot pass an array as a function parameter like that. You do have a few options to get the initialization syntax you want though:
Make myClass an aggregate by making myData public:
constexpr size_t MYNUM = 4;
class myClass {
public:
char myData[MYNUM];
};
Live Demo
C++ allows the members of aggregate classes to be initialized directly using brace-initialization. This is the path that the standard library's std::array template uses. This obviously won't work if your class has other data members that you want to keep private.
Use a std::initializer_list<char>
constexpr size_t MYNUM = 4;
class myClass {
private:
char myData[MYNUM];
public:
myClass(std::initializer_list<char> myList)
{
// Initialize first elements of myData with the parameters passed
for (size_t i = 0; i < std::min(myList.size(), MYNUM); ++i) {
myData[i] = myList.begin()[i];
}
// Fill out any missing elements with 0
for (size_t i = myList.size(); i < MYNUM; ++i) {
myData[i] = 0;
}
}
};
Live Demo
This will work to initialize a private class member, and it supports brace-initialization. It even zero-fills trailing elements if not provided like the default way C++ treats brace-initializing arrays. Its only drawback is that it won't produce an error if more elements are given than myClass wants.
Templates
constexpr size_t MYNUM = 4;
class myClass {
private:
char myData[MYNUM];
public:
template <typename... Ts>
myClass(Ts... args)
: myData{static_cast<char>(args)...}
{
}
};
Live Demo
This is the closest you can get to the aggregate initialization approach with a private class member. Instead of accepting a container to use to initialize myData, myClass's constructor accepts a variable number of parameters, and uses them to directly initialize myData. This will zero-initialize trailing elements if less than MYNUM parameters are provided and will produce a compile-time error if more than MYNUM parameters are provided.
Utilized nested for loop to assign elements of array (which was passed by const. ref.) to member variable.
#include <iostream>
#define MYNUM 4
class myClass {
private:
int myData[MYNUM][MYNUM];
public:
myClass();
myClass(const int (&myArr)[MYNUM][MYNUM]){
for(int i = 0; i < MYNUM; i++){
for(int j = 0; j < MYNUM; j++){
myData[i][j] = myArr[i][j];
}
}
}
void printmyData(){
for(int i = 0; i < MYNUM; i++){
std::cout << "{";
for(int j = 0; j < MYNUM; j++){
std::cout << myData[i][j];
}
if (i < MYNUM){
std::cout << "}";
if (i < MYNUM-1){
std::cout << ",";
std::cout << " ";
}
}
}
std::cout << std::endl;
}
};
int main () {
int mainArr[MYNUM][MYNUM] = {{1, 2, 3, 4}, {5, 6, 7, 8}, {4, 3, 2, 1}, {8, 7, 6, 5}};
myClass obj = myClass(mainArr);
obj.printmyData();
return 0;
}
I am trying to rotate a vector of Vectors of chars.
I made a 2d vector matrix setup. right now the matrix takes input from a file, I use vector.push_back(c) to add the characters to the vvc;
An example of the vvc array would be something like this
aaaaa
azzza
azaza
azzza
azaaa
azaaa
azaaa
aaaaa
I have the vvc setup, But I am trying to rotate it 90 degrees. I rotated it 90 degrees counter clockwise but I need to rotate it 90 degrees clockwise.
as of right now my code does this
90 counter clock
aaaaaaaa
azzzzzza
azazaaaa
azzzaaaa
aaaaaaaa
and it does it through this loop;
cout <<"\n90 counter clock"<<endl;
for (size_t colNo = 0; colNo < kvsize2; colNo++)
{
for (const auto &row : twovector)
{
char colVal = row.at(colNo);
cout << colVal;
}
cout << endl;
}
I am just learning about vectors, and the range for. Trying to do a decrement loop almost works, but keeps throwing me into a segfault.
"Solved"
I was using
twovector.push_back(temp);
using
twovector.insert(twovector.begin(),temp);
gives me
90 counter clock
aaaaaaaa
azzzzzza
aaaazaza
aaaazzza
aaaaaaaa
Tackling a specific part of the question :
If anyone has any tips or suggestions on how to rotate a M*N 2d vector array
C++ is good at segregating algorithms from data.
Kindly note that the answer is a bit lengthy and has been written with the objective of a tutorial.
Lets begin !!
We want 3 features from our rotate_2d_matrix_clockwise algorithm :
It should work with all datatypes, i.e. int, char, double or any user defined type.
It should work with different types of containers, such as std::array and std::vector
It should be chain-able, i.e. user should be able to call rotate_2d_matrix_clockwise on the result returned by rotate_2d_matrix_clockwise, to achieve 2 times rotation.
Once we are clear with our requirements, we can draft some use-cases for our algorithm.
std::vector<std::vector<char>> data = { {'a', 'b', 'c', 'd'},
{'e', 'f', 'g', 'h'},
{'i', 'j', 'k', 'l'} };
rotate_2d_matrix_clockwise(data); // rotating 2d-matrix of vector<char>
std::array<std::array<int, 4>, 3> data2 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
// rotating 2d-matrix of array<int>, twice
rotate_2d_matrix_clockwise(rotate_2d_matrix_clockwise(data2)));
So lets use some templates to create a generic 2d-clockwise-rotate function.
Our rotate_2d_matrix_clockwise will :
take the original_matrix and return a new rotated_matrix.
automatically deduce the dimensions i.e. M x N of the container passed to it.
create the rotated_matrix and pass it to a helper function rotate_2d_matrix_clockwise_impl where the actual work would be done.
So how will the implementation of rotate_2d_matrix_clockwise for std::array look ?
template<typename T, size_t M, size_t N>
auto rotate_2d_matrix_clockwise(std::array<std::array<T, M>, N> const & original_matrix)
-> std::array<std::array<T, N>, M>
{
std::array<std::array<T, N>, M> rotated_matrix;
rotate_2d_matrix_clockwise_impl(original_matrix, rotated_matrix, M, N); // rotate
return rotated_matrix;
}
Neat and precise.
The implementation of rotate_2d_matrix_clockwise for std::vector is a bit messy, though.
template<typename Matrix2D>
auto rotate_2d_matrix_clockwise(Matrix2D const & original_matrix) -> Matrix2D
{
int const M = original_matrix[0].size(); // deduce M and N
int const N = original_matrix.size();
Matrix2D rotated_matrix; // vector has no form, hence we have to resize it for `N x M`
rotated_matrix.resize(M);
for (auto x = 0; x < M; ++x) {
rotated_matrix[x].resize(N);
}
rotate_2d_matrix_clockwise_impl(original_matrix, rotated_matrix, M, N); // rotate
return rotated_matrix;
}
Now lets look at how the actual rotation algorithm rotate_2d_matrix_clockwise_impl would look.
It should be noted, that the algorithm is independent of the container and/or the data contained. It just focuses on rotating.
template<typename OriginalMatrix2D, typename RotatedMatrix2D>
void rotate_2d_matrix_clockwise_impl(OriginalMatrix2D const & original_matrix,
RotatedMatrix2D & rotated_matrix,
int const M,
int const N)
{
for (auto x = 0; x < N; ++x) {
for (auto y = 0; y < M; ++y) {
// Source : https://stackoverflow.com/questions/4780119/2d-euclidean-vector-rotations
rotated_matrix[y][-x -1 +N] = original_matrix[x][y];
}
}
}
Here is a full working example compiled in C++11.
#include <iostream>
#include <vector>
#include <array>
template<typename Matrix2D>
void print_matrix(Matrix2D const & vec)
{
std::cout << "size of matrix is [" << vec[0].size() << " x " << vec.size() << "]\n";
for (auto const & inner_vec : vec) {
for (auto const & item : inner_vec) {
std::cout << item << ", ";
}
std::cout << std::endl;
}
}
template<typename OriginalMatrix2D, typename RotatedMatrix2D>
void rotate_2d_matrix_clockwise_impl(OriginalMatrix2D const & matrix,
RotatedMatrix2D & rotated_matrix,
int const M,
int const N)
{
for (auto x = 0; x < N; ++x) {
for (auto y = 0; y < M; ++y) {
// Source : https://stackoverflow.com/questions/4780119/2d-euclidean-vector-rotations
rotated_matrix[y][-x -1 +N] = matrix[x][y];
}
}
}
template<typename T, size_t M, size_t N>
auto rotate_2d_matrix_clockwise(std::array<std::array<T, M>, N> const & original_matrix)
-> std::array<std::array<T, N>, M>
{
std::array<std::array<T, N>, M> rotated_matrix;
rotate_2d_matrix_clockwise_impl(original_matrix, rotated_matrix, M, N);
return rotated_matrix;
}
template<typename Matrix2D>
auto rotate_2d_matrix_clockwise(Matrix2D const & original_matrix) -> Matrix2D
{
int const M = original_matrix[0].size();
int const N = original_matrix.size();
Matrix2D rotated_matrix;
rotated_matrix.resize(M);
for (auto x = 0; x < M; ++x) {
rotated_matrix[x].resize(N);
}
rotate_2d_matrix_clockwise_impl(original_matrix, rotated_matrix, M, N);
return rotated_matrix;
}
int main()
{
std::array<std::array<int, 4>, 3> data = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
std::cout << "\nBefore Rotation :\n";
print_matrix(data);
std::cout << "\nAfter 2nd Clockwise Rotation :\n";
print_matrix(rotate_2d_matrix_clockwise(rotate_2d_matrix_clockwise(data)));
std::vector<std::vector<char>> data2 = { {'a', 'b', 'c', 'd'}, {'e', 'f', 'g', 'h'}, {'i', 'j', 'k', 'l'}};
std::cout << "Before Rotation :\n";
print_matrix(data2);
std::cout << "\nAfter Clockwise Rotation :\n";
print_matrix(rotate_2d_matrix_clockwise(data2));
return 0;
}
If I got you right, and all you want is to print the matrix 90 degrees clockwise, try this code:
for (int colNo = 0; colNo < vec[0].size(); colNo++)
{
for (int i = vec.size() - 1; i >= 0; i--)
{
const auto& row = vec[i];
int colVal = row.at(colNo);
cout << colVal;
}
cout << endl;
}
I have a program that looks like the following:
double[4][4] startMatrix;
double[4][4] inverseMatrix;
initialize(startMatrix) //this puts the information I want in startMatrix
I now want to calculate the inverse of startMatrix and put it into inverseMatrix. I have a library function for this purpose whose prototype is the following:
void MatrixInversion(double** A, int order, double** B)
that takes the inverse of A and puts it in B. The problem is that I need to know how to convert the double[4][4] into a double** to give to the function. I've tried just doing it the "obvious way":
MatrixInversion((double**)startMatrix, 4, (double**)inverseMatrix))
but that doesn't seem to work. Is that actually the right way to do it?
No, there's no right way to do specifically that. A double[4][4] array is not convertible to a double ** pointer. These are two alternative, incompatible ways to implement a 2D array. Something needs to be changed: either the function's interface, or the structure of the array passed as an argument.
The simplest way to do the latter, i.e. to make your existing double[4][4] array compatible with the function, is to create temporary "index" arrays of type double *[4] pointing to the beginnings of each row in each matrix
double *startRows[4] = { startMatrix[0], startMatrix[1], startMatrix[2] , startMatrix[3] };
double *inverseRows[4] = { /* same thing here */ };
and pass these "index" arrays instead
MatrixInversion(startRows, 4, inverseRows);
Once the function finished working, you can forget about the startRows and inverseRows arrays, since the result will be placed into your original inverseMatrix array correctly.
For given reason that two-dimensional array (one contiguous block of memory) and an array of pointers (not contiguous) are very different things, you can't pass a two-dimensional array to a function working with pointer-to-pointer.
One thing you could do: templates. Make the size of the second dimension a template parameter.
#include <iostream>
template <unsigned N>
void print(double a[][N], unsigned order)
{
for (unsigned y = 0; y < order; ++y) {
for (unsigned x = 0; x < N; ++x) {
std::cout << a[y][x] << ' ';
}
std::cout << '\n';
}
}
int main()
{
double arr[3][3] = {{1, 2.3, 4}, {2.5, 5, -1.0}, {0, 1.1, 0}};
print(arr, 3);
}
Another, a bit clumsier way might be to make the function accept a pointer to a single-dimensional array, and both width and height given as arguments, and calculate the indexes into a two-dimensional representation yourself.
#include <iostream>
void print(double *a, unsigned height, unsigned width)
{
for (unsigned y = 0; y < height; ++y) {
for (unsigned x = 0; x < width; ++x) {
std::cout << a[y * width + x] << ' ';
}
std::cout << '\n';
}
}
int main()
{
double arr[3][3] = {{1, 2.3, 4}, {2.5, 5, -1.0}, {0, 1.1, 0}};
print(&arr[0][0], 3, 3);
}
Naturally, a matrix is something that deserves a class of its own (but the above might still be relevant, if you need to write helper functions).
Since you are using C++, the proper way to do something like this would be with a custom class and some templates. The following example is rather rough, but it gets the basic point across.
#include <iostream>
using namespace std;
template <int matrix_size>
class SquareMatrix
{
public:
int size(void) { return matrix_size; }
double array[matrix_size][matrix_size];
void copyInverse(const SquareMatrix<matrix_size> & src);
void print(void);
};
template <int matrix_size>
void SquareMatrix<matrix_size>::copyInverse(const SquareMatrix<matrix_size> & src)
{
int inv_x;
int inv_y;
for (int x = 0; x < matrix_size; x++)
{
inv_x = matrix_size - 1 - x;
for (int y = 0; y < matrix_size; y++)
{
inv_y = matrix_size - 1 - y;
array[x][y] = src.array[inv_x][inv_y];
}
}
}
template <int matrix_size>
void SquareMatrix<matrix_size>::print(void)
{
for (int y = 0; y < 4; y++)
{
for (int x = 0; x < 4; x++)
{
cout << array[x][y] << " ";
}
cout << endl;
}
}
template <int matrix_size>
void Initialize(SquareMatrix<matrix_size> & matrix);
int main(int argc, char * argList[])
{
SquareMatrix<4> startMatrix;
SquareMatrix<4> inverseMatrix;
Initialize(startMatrix);
inverseMatrix.copyInverse(startMatrix);
cout << "Start:" << endl;
startMatrix.print();
cout << "Inverse:" << endl;
inverseMatrix.print();
return 0;
}
template <int matrix_size>
void Initialize(SquareMatrix<matrix_size> & matrix)
{
for (int x = 0; x < matrix_size; x++)
{
for (int y = 0; y < matrix_size; y++)
{
matrix.array[x][y] = (x+1)*10+(y+1);
}
}
}
Two dimensional array is not a pointer to pointer or something similar. The correct type for you startMatrix is double (*)[4]. For your function, the signature should be like:
MatrixInversion( double (*A)[4], int order, double (*B)[4] );
There is a solution using the pointer to point by bobobobo
William Sherif (bobobobo) used the C version and I just want to show C++ version of bobobobo's answer.
int numRows = 16 ;
int numCols = 5 ;
int **a ;
a = new int*[ numRows* sizeof(int*) ];
for( int row = 0 ; row < numRows ; row++ )
{
a[row] = new int[ numCols*sizeof(int) ];
}
The rest of code is the same with bobobobo's.
You can definitely do something like the code below, if you want.
template <typename T, int n>
class MatrixP
{
public:
MatrixP operator()(T array[][n])
{
for (auto i = 0; i < n; ++i) {
v_[i] = &array[i][0];
}
return *this;
}
operator T**()
{
return v_;
}
private:
T* v_[n] = {};
};
void foo(int** pp, int m, int n)
{
for (auto i = 0; i < m; ++i) {
for (auto j = 0; j < n; ++j) {
std::cout << pp[i][j] << std::endl;
}
}
}
int main(int argc, char** argv)
{
int array[2][2] = { { 1, 2 }, { 3, 4 } };
auto pa = MatrixP<int, 2>()(array);
foo(pa, 2, 2);
}
The problem is that a two-dimensional array is not the same as an array of pointers. A two-dimensional array stores the elements one row after another — so, when you pass such an array around, only a pointer to the start is given. The receiving function can work out how to find any element of the array, but only if it knows the length of each row.
So, your receiving function should be declared as void MatrixInversion(double A[4][], int order, double B[4][]).
by nice coding if c++:
struct matrix {
double m[4][4];
};
matrix startMatrix;
matrix inverseMatrix;
so the interface would be
void MatrixInversion(matrix &A, int order, matrix &B);
and use it
MatrixInversion(startMatrix, 4, inverseMatrix);
The benefit
the interface is very simple and clear.
once need to modify "m" of matrix internally, you don't need to update the interface.
Or this way
struct matrix {
void Inversion(matrix &inv, int order) {...}
protected:
double m[4][4];
};
matrix startMatrix;
matrix inverseMatrix;
...
An ugly way in c
void MatrixInversion(void *A, int order, void *B);
MatrixInversion((void*)startMatrix, 4, (void*)inverseMatrix);
EDIT: reference code for MatrixInversion which will not crash:
void MatrixInversion(void *A, int order, void *B)
{
double _a[4][4];
double _b[4][4];
memcpy(_a, A, sizeof _a);
memcpy(_b, B, sizeof _b);
// processing data here
// copy back after done
memcpy(B, _b, sizeof _b);
}