I have this function which i prototyped in python for navigating grid indexes. It works perfectly in python but due to the way the modulo operator handles negative numbers it falls down in c++. Can anyone suggest a modification that will make this work?
The function fails when coordinates nx and ny are negative.
int wrap_grid(int index, int x, int y, int nx, int ny) {
//first calculate positon on row by adding nx -
//assuming an infinite grid of indices (no limits or wrap)
int a = (index + (y * nx));
//then wrap around the width (x) of the row
int b = a % (x * y);
//now do column, calculate the bottom index of the column
int start = b - b % y;
//and the top index
int limit = b - b % y + y;
//now wrap the ny value around the columns
return start + (b + ny) % (limit - start);
}
EDIT: To explain function arguments
index is the index of a rectangular grid, like this:
col1
col2
col3
5
11
17
4
10
16
3
9
15
2
8
14
1
7
13
0
6
12
x is the width of the grid, in this case 3.
y is the height of the grid, in this case 6.
nx is the coordinate grid square offset, so nx = 1 is one grid square to the right, similar for ny=1 is one grid square 'upwards'.
The return value is the new index number after transforming index with the coordinates nx and ny.
EDIT: updated function based on jwezorek's approach. Note, the only effective change (function factors aside) are the comparison operators which must allow zero values.
int wrap_grid(int index, int rows, int columns, int offset_x, int offset_y) {
//index to grid coordinates always positive
int x = (index / rows) + (offset_x);
x = x >= 0 ? x : x + columns;
int y = (index % rows) + (offset_y);
y = y >= 0 ? y : y + rows;
//grids to coords
int column = x % columns;
column = column >= 0 ? column : column + columns;
int row = y % rows;
row = row >= 0 ? row : row + rows;
int bottom_of_column_index = column * rows;
return bottom_of_column_index + row;
}
You just need a mod function that will only give you non-negative values. To just do it the straight-forward way is like below (after moving your code around for clarity).
#include <tuple>
#include <iostream>
int grid_coords_to_index(int cols, int rows, int x, int y) {
// wrap the coordinates...
int column = x % cols;
column = column >= 0 ? column : column + cols;
int row = y % rows;
row = row >= 0 ? row : row + rows;
int bottom_of_column_index = column * rows;
return bottom_of_column_index + row;
}
std::tuple<int,int> index_to_grid_coords(int cols, int rows, int index) {
// TODO: handle negatives correctly here too, if we cannot
// assume indices are positive.
return { index / rows, index % rows };
}
int wrap_grid(int initial_index, int cols, int rows, int x_offset, int y_offset) {
auto [x, y] = index_to_grid_coords(cols, rows, initial_index);
return grid_coords_to_index(cols, rows, x + x_offset, y + y_offset);
}
int main()
{
/*
5 11 17
4 10 16
3 9 15
2 8 14
1 7 13
0 6 12
index 9 is (1,3) so two to the left and one down should be 14 given wrapping
*/
std::cout << wrap_grid(9, 3, 6, -2, -1) << "\n";
}
Related
I have a c++ program that looks as following:
using namespace std;
extern"C" {
void fortfunc_(int a[][4], int *size_x, int *size_y);
}
int main()
{
// size_x and size_y are dynamically determined at runtime
// setting them here directly for simplification
int size_x = 5;
int size_y = 4;
//we need to use 4 instead of size_y to prevent a mismatch with the int a[][4] definition in fortfunc_
int foo [size_x][4];
for (int i=0 ; i<size_x ; i++ )
{
for (int y=0 ; y<size_y ; y++ )
{
foo[i][y] = i+y;
}
}
fortfunc_(foo, &size_x, &size_y);
return 0;
}
The respective fortran program only prints the array and looks like this:
subroutine fortfunc(foo, size_x, size_y)
use :: ISO_C_BINDING
integer :: size_x, size_y
integer(c_int), dimension(size_y,size_x), intent(in) :: foo
integer :: i, y
do y = 1, size_x ! We reverse the loop order because of the reverse array order in fortran
do i = 1, size_y
print*, "col ",i,y, foo(i,y)
end do
print*, "row"
end do
return
end
When compiled with gfortran -c testF.f90 && g++ -c testC.cpp && g++ -o test testF.o testC.o -lgfortran && ./test this works.
However, I would like to be able to dynamically determine the shape of the 2d array foo in my main function and call my external fortfunc_ function accordingly, instead of hardcoding int a[][4] there. How can I modify my program to accomplish that?
You typically allocate a 1d vector and treat it as a 2d array.
Example:
#include <vector>
extern "C" {
// note the changed signature with `int* a` instead:
void fortfunc_(int* a, int *size_x, int *size_y);
}
int main() {
int size_x = 5;
int size_y = 4;
// A 1d vector with size_y * size_x elements:
std::vector<int> foo(size_y * size_x);
for (int y = 0; y < size_y; y++) {
for (int x = 0; x < size_x; x++) {
// calculation for row-major order:
foo[y * size_x + x] = y * size_x + x;
// Note: Fortran uses column-major order so you may need to change
// to `foo[x * size_y + y] = x * size_y + y;`
}
}
fortfunc_(foo.data(), &size_x, &size_y);
// ^^^^^^
// a pointer to the first `int` in the 1d vector
}
Output:
col 1 1 0
col 2 1 1
col 3 1 2
col 4 1 3
row
col 1 2 4
col 2 2 5
col 3 2 6
col 4 2 7
row
col 1 3 8
col 2 3 9
col 3 3 10
col 4 3 11
row
col 1 4 12
col 2 4 13
col 3 4 14
col 4 4 15
row
col 1 5 16
col 2 5 17
col 3 5 18
col 4 5 19
row
I've been struggling with a simple class representing a matrix in C++. Instead of using a multidimensional array, I've decided to use a flat array and access the values by calculating the index of the according cell by [row * x_dim + col]. I want to use 2D matrices only.
Ideally, I would also create getter and setter functions, but as I am already having troubles I skipped those for now.
The main problem is, that after setting values, those values seem to be corrupted somewhere along the way as when printing them out again, I'm reading different values then what I've actually stored.
Here's the (simplified) header MyMatrix.h:
class MyMatrix{
public:
int x_dim, y_dim;
float *my_matrix;
MyMatrix(int x, int y);
~MyMatrix();
};
Here is MyMatrix.cpp:
#include "MyMatrix.h"
MyMatrix::MyMatrix(int x, int y){
x_dim = x;
y_dim = y;
my_matrix = new float[x * y];
}
MyMatrix::~MyMatrix(){
delete[] my_matrix;
}
Now when creating a new instance of MyMatrix, filling the array with ascending numbers and then printing the values again, I am getting different values for some cells in the (flat) matrix. Here's what I did:
#include "MyMatrix.h"
#include <iostream>
int main(){
MyMatrix test(3, 4);
//filling the array in test with ascending numbers
for(int row = 0; row < test.x_dim; row++){
for(int col = 0; col < test.y_dim; col++){
test.my_matrix[row * test.x_dim + col] = col+1;
}
}
for(int row = 0; row < test.x_dim; row++){
std::cout << "Row " << row << ": ";
for(int col = 0; col < test.y_dim; col++){
std::cout << test.my_matrix[row * test.x_dim + col] << " ";
}
std::cout << std::endl;
}
}
So what my output should look like is this:
Row 0: 1 2 3 4
Row 1: 1 2 3 4
Row 2: 1 2 3 4
But instead, it looks like this:
Row 0: 1 2 3 1
Row 1: 1 2 3 1
Row 2: 1 2 3 4
As one can see, the first two rows have a 1 instead of a 4 in column 3.
I've really been struggling with identifying the underlying issue here and I can't figure it out so I would appreciate any help!
Thanks!
I am using clang version 13.0.0 on an M1 Pro and the g++ compiler.
This is the wrong index:
row * test.x_dim + col
Suppose you are in the last iteration of the outer loop then row == x_dim-1 and you get:
(x_dim-1) * x_dim + col
while it should be (supposed x is rows):
(y_dim-1) * x_dim + col
Tip: Your variable naming col vs x_dim and row vs y_dim can be made better. x, x_dim and y, y_dim or col, num_columns and row, num_rows would be less errorprone.
I have written a program that gives random values to two matrices and then using multiplication to print out a third matrix. Matrix 1 is 3x3 (rows, columns) and Matrix 2 is (3x2).
My output is as follows:
Matrix 1:
4 6 0
9 1 5
4 7 5
Matrix 2:
4 6
0 9
1 5
matrix 1 x matrix 2:
16 78 97059710
41 88 218384285
21 112 97059715
As you can see the third matrix gives an extra row / column with weird values. (97057910 etc.)
Below is my multiply function written in C++:
Matrix Matrix::multiply(Matrix one, Matrix two) {
int n1 = one.data[0].size();
int n2 = two.data.size();
int nCommon = one.data.size();
vector< vector<int> > temp(nCommon);
for ( int i = 0 ; i < nCommon ; i++ )
temp[i].resize(n2);
for(int i=0;i<n1;i++) {
for(int j=0;j<n2;j++) {
for(int k=0;k<nCommon;k++) {
temp[i][j]= temp[i][j] + one.data[i][k] * two.data[k][j];
}
}
}
const Matrix result = Matrix(temp);
return result;
}
Does anyone have any suggestion on how to fix this issue? I want to remove that line of weird values and only have two columns.
You're getting your numbers of rows and columns mixed up. The idea is to multiply A (I x K) by B (K x J), and here's what the code does:
int n1 = one.data[0].size(); // this is K
int n2 = two.data.size(); // this is also K
int nCommon = one.data.size(); // this is I
vector< vector<int> > temp(nCommon);
for ( int i = 0 ; i < nCommon ; i++ )
temp[i].resize(n2);
// temp is now I x K, which is not what was intended,
// and the iteration over rows and columns will not be correct.
Try this instead:
int n1 = one.data.size(); // this is I
int n2 = two.data[0].size(); // this is J
int nCommon = two.data.size(); // this is K
vector< vector<int> > temp(n1);
for ( int i = 0 ; i < nCommon ; i++ )
temp[i].resize(n2);
Even though one of your matrixes has only two columns, looks like your for-loop will still attempt to access values in the third column of each row.
two.data[k][j]
k iterates from 0 to one.data.size()-1, or 0..2.
j also iterates from 0 to two.data.size()-1, also 0..2.
However, according to your description, the two's matrix's second dimension's range is only 0..1.
Undefined behavior. The code is running off past the end of the vector, and reads garbage.
I have a table which consists of nonnegative integers that are layed out in this manner: Each element in the table is the minimum value that does not appear to its left or above it. Here's an example of a 6x6 grid:
0 1 2 3 4 5
1 0 3 2 5 4
2 3 0 1 6 7
3 2 1 0 7 6
4 5 6 7 0 1
5 4 7 6 1 0
The first row and column begin with 0 1 2 3 4 5... In coordinates (x,x) is always a 0, as you can see. On each tile after that, you have to place the smallest positive number that doesn't already exist on the same row or column. Much like in a sudoku-puzzle: There cannot be a number twice on the same row and column.
Now I have to print the number in the given coordinates (y,x). For example [2, 5] = 5
I came up with a working solution, but it takes way too much memory and time, and I just know there's another way of doing this. My time limit is 1 second, and the coordinates I have to find the number at can go up to (1000000, 1000000).
Here's my code at the moment:
#include <iostream>
#include <vector>
int main()
{
int y, x, grid_size;
std::vector< std::vector<int> > grid;
std::cin >> y >> x; // input the coordinates we're looking for
grid.resize(y, std::vector<int>(x, 0)); // resize the vector and initialize every tile to 0
for(int i = 0; i < y; i++)
for(int j = 0; j < x; j++)
{
int num = 1;
if(i != j) { // to keep the zero-diagonal
for(int h = 0; h < y; h++)
for(int k = 0; k < x; k++) { // scan the current row and column
if(grid[h][j] == num || grid[i][k] == num) { // if we encounter the current num
num++; // on the same row or column, increment num
h = -1; // scan the same row and column again
break;
}
}
grid[i][j] = num; // assign the smallest number possible to the current tile
}
}
/*for(int i = 0; i < y; i++) { // print the grid
for(int j = 0; j < x; j++) // for debugging
std::cout << grid[i][j] << " "; // reasons
std::cout << std::endl;
}*/
std::cout << grid[y-1][x-1] << std::endl; // print the tile number at the requested coordinates
//system("pause");
return 0;
}
So what should I do? Is this easier than I think it is?
To summarize your question: You have a table where each element is the minimum nonnegative integer that does not appear to its left or above. You need to find the element at position (x,y).
The result is surprisingly simple: If x and y are 0-based, then the element at (x,y) is x XOR y. This matches the table you have posted. I have verified it experimentally for a 200x200 table.
The proof:
It's easy to see that the same number won't appear twice on the same row or column, because if x1^y = x2^y then necessarily x1=x2.
To see that x^y is minimal: Let a be a number smaller than x^y. Let i be the index (from the right) of the leftmost bit where a differs from x^y. The ith bit of a must be 0 and the ith bit of x^y must be 1.
Therefore, either x or y must have 0 in the ith bit. Suppose WLOG it was x that had 0. Represent x and y as:
x = A0B
y = C1D
Where A,B,C,D are sequences of bits, and B and D are i bits long. Since the leftmost bits of a are the same as those in x^y:
a^x = C0E
Where E is a sequence of i bits. So we can see that a^x < y. The value that appered in the (a^x)th row on the same column was: (a^x)^x = a. So the value a must have already appeared in the same row (or column, if it was y that had 0 in the ith bit). This is true for any value smaller than x^y, so x^y is indeed the minimum possible value.
I'm trying to get a specific element inside of a vector.
For example,
Lets say I have a vector.
std::vector<Tile> TileList;
The Vector is of size MAP_HEIGHT = 30, MAP_WIDTH = 200
So its total size is MAP_HEIGHT * MAP_WIDTH = 6000.
I use a double nested for loop to iterate through and create a vector full of tiles.
for(int Y = 0; Y < MAP_HEIGHT; Y++)
{
for(int X = 0; X < MAP_WIDTH; X++)
{
Tile TempTile;
fscanf(FileHandle, "%d:%d ", &TempTile.TileID, &TempTile.TypeID);
TileList.push_back(TempTile);
}
}
Now my questions is lets say I iterate through
int ID = 0;
for(int Y = 0; Y < MAP_HEIGHT; Y++)
{
for(int X = 0; X < MAP_WIDTH; X++)
{
TileList[ID].do stuff with it
//Check for the tile above this tile
// Find a way to calculate the ID of the tile above this tile
int IDoftilabove = ID - do something;
if(TileList[IDoftilabove].variable == TILE_SOMETHING)
{
do stuff
}
ID++;
}
How do I calculate the ID of an element above(well technically before this ID) inside the vector based on the current element I'm on.
Illustration:
say i have a matrix 5x5,
Lets say my current ID is 8. so I am on the second row number 3.
1 2 *3* 4 5
1 2 (3) 4 5
1 2 3 4 5
1 2 3 4 5
1 2 3 4 5
Now I want the ID of the element in vector that is directly above me which is the ID 3, first row number 3. and this is just assuming the the MAP_WIDTH = 5 and the MAP_HEIGHT = 5.
8 - 5 = 3
Current - MAP_WIDTH = Above
You can easily determine the (row,col) coordinates given the ID:
row = ID / MAP_WIDTH;
col = ID % MAP_WIDTH;
If you want to know what is the coordinate from the element above:
row--;
ID_above = row * MAP_WIDTH + col;
The same applies if you want to know what is the element below:
row++;
ID_below = row * MAP_WIDTH + col;
It seems like you want to map between linear and 2d indices. This is pretty straightforward.
int rect2lin(int w, int x, int y) { return y*w+x; }
void lin2rect(int w, int i, int * x, int * y) { *y = i/w; *x = i%w; }
So in your example, the ID of the element above (X,Y) would be rect2lin(MAP_WIDTH, X,Y-1), which is simply (Y-1)*MAP_WIDTH+X. This generalizes straightforwardly to higher numbers of dimension. For example, i=(z*h+y)*w+x for 3d, and so on.