Using unordered_map on array of doubles - c++

My main data object is a array of doubles of a length that depends on a specific instantiation of my class. I would like to construct a very simple hash table to store/retrieve these objects, and we can assume that the numbers are generated in a way that is free of numerical error.
int main() {
std::tr1::unordered_map<double*, double*> cache;
double x1[] = { 1.0, 3.14 };
double x2[] = { 1.0, 3.14 };
cache[x1] = x1;
std::cout << "x1: " << cache.count(x1) << std::endl;
std::cout << "x2: " << cache.count(x2) << std::endl;
return 0;
}
The above obviously only compares the pointers, giving the output:
> ./tmp
x1: 1
x2: 0
When I really want to see:
> ./tmp
x1: 1
x2: 1
It's pretty clear how to create custom hashing and equality functions when the size of the arrays are fixed at compile time but I do not know how to make custom functions that depend on a specific instantiation... I created a class below, but I'm not sure if it's useful, or how it could be used.
class Hash_double_vec {
public:
int dim;
Hash_double_vec(int d) { dim = d; }
size_t operator()(const double *x) const{
std::tr1::hash<double> hash_fn;
size_t r = hash_fn(x[0]);
for(int i=1;i<dim;i++) r ^= hash_fn(x[i]);
return r;
}
bool operator()(const double *x, const double *y) const{
for(int i=1;i<dim;i++) if (fabs(x[i]-y[i]) > 1e-10) return false;
return true;
}
};

One way would be to create struct to hold the pointer to the sequence of doubles:
struct DoubleRegion
{
double* p;
size_t size;
};
bool operator==(DoubleRegion a, DoubleRegion b)
{
return a.size == b.size && memcmp(a.p, b.p, a.size) == 0;
}
size_t hash(DoubleRegion dr)
{
size_t h = 0;
for (double* p = dr.p; p != dr.p + dr.size; ++p)
h ^= hash(*p);
return h;
}
And then use it:
unordered_map<DoubleRegion, DoubleRegion> cache;
Of course it is your problem to make sure the lifetime of the backing memory is a superset of the lifetime of the DoubleRegion.
Old Answer:
If you don't know until runtime how big the key and value is going to be, use a std::vector:
unordered_map<vector<double>, vector<double>> cache;
If you know at compile-time how big you can use an std::array:
unordered_map<array<double, N>, array<double, N>> cache;
In both cases the default hashing function will work by value as you want, and you do not need to define a custom one.

Related

How do I order an array of strings on the basis of an array of integers

I have an array of integers with a bunch of numbers from 1-10
Then I have an array of names(strings) which belong with the numbers a.e.
Numbers[0] = 5, Numbers[1] = 2
Names[0] = "Jeremy", Names [1] = "Samantha".
I can easily order the numbers with:
int n = sizeof(Numbers) / sizeof(Numbers[0]);
sort(Numbers, Numbers + n, greater<int>());
But then the names and numbers don't match at all.
How do I fix this?
A very common approach is to create an array of indices and sort that:
std::vector<int> indices(Numbers.size());
std::iota(indices.begin(), indices.end(), 0);
std::sort(indices.begin(), indices.end(),
[&](int A, int B) -> bool {
return Numbers[A] < Numbers[B];
});
The original arrays are not altered, but now indices can be used to access both arrays in the desired order.
If we want to reorder Numbers or Names in place, then we can
create a set of "back indices" that record where to find the element i in the sorted array:
std::vector<int> back_indices(indices.size());
for (size_t i = 0; i < indices.size(); i++)
back_indices[indices[i]] = i;
Now we can reorder, for example, Names in place in the desired order:
int index = 0;
std::string name = Names[index];
for (int i = 0; i < back_indices.size(); i++) {
index = back_indices[index];
std::swap(name,Names[index]);
}
I've tested this code which should give you the required behavior:
struct numberName {
int num;
string name;
};
bool compare(numberName a, numberName b){
return a.num < b.num; // if equal, no need to sort.
}
int main() {
numberName list[2];
list[0].num = 5, list[1].num = 2;
list[0].name = "Jeremy", list[1].name = "Samantha";
sort(list, list+2, compare);
}
Like HAL9000 said, you want to use a struct since this keeps variables that belong to each other together. Alternatively you could use a pair, but I don't know if a pair would be good practice for your situation or not.
This is a great example of the complexities introduced by using parallel arrays.
If you insist on keeping them as parallel arrays, here is a possible approach. Create a vector of integer indexes, initialised to { 0, 1, 2, 3, etc }. Each integer represents one position in your array. Sort your vector of indexes using a custom comparision function that uses the indexes to refer to array1 (Numbers). When finished you can use the sorted indexes to reorder array1 and array2 (Names).
One could also write their own sort algorithm that performs swaps on the extra array at the same time.
Or one could trick std::sort into sorting both arrays simultaneously by using a cleverly designed proxy. I will demonstrate that such a thing is possible, although the code below may be considered a simple hackish proof of concept.
Tricking std::sort with a cleverly-designed proxy
#include <iostream>
#include <algorithm>
constexpr size_t SZ = 2;
int Numbers[SZ] = {5, 2};
std::string Names[SZ] = {"Jeremy", "Samantha"};
int tempNumber;
std::string tempName;
class aproxy {
public:
const size_t index = 0;
const bool isTemp = false;
aproxy(size_t i) : index(i) {}
aproxy() = delete;
aproxy(const aproxy& b) : isTemp(true)
{
tempName = Names[b.index];
tempNumber = Numbers[b.index];
}
void operator=(const aproxy& b) {
if(b.isTemp) {
Names[index] = tempName;
Numbers[index] = tempNumber;
} else {
Names[index] = Names[b.index];
Numbers[index] = Numbers[b.index];
}
}
bool operator<(const aproxy& other) {
return Numbers[index] < Numbers[other.index];
}
};
int main() {
aproxy toSort[SZ] = {0, 1};
std::sort(toSort, toSort+SZ);
for(int i=0; i<SZ; ++i) {
std::cout << "Numbers[" << i << "]=" << Numbers[i] << std::endl;
std::cout << "Names[" << i << "]=" << Names[i] << std::endl;
}
return 0;
}
...and an even more cleverly-designed proxy could avoid entirely the need to allocate SZ "aproxy" elements.
Tricking std::sort with an "even more cleverly-designed" proxy
#include <iostream>
#include <algorithm>
class aproxy;
constexpr size_t SZ = 2;
int Numbers[SZ] = {5, 2};
std::string Names[SZ] = {"Jeremy", "Samantha"};
aproxy *tempProxyPtr = nullptr;
int tempNumber;
std::string tempName;
class aproxy {
public:
size_t index() const
{
return (this - reinterpret_cast<aproxy*>(Numbers));
}
bool isTemp() const
{
return (this == tempProxyPtr);
}
~aproxy()
{
if(isTemp()) tempProxyPtr = nullptr;
}
aproxy() {}
aproxy(const aproxy& b)
{
tempProxyPtr = this;
tempName = Names[b.index()];
tempNumber = Numbers[b.index()];
}
void operator=(const aproxy& b) {
if(b.isTemp()) {
Names[index()] = tempName;
Numbers[index()] = tempNumber;
} else {
Names[index()] = Names[b.index()];
Numbers[index()] = Numbers[b.index()];
}
}
bool operator<(const aproxy& other) {
return Numbers[index()] < Numbers[other.index()];
}
};
int main() {
aproxy* toSort = reinterpret_cast<aproxy*>(Numbers);
std::sort(toSort, toSort+SZ);
for(int i=0; i<SZ; ++i) {
std::cout << "Numbers[" << i << "]=" << Numbers[i] << std::endl;
std::cout << "Names[" << i << "]=" << Names[i] << std::endl;
}
return 0;
}
Disclaimer: although my final example above may technically be in violation of the strict-aliasing rule (due to accessing the same space in memory as two different types), the underlying memory is only used for addressing space-- not modified-- and it does seems to work fine when I tested it. Also it relies entirely on std::sort being written in a certain way: using a single temp variable initialized via copy construction, single-threaded, etc. Putting together all these assumptions it may be a convenient trick but not very portable so use at your own risk.

Efficient matrix implementation

I have the following problem:
I've a precomputed 2d matrix of values which i need to lookup very often and compute only once
The size of the matrix is about 4000x4000 at most
The matrix won't be sparse, i typically need almost all values.
The values in the matrix can be boolean, integer or double. At least they are always small objects
Currently i am storing the precomputed values in a std::vector<<std::vector<T>>, and i've noticed the lookups into this datastructure takes quite some time in heavy computations. I've googled around and so far the suggested implementation seems to be to try a solution in which all the memory is stored contigious using an 1D array where the location in this array is computed based on i and j.
Does anybody have a good example implementation of this or has an even better suggestion? I couldn't find a modern C++ example, while it seems to be a very common problem to me. I'd prefer to use someone elses code instead of reinventing the wheel here. Of course i will measure the differences to see whether it actually improves performance.
Examples i've found:
https://medium.com/#patdhlk/c-2d-array-a-different-better-solution-6d371363ebf8
https://secure.eld.leidenuniv.nl/~moene/Home/tips/matrix2d/
Here is a very simple and efficient 2-d matrix. The 'main' creates a 10000x10000 double array 'mat', then filled it with random number. The array 'mat' is copied into another array 'mat2'. your may input two integers 'n' and 'm' between 0 and 9999 to fetch the double data at mat2(n,m).
Feel free to use or test it. Let me know if you encounter problems or need some more functions to be implemented. Good luck!
#ifndef ytlu_simple_matrix_class_
#define ytlu_simple_matrix_class_
#include <iostream>
#include <iomanip>
#include <complex>
template <typename T> class tMatrix
{
public:
T *ptr;
int col, row, size;
inline T* begin() const {return ptr;}
inline T* end() const {return this->ptr + this->size;}
inline T operator()(const int i, const int j) const { return ptr[i*col+j];
} // r-value
inline T&operator()(const int i, const int j) { return ptr[i*col+j]; } //l-value
inline tMatrix(): col{0}, row{0}, size{0}, ptr{0} {;}
tMatrix(const int i, const int j): col(j), row(i), size(i*j)
{
ptr = new T [this->size] ;
}
tMatrix(const tMatrix<T>&a) : tMatrix<T>(a.row, a.col)
{
std::copy(a.begin(), a.end(), this->ptr);
}
tMatrix<T>& operator=(tMatrix<T>&&a)
{
this->col = a.col;
this->row = a.row;
delete [] this->ptr;
this->ptr = a.ptr;
a.ptr = nullptr;
return *this;
}
tMatrix<T>& operator=(const tMatrix<T>&a)
{
if (col==a.cpl && row==a.row) std::copy(a.begin(), a.end(), this->ptr);
else { tMatrix<T>&&v(a); *this = std::move(v);}
return *this;
}
~tMatrix() {delete [] this->ptr;}
}; //end of class tMatrix
template <typename X> std::ostream& operator<<(std::ostream&p, const tMatrix<X>&a)
{
p << std::fixed;
for (int i=0; i<a.row; i++) {
for (int j=0; j <a.col; j++) p << std::setw(12) << a(i, j);
p << std::endl;
}
return p;
}
using iMatrix = tMatrix<int>;
using rMatrix = tMatrix<double>;
using cMatrix = tMatrix<std::complex<double> >;
#endif
//
//
#include <ctime>
#include <cstdlib>
#define N1 10000
int main()
{
int n, m;
std:srand(time(NULL)); // randomize
rMatrix mat(N1, N1); // declare a 10000 x 10000 double matrix
//
// fill the whole matrix with double random number 0.0 - 1.0
//
for (int i = 0; i<mat.row; i++)
{ for (int j=0; j<mat.col; j++) mat(i, j) = (double)std::rand() / (double)RAND_MAX; }
//
// copy mat to mat 2 just for test
//
rMatrix mat2 = mat;
//
// fetch data test input 0 <= n m < 10000 to print mat2(n, m)
//
while(1)
{
std::cout << "Fetch 2d array at (n m) = ";
std::cin >> n >> m;
if ((n < 0) || (m < 0) || (n > mat2.row) || (m > mat2.col) )break;
std::cout << "mat(" << n << ", " << m << ") = " << mat2(n, m) << std::endl << std::endl;
}
return 0;
}
The compile parameter I used and the test run. It takes a couple seconds to fill the random numbers, and I felt no lapse at all in fetch a data running in my aged PC.
ytlu#ytlu-PC MINGW32 /d/ytlu/working/cpptest
$ g++ -O3 -s mtx_class.cpp -o a.exe
ytlu#ytlu-PC MINGW32 /d/ytlu/working/cpptest
$ ./a.exe
Fetch 2d array at (n m) = 7000 9950
mat(7000, 9950) = 0.638447
Fetch 2d array at (n m) = 2904 5678
mat(2904, 5678) = 0.655934
Fetch 2d array at (n m) = -3 4

How to make index in an vector as a pair of (x,y) coordinates?

#include<bits/stdc++.h>
using namespace std;
int main() {
int i,j;
vector<int> v(100); // defined a vector of size 100
for(i=1;i<=50;i++) {
v[i]=i; // storing the values as we do in 1-d array
}
for(int i=1;i<=50;i++) {
cout<<"index="<<i<<" "<<v[i]<<"\n"; // It will give output similar
// to 1-d array
}
return 0;
}
So this is the case of one dimensional vector where index of vector is integer and the value is also integer. The above code is running fine.
But i want to take the index of a vector as pair (i,j) and the value as an integer.
See the below code for more clarification .
#include<bits/stdc++.h>
using namespace std;
int main() {
int i,j;
vector<pair<int,int>> ve(make_pair(100,100));
//defined a vector of size of indices (100,100)
for(i=1;i<=50;i++) {
for(j=0;j<=50;j++) {
ve[make_pair(i,j)]=2; // Storing value of 2 in all the
// (i,j) indices
}
}
for(int i=1;i<=50;i++) {
for(j=0;j<=50;j++) {
cout<<ve[make_pair(i,j)]<<" ";
// Output should be 2 in all the possible pairs of (i,j)
}
}
return 0;
}
But the above code is not working :(.
Please tell me how i can fix this problem.
Vectors, like arrays, work only with integer indexes. For a vector vec, the index must be in range 0 <= index < vec.size(), otherwise it either does not compile (not convertible to unsigned int) or the behavior is undefined (out of bounds).
You have written
vector<pair<int,int>> ve
Which means that you create a vector that contains pairs, not that it is indexed by pairs.
Now, if you want a two dimensional vector, i.e. a matrix, you should check Boost matrix. You can also implement it yourself, but making it general purpose will take some effort. The basic idea is to convert the pair to an single integer value. The simplest implementation is:
template <class T>
void init_2d(std::vector<T> &vec, std::pair<unsigned, unsigned> coordinates)
{
vec.resize(coordinates.first * coordinates.second);
}
inline unsigned flatten(std::pair<unsigned, unsigned> coordinates,
unsigned num_columns)
{
return coordinates.first * num_columns + coordinates.second;
}
template <class T>
T & get_2d(std::vector<T> & vec,
std::pair<unsigned, unsigned> coordinates,
unsigned num_columns)
{
return vec.at(flatten(coordinates, num_columns));
}
template <class T>
const T & get_2d(const std::vector<T> & vec,
std::pair<unsigned, unsigned> coordinates,
unsigned num_columns)
{
return vec.at(flatten(coordinates, num_columns));
}
and then use it in your code:
int main() {
std::vector<int> ve;
auto dimensions = std::make_pair(100,100);
init_2d(ve, dimensions);
for(int i=1;i<=50;i++) {
for(int j=0;j<=50;j++)
get_2d(ve, {i,j}, dimensions.second) =j;
}
for(int i=1;i<=50;i++) {
for(int j=0;j<=50;j++)
std::cout << get_2d(ve, {i,j}, dimensions.second) <<" ";
std::cout << '\n';
}
return 0;
}
But, instead of reimplementing existing code, you should prefer to use boost matrix. If you are trying to learn how a matrix can be implemented (which is a very good idea), then go on and try to convert the above functions+vector into a class, and put the dimensions pair into that class. Having a class, for a matrix, is better than to use separate functions. It is easier to maintain invariants for a class than for separate functions.
Note: you can use std::map<std::pair<int, int>> instead, but it will be more difficult to iterate over it and it will be much slower. If it makes your code clearer, using std::map is a good idea, but it is not clear cut whether std::map<pair<...>> is easier to work with than with std::vector + _2d functions.
I would suggest you to use map instead.
Operator [] for map takes key_type as parameter which is a container which means you can use pair object as index (called key in map), however Operator [] for vetor takes size_type as parameter which is an unsigned integer.
Your code could look like the following:
map< pair<int, int>, int > notVector;
for(i=0;i<=50;i++)
for(j=0;j<=50;j++)
notVector[make_pair(i,j)]=2; // Storing value of 2 in all the (i,j) indices
for(i=0;i<=50;i++)
for(j=0;j<=50;j++)
cout<<notVector[make_pair(i,j)]<<" ";
another solution: create your own container by aggregating a standard one.
Extremely simplified example:
#include <vector>
#include <iostream>
struct xy
{
std::size_t x, y;
};
constexpr std::size_t linear_extent(xy _)
{
return _.y * _.x;
}
constexpr std::size_t linear_position(xy _, xy extent)
{
return _.y * extent.x + _.x;
}
template<class T>
struct vector_2d
{
vector_2d(xy size, T x = T())
: extent_(size)
, storage_(linear_extent(extent_), x)
{
}
T& operator[](xy const& _)
{
return storage_[linear_position(_, extent_)];
}
T const& operator[](xy const& _) const
{
return storage_[linear_position(_, extent_)];
}
constexpr auto extent() const { return extent_; }
xy extent_;
std::vector<T> storage_;
};
template<class T>
std::ostream& operator<<(std::ostream& os, vector_2d<T> const& v)
{
const char* sep = " [";
os << "[";
auto extent = v.extent();
for(auto y = std::size_t(0) ; y < extent.y ; ++y)
{
os << sep;
const char* sep2 = " ";
for (auto x = size_t(0) ; x < extent.x ; ++x)
{
std::cout << sep2 << v[{x, y}];
sep2 = ", ";
}
os << " ]";
sep = "\n [";
}
os << " ]";
return os;
}
int main()
{
auto v = vector_2d<int>({5, 5});
v[{1, 3}] = 8;
std::cout << v << std::endl;
}
Keep it simple
All you need is 1 (One!) C++ line: ...+ Update: Optional macro (the macro is to answer #eneski comment):
std::vector<std::vector<int>> ve(100, std::vector<int>(100, 0)); // Initialize to 0
// Turns [wr(pair)] syntax to [pair.first][pair.second] syntax:
#define wr(pr) (pr).first][(pr).second // Wrapper macro
And than use:
ve[wr(std::make_pair(i, j))] = 35; // For example
int val = ve[wr(std::make_pair(i, j))];
// Or:
ve[i][j] = 70; // For example
val = ve[i][j];
There is no real need to use the wr wrapper macro. Use ve[i][j] and if you have somewhere in your code a std::pair p, use: ve[p.first][p.second] instead of ve[p] - Both are the same. Also, it is nonsense to take (i, j) and to make_pair on-the-fly just to use them again as [i][j] indexes. If, despite all, one insists on the syntax, than use the wr wrapper macro.
--
But, in a case of a fixed sequential range, a 2D std::array is a better choice (& you can add the wrapper macro as well, if you insist):
#include <array>
int main()
{
int i = 7, j = 5;
std::array<std::array<int, 100>, 100> ar; // 100 X 100
ar[0].fill(0); ar.fill(ar[0]); // Initialize to 0
ar[i][j] = 35; // For example
return 0;
}
Are you simply attempting to access 1d vector content as if it was a 2d vector? Perhaps you could use a helper function to convert 2d index into 1d index, for example:
#include <vector>
#include <iostream>
#include <cassert>
template<size_t ROWS, size_t COLS>
size_t convertIndex(size_t row, size_t col)
{
assert(row < ROWS && col < COLS);
return row * COLS + col;
}
int main()
{
std::vector<int> v =
{
0,1,2,3,4,
5,6,7,8,9
};
std::cout << v[convertIndex<2, 5>(1, 3)];
}
This outputs 8

Fastest way to subtract pointer array by a constant

I have a very large array of type (short*). How do I subtract all values by a constant in the fastest manner?
Using a for loop is indeed the most efficient way to do this
short *arr = new short[1000000];
const short c = 8504;
//populate the array
Populate(arr); //just some method to populate the array
for(int i=0;i<1000000;i++){
arr[i] = c - arr[i] ;//subtract from the constant
//or even
//*arr = c - *arr++ ;
}
This code doesn't check for type overflows though.
If you don't need to recalculate the actual values, you can calculate it ad hoc on usage:
#include <iostream>
using namespace std;
struct OffsetShort {
short value;
static short offset;
operator short() const { return value - offset; }
};
short OffsetShort::offset = 0;
int main() {
OffsetShort *vals[] = {new OffsetShort{1},new OffsetShort{2},new OffsetShort{3}};
for (auto f : vals) {
cout << *f;
}
OffsetShort::offset = 10;
for (auto f : vals) {
cout << *f;
}
return 0;
}
this prints
123
-9-8-7

Converting multidimensional arrays to pointers in c++

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);
}