C bitmap: rotation and zoom - c

I'm recently checking out C for a friend having problems with it for school. As I only have learned java and C#, though it would be easy. But currently stuck on this.
I have a project reading a small bmp (512x512) image. I've managed to change some colors on it and have it rotated (both horizontal as vertical). Though I'm stuck with the -90° rotation.
1. ROTATION (512x512)
Currently I have this code (both getPixel and setPixel are my own functions):
typedef struct _bitmap {
char file_path[PATH_MAX+1];
char magic_number[3];
unsigned int size;
unsigned char application[5];
unsigned int start_offset;
unsigned int bitmapHeaderSize;
unsigned int width;
unsigned int height;
unsigned short int depth;
unsigned char* header;
PIXEL* raster;
} BITMAP;
void rotate(BITMAP* bmp) {
int i;
int j;
PIXEL* originalPixel;
BITMAP* originalBmp;
deepCopyBitmap(bmp, originalBmp);
for(j=1; j <= bmp->height; j++) {
for(i=1; i <= bmp->width; i++) {
originalPixel=getPixel(originalBmp->raster, bmp->width, bmp->height, j, i);
setPixel(bmp->raster, bmp->width, bmp->height, (bmp->width + 1 - i), j, originalPixel);
}
}
}
void deepCopyBitmap(BITMAP* bmp, BITMAP* copy) {
*copy = *bmp;
if (copy->raster) {
copy->raster = malloc(copy->height * sizeof(*copy->raster));
for (int i = 0; i < copy->height; i++) {
copy->raster[i] = malloc(copy->width * sizeof(*copy->raster[i]));
memcpy(copy->raster[i], bmp->raster[i], copy->width * sizeof(*copy->raster[i]));
}
}
}
indirection requires pointer operand ('PIXEL' (aka 'struct _pixel') invalid)
copy->raster[i] = malloc(copy->width * sizeof(*copy->raster[i]));
^~~~~~~~~~~~~~~~
indirection requires pointer operand ('PIXEL' (aka 'struct _pixel') invalid)
memcpy(copy->raster[i], bmp->raster[i], copy->width * sizeof(*copy->raster[i]));
^~~~~~~~~~~~~~~~
expanded from macro 'memcpy' __builtin___memcpy_chk (dest, src, len, __darwin_obsz0 (dest))
This correctly rotates the first diagonal part of the image, but the second part is totally wrong (having two times a part of the first diagonal).
I think the problem is, swapping pixels around and halfway I'm starting to swap already swapped pixels. So I tried to duplicate my bmp, to a original bitmap (originalBmp) and one rotated (rotatedBmp). Though I think it just copies the reference. Anyone has an idea how I create a duplicate bmp?
As example (sorry for the flue img): I want the vertical lines (left), to turn -90deg, so it becomes horizontal lines (right). Though the left diagonal part is correct. But the right part of the diagonal is incorrect copying a piece of the left diagonal. I think because it swaps pixels that are already swapped in the bmp file.
2. ROTATION (512x1024)
What happens if the height or width is the double of the other? Anyone knows how to start on this?
3. ZOOM (200%)
Anyone know how to do this? Get the center pixels of the bitmap, and make them twice at the start of the image, or is there a better/cleaner solution?
1 2 3 4 5 6 7 8 3 3 4 4 5 5 6 6
2 2 3 4 5 6 7 8 3 3 4 4 5 5 6 6
3 3 3 4 5 6 7 8 4 4 4 4 5 5 6 6
4 4 4 4 5 6 7 8 4 4 4 4 5 5 6 6
5 5 5 5 5 6 7 8 5 5 5 5 5 5 6 6
6 6 6 6 6 6 7 8 5 5 5 5 5 5 6 6
7 7 7 7 7 7 7 8 6 6 6 6 6 6 6 6
8 8 8 8 8 8 8 8 6 6 6 6 6 6 6 6

From your code it seems clear that both originalBmpand bmp are pointers to some BMP-type. So when you do originalBmp=bmp;, you just get two pointers pointing to the same BMP, i.e. they operate on the same data.
I assume you have something like
struct BMP
{
// ....
};
If that is the case you can make a copy like this:
struct BMP originalBmp = *bmp;
When using originalBmp you must use the . notation, e.g. originalBmp.raster
EDIT An alternative approach
Instead of making a copy of the original bmp you could do the rotation directly on the original. Each rotation will involve 4 locations. You can copy the 4 locations into temp variables first and then write them to their final location.
For a simple matrix it could be something like this:
#include <stdio.h>
#define WIDTH 4
// display function
void d(int t[WIDTH][WIDTH])
{
int i, j;
for (i=0; i<WIDTH;i++)
{
for (j=0; j<WIDTH; j++)
{
printf("%d ", t[i][j]);
}
printf("\n");
}
}
int main(void) {
int org[WIDTH][WIDTH];
int i, j;
// Just initialize the matrix
for (i=0; i<WIDTH;i++)
{
for (j=0; j<WIDTH; j++)
{
org[i][j] = 10 + i*5 + j;
}
}
printf("Original\n");
d(org);
// Rotate the matrix
for (j=0; j < (WIDTH/2); j++)
{
for (i=0; i < ((WIDTH+1)/2); i++)
{
int t1 = org[j][i];
int t2 = org[i][WIDTH-1-j];
int t3 = org[WIDTH-1-j][WIDTH-1-i];
int t4 = org[WIDTH-1-i][j];
org[j][i] = t2;
org[i][WIDTH-1-j] = t3;
org[WIDTH-1-j][WIDTH-1-i] = t4;
org[WIDTH-1-i][j] = t1;
}
}
printf("Rotated\n");
d(org);
return 0;
}
This will output:
Original
10 11 12 13
15 16 17 18
20 21 22 23
25 26 27 28
Rotated
13 18 23 28
12 17 22 27
11 16 21 26
10 15 20 25
Change to #define WIDTH 5 and it will output:
Original
10 11 12 13 14
15 16 17 18 19
20 21 22 23 24
25 26 27 28 29
30 31 32 33 34
Rotated
14 19 24 29 34
13 18 23 28 33
12 17 22 27 32
11 16 21 26 31
10 15 20 25 30

Related

Deleting an element from an array in C

so Im supposed to make a game an assignment for class.
Essentially, I decided to re-create a heads up Poker game, running different functions such as int deal(a, b, x, y) where a and b are the hero's cards, and x and y are the villan's.
This function in particular, has me a bit stumped. Effectively, I loop through the array deck, and assign random numbers to a, b, x and y. Then, I will translate each assigned value into a real, unique card, and return that to int main().
The part that I am stuck at is "as each card is selected, it is deleted from the array. It seems that there is no easy way in C to simply remove an element from deck array.
int deal (a, b, x, y)
{
int deck[52] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30
31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52};
int heroFirst;
int heroSecond;
int villainFirst;
int villainSecond;
srand(0);
}
Any thoughts?
You don't have to delete anything.
Shuffle your deck array (using a Fisher-Yates shuffle or similar algorithm). Deal each card from the "top" of the deck:
int top = 0;
card1 = deck[top++];
card2 = deck[top++];
card3 = deck[top++];
...
etc. The top variable is the index of the next available card in the deck.
The general outline of your code will be something like
#define DECKSIZE 52
#define HANDSIZE 5
int main( void )
{
int deck[DECKSIZE] = { ... }; // initial deck;
size_t top = 0; // points to next available card
shuffle( deck, DECKSIZE );
int hero[HANDSIZE] = {0}; // 0 means no card has been drawn for
int villan[HANDSIZE] = {0}; // that element.
if ( deal( hero, HANDSIZE, deck, DECKSIZE, &top ) &&
deal( villan, HANDSIZE, deck, DECKSIZE, &top ) )
{
/**
* do stuff with hero and villan hands
*/
}
else
{
/**
* Not enough cards available in deck for two hands.
*/
}
};
Your deal function would look something like
int deal( int *hand, size_t handsize, int *deck, size_t decksize, size_t *top )
{
size_t i;
for ( i = 0; i < handsize && *top < decksize; i++ )
hand[i] = deck[(*top)++];
return i == handsize;
}
This function will return 0 if we run out of cards in deck before we've dealt the hand, in which case you'll need to do...something. Good luck!
If you want to deal a partial hand (such as to replace 3 cards), you'd do something like
if ( deal( &hero[2], 3, deck, DECKSIZE, &top) )
...
This call will overwrite hero[2] through hero[4] with three new cards drawn from deck. With each call to deal, top will be advanced to point to the next available card in the deck.
You can write a discard function that returns cards to the deck. It means keeping a separate bottom variable and updating that:
int discard( int card, int *deck, size_t decksize, size_t *top, size_t *bottom )
{
int result = *bottom < *top && *bottom < decksize;
if ( result )
deck[(*bottom)++] = card;
return result;
}
Obviously, bottom should be strictly less than the deck size and strictly less than top on a discard; otherwise, we haven't managed our deck or hands properly. With a little work, you could make your array "circular", such that top and bottom "wrap around" as necessary. If you exhaust the deck, you can reshuffle (minus the cards in hand, which will be the deck entries between bottom and top) and reset top and bottom as necessary.
Play with this on paper for a little while, and it should become obvious.
EDIT
Addressing questions here:
At which point do you assign deck[5] to a card, for instance
That happens in the deal function, in the for loop. The first time we call deal, we tell it to deal to the hero hand:
deal( hero, HANDSIZE, deck, DECKSIZE, &top )
At this point, top is 0. Assuming we're dealing 5 cards at a time, the first call to deal effectively does this:
Loop iteration 0: hero[0] = deck[0]
Loop iteration 1: hero[1] = deck[1]
Loop iteration 2: hero[2] = deck[2]
Loop iteration 3: hero[3] = deck[3]
Loop iteration 4: hero[4] = deck[4]
When the function returns, the top variable has been updated to 5. The next time we call deal, we tell it to deal to the villain hand:
deal( villain, HANDSIZE, deck, DECKSIZE, &top )
Again, assuming we're dealing 5 cards at a time, the loop effectively does this:
Loop iteration 0: villain[0] = deck[5];
Loop iteration 1: villain[1] = deck[6];
Loop iteration 2: villain[2] = deck[7];
Loop iteration 3: villain[3] = deck[8];
Loop iteration 4: villain[4] = deck[9];
After the second call to deal, top has been updated to 10.
Each time you call deal with the top variable, it will start dealing from deck at the position specified by top, and each time through the loop it will add 1 to top. The loop will exit if one of two conditions is true:
i == handsize - we've dealt all the cards necessary for this hand
*top == decksize - we've reached the end of the array, nor more cards may be dealt.
So, suppose you've dealt a number of hands, and there are only 3 cards left in the deck - if you try to deal 5 more cards, the loop will exit before you've dealt all 5 cards, and we'll return a 0 to indicate that no more cards are left in the deck.
at which point is the desk shuffled randomly?
You would call a shuffle function to do that before the first call to deal:
int deck[DECKSIZE] = { ... };
...
shuffle( deck, DECKSIZE );
...
if ( deal( hero, HANDSIZE, deck, DECKSIZE, &top ) &&
deal( villain, HANDSIZE, deck, DECKSIZE, &top ) )
{
...
}
A simplistic (and not terribly good) implementation of the shuffle function would be:
void shuffle( int *deck, size_t decksize )
{
for ( size_t i = 0; i < decksize; i++ )
{
int r = rand() % (decksize - i)
int tmp = deck[i+r];
deck[i+r] = deck[i];
deck[i] = tmp;
}
}
Basically, what this does is swap each deck[i] with a randomly chosen element from deck[i] through deck[decksize-1] (meaning the element may remain in place). Assume we have 5 cards. The first time through the loop, i points to the first card. We pick an offset from i at random and call it r:
i --> 1
2
3
4 <-- r
5
We then swap the contents of deck[i] and deck[i+r], and then advance i:
4
i --> 2
3
1
5
We pick another r at random from the remaining elements:
4
i --> 2
3
1
5 <-- r
and do another swap and advance i:
4
5
i --> 3
1
2
Lather, rinse, repeat - by the end of the loop, the array is more-or-less randomly shuffled.
No, there is no way in C to delete an element from an array. Indeed, as far as I know there is no way to delete an element from an array in C++, C# or Java either.
Now, that being the case, you have a few options. You can use a sentinel value in your code to mark an element as absent. You can resize your array to actually shrink it by one and relocate all elements backwards one place whenever an element is deleted.
In your example, either 0 or -1 should serve fine as sentinel values.
First at all, make the array deck static.
Next, introduce another static variable initially equal to the lenght of array=52.
Now when a card at a random position is dealt, it can be swapped with the last card in the deck, indexed with arraysize-1, and the arraysize being decreased.
Making these two variables static allows the function to maintain a state between calls. Of course better techniques would encapsulate these variables in a struct (allowing eg multiple games / resetting the deck).
In short, the problem you're really trying to solve isn't one of deleting an entry in an array.. Rather, it is a more encompassing issue: How to perform repeated random selection from a fixed domain without repeating selected values. The method described above is one way to do that. An example of the latter technique using a 20-slot array is below (the value 20 was chosen for short output lines (easy to read). It could just as easily be 52, 1000, etc.):
Code
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define DECK_SIZE 20
typedef struct Deck
{
int cards[DECK_SIZE];
size_t size;
} Deck;
Deck init_deck()
{
// no shuffle is needed. each selection in draw_card will
// pick a random location in the remaining cards.
Deck deck;
for (int i=0; i<DECK_SIZE; ++i)
deck.cards[i] = i+1;
deck.size = DECK_SIZE;
return deck;
}
int draw_card(Deck *deck)
{
// reset when we run out of cards.
if (deck->size == 0)
{
printf("- reset \n");
deck->size = DECK_SIZE;
}
// generate random location in remaining cards.
// note: susceptible to modulo bias
size_t idx = rand() % deck->size;
// decrement size to consume card and index where
// the card will be swap-stored.
--deck->size;
// swap with last card in remaining cards
int tmp = deck->cards[deck->size];
deck->cards[deck->size] = deck->cards[idx];
deck->cards[idx] = tmp;
// return the drawn card
return deck->cards[deck->size];
}
int main()
{
Deck deck = init_deck();
srand((unsigned)time(NULL));
// draw 300 times. this should reset 15 times, and
// each time a new set of 1..20 should result
for (int i=0; i<300; ++i)
printf("%d ", draw_card(&deck));
fputc('\n', stdout);
}
Output (obviously varies)
7 16 3 20 9 13 6 4 1 12 18 10 14 2 8 17 11 5 15 19 - reset
6 20 14 16 11 2 10 13 4 12 18 5 3 7 19 9 17 8 15 1 - reset
14 1 8 15 13 2 19 16 11 17 5 18 9 12 7 6 3 20 4 10 - reset
18 17 12 2 15 19 1 4 14 10 20 16 9 5 11 13 6 8 3 7 - reset
4 18 5 1 19 16 8 10 9 14 13 17 12 20 7 2 15 6 11 3 - reset
14 16 18 1 5 10 17 3 19 9 8 2 7 13 12 20 4 15 11 6 - reset
16 15 12 13 6 1 17 10 9 7 11 20 8 19 2 18 3 4 14 5 - reset
7 1 8 16 17 5 2 12 13 6 18 20 9 11 14 19 15 3 4 10 - reset
20 13 4 18 7 17 12 15 5 14 2 16 11 3 9 10 1 19 8 6 - reset
5 19 4 17 18 13 8 2 12 7 9 1 11 10 3 14 6 15 16 20 - reset
3 5 10 7 1 15 19 13 16 12 9 8 6 20 4 11 17 18 14 2 - reset
11 14 4 7 15 9 16 18 8 13 12 5 10 19 2 6 20 1 3 17 - reset
10 18 2 4 12 20 14 11 16 13 3 9 8 6 5 7 17 1 15 19 - reset
19 12 20 11 13 9 5 1 10 15 7 2 17 6 3 4 8 14 16 18 - reset
10 3 19 4 6 14 18 11 1 7 9 16 8 13 17 20 2 5 15 12
Notive that on each line, there are twenty selections, and each number in 1..20 appears exactly once per line. How this technique serves you is up to you. A worthy challenge will be how to enumerate the hands held by existing players when a reset (often called a deck-flip) happens. That's an interesting problem to solve, and not one that is as intuitive as it may seem.
Hope it helps.
There are a couple of solutions you could use to solve your problem:
First, is using the vector class, especially the insert and remove functions. here's a good explanation on how it works:
C++ Vectors
Second, which is also my favorite is to use numbers or booleans as indicators. for example, declare a simple boolean array of the same length as your deck. the initial value of all elements would be true. for each card, you'd like to remove from the deck simply change its value to false to indicate it's gone.

Converting from Source-based Indices to Destination-based Indices

I'm using AVX2 instructions in some C code.
The VPERMD instruction takes two 8-integer vectors a and idx and generates a third one, dst, by permuting a based on idx. This seems equivalent to dst[i] = a[idx[i]] for i in 0..7. I'm calling this source based, because the move is indexed based on the source.
However, I have my calculated indices in destination based form. This is natural for setting an array, and is equivalent to dst[idx[i]] = a[i] for i in 0..7.
How can I convert from source-based form to destination-based form? An example test case is:
{2 1 0 5 3 4 6 7} source-based form.
{2 1 0 4 5 3 6 7} destination-based equivalent
For this conversion, I'm staying in ymm registers, so that means that destination-based solutions don't work. Even if I were to insert each separately, since it only operates on constant indexes, you can't just set them.
I guess you're implicitly saying that you can't modify your code to calculate source-based indices in the first place? I can't think of anything you can do with x86 SIMD, other than AVX512 scatter instructions that take dst-based indices. (But those are not very fast on current CPUs, even compared to gather loads. https://uops.info/)
Storing to memory, inverting, and reloading a vector might actually be best. (Or transferring to integer registers directly, not through memory, maybe after a vextracti128 / packusdw so you only need two 64-bit transfers from vector to integer regs: movq and pextrq).
But anyway, then use them as indices to store a counter into an array in memory, and reload that as a vector. This is still slow and ugly, and includes a store-forwarding failure delay. So it's probably worth your while to change your index-generating code to generate source-based shuffle vectors if at all possible.
To benchmark the solution, I modified the code from my other answer to compare the performance of the scatter instruction (USE_SCATTER defined) with a store and sequential permute (USE_SCATTER undefined). I had to copy the result back to the permutation pattern perm in order to prevent the compiler from optimizing the loop body away:
#ifdef TEST_SCATTER
#define REPEATS 1000000001
#define USE_SCATTER
__m512i ident = _mm512_set_epi32(15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0);
__m512i perm = _mm512_set_epi32(7,9,3,0,5,8,13,11,4,2,15,1,12,6,10,14);
uint32_t outA[16] __attribute__ ((aligned(64)));
uint32_t id[16], in[16];
_mm512_storeu_si512(id, ident);
for (int i = 0; i < 16; i++) printf("%2d ", id[i]); puts("");
_mm512_storeu_si512(in, perm);
for (int i = 0; i < 16; i++) printf("%2d ", in[i]); puts("");
#ifdef USE_SCATTER
puts("scatter");
for (long t = 0; t < REPEATS; t++) {
_mm512_i32scatter_epi32(outA, perm, ident, 4);
perm = _mm512_load_si512(outA);
}
#else
puts("store & permute");
uint32_t permA[16] __attribute__ ((aligned(64)));
for (long t = 0; t < REPEATS; t++) {
_mm512_store_si512(permA, perm);
for (int i = 0; i < 16; i++) outA[permA[i]] = i;
perm = _mm512_load_si512(outA);
}
#endif
for (int i = 0; i < 16; i++) printf("%2d ", outA[i]); puts("");
#endif
Here's the output for the two cases (using the builtin time command of tcsh, the u output is user-space time in seconds):
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
14 10 6 12 1 15 2 4 11 13 8 5 0 3 9 7
store & permute
12 4 6 13 7 11 2 15 10 14 1 8 3 9 0 5
10.765u 0.001s 0:11.22 95.9% 0+0k 0+0io 0pf+0w
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
14 10 6 12 1 15 2 4 11 13 8 5 0 3 9 7
scatter
12 4 6 13 7 11 2 15 10 14 1 8 3 9 0 5
10.740u 0.000s 0:11.19 95.9% 0+0k 40+0io 0pf+0w
The runtime is about the same (Intel(R) Xeon(R) W-2125 CPU # 4.00GHz, clang++-6.0, -O3 -funroll-loops -march=native). I checked the assembly code generated. With USE_SCATTER defined, the compiler generates vpscatterdd instructions, without it generates complex code using vpextrd, vpextrq, and vpextracti32x4.
Edit: I was worried that the compiler may have found a specific solution for the fixed permutation pattern I used. So I replaced it with a randomly generated pattern from std::random_shuffe(), but the time measurements are about the same.
Edit: Following the comment by Peter Cordes, I wrote a modified benchmark that hopefully measures something like throughput:
#define REPEATS 1000000
#define ARRAYSIZE 1000
#define USE_SCATTER
std::srand(unsigned(std::time(0)));
// build array with random permutations
uint32_t permA[ARRAYSIZE][16] __attribute__ ((aligned(64)));
for (int i = 0; i < ARRAYSIZE; i++)
_mm512_store_si512(permA[i], randPermZMM());
// vector register
__m512i perm;
#ifdef USE_SCATTER
puts("scatter");
__m512i ident = _mm512_set_epi32(15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0);
for (long t = 0; t < REPEATS; t++)
for (long i = 0; i < ARRAYSIZE; i++) {
perm = _mm512_load_si512(permA[i]);
_mm512_i32scatter_epi32(permA[i], perm, ident, 4);
}
#else
uint32_t permAsingle[16] __attribute__ ((aligned(64)));
puts("store & permute");
for (long t = 0; t < REPEATS; t++)
for (long i = 0; i < ARRAYSIZE; i++) {
perm = _mm512_load_si512(permA[i]);
_mm512_store_si512(permAsingle, perm);
uint32_t *permAVec = permA[i];
for (int e = 0; e < 16; e++)
permAVec[permAsingle[e]] = e;
}
#endif
FILE *f = fopen("testperm.dat", "w");
fwrite(permA, ARRAYSIZE, 64, f);
fclose(f);
I use an array of permutation patterns which are modified sequentially without dependencies.
These are the results:
scatter
4.241u 0.002s 0:04.26 99.5% 0+0k 80+128io 0pf+0w
store & permute
5.956u 0.002s 0:05.97 99.6% 0+0k 80+128io 0pf+0w
So throughput is better when using the scatter command.
I had the same problem, but in the opposite direction: destination indices were easy to compute, but source indices were required for the application of SIMD permute instructions. Here's a solution for AVX-512 using a scatter instruction as suggested by Peter Cordes; it should also apply to the opposite direction:
__m512i ident = _mm512_set_epi32(15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0);
__m512i perm = _mm512_set_epi32(7,9,3,0,5,8,13,11,4,2,15,1,12,6,10,14);
uint32_t id[16], in[16], out[16];
_mm512_storeu_si512(id, ident);
for (int i = 0; i < 16; i++) printf("%2d ", id[i]); puts("");
_mm512_storeu_si512(in, perm);
for (int i = 0; i < 16; i++) printf("%2d ", in[i]); puts("");
_mm512_i32scatter_epi32(out, perm, ident, 4);
for (int i = 0; i < 16; i++) printf("%2d ", out[i]); puts("");
An identity mapping ident is distributed to the out array according to the index pattern perm. The idea is basically the same as the one described for inverting a permutation. Here's the output:
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
14 10 6 12 1 15 2 4 11 13 8 5 0 3 9 7
12 4 6 13 7 11 2 15 10 14 1 8 3 9 0 5
Note that I have permutations in the mathematical sense (no duplicates). With duplicates, the out store needs to be initialized since some elements could remain unwritten.
I also see no easy way to accomplish this within registers. I thought about cycling through the given permutation by repeatedly applying a permute instruction. As soon as the identity pattern is reached, the one before is the inverse permutation (this goes back to the idea by EOF on unzip operations). However, the cycles can be long. The maximum number of cycles that may be required is given by Landau's function which for 16 elements is 140, see this table. I could show that it possible to shorten this to a maximum of 16 if the individual permutation subcycles are frozen as soon as they coincide with the identity elements. The shortens the average from 28 to 9 permute instructions for a test on random permutation patterns. However, it is still not an efficient solution (much slower than the scatter instruction in the throughput benchmark described in my other answer).

MPI IO - MPI_FIle_seek - How to calculate correct offset size for shared file

Update. Now the junk is removed from the end of the shared file, but ther is still som "junk" in the middle of the file where process 0 ends writing and process 1 starts writing:
10 4 16 16 0 2 2 3 1 3 4 2 4 5 1 0 4 6 2 8 5 3 8 10 4 9 5 4 ^#^#^#^#^#^#^#^#^#^#^#^#^#^#^#^#^#^#^#^#^#10 4 16 16 1 2 6 0 3 5 2 2 2 8 1 5 6 5 6 6 4 8 9 7 6 2 1 3 6 4 10 2 5 7 7 6 10 6 5 9 9 10 6 7 5 8
However if i count the the jiberish, i get to 40. When i try to do;
offset = (length-40)*my_rank;
It works, but it is not a very scalable and robust solution. Therfor i need to compute this number for a more generell solution. Does anybody see how can be done, here is my current function:
#define MAX_BUFF 50
int write_parallel(Context *context, int num_procs, int my_rank, MPI_Status status){
int written_chars = 0;
int written_chars_accumulator = 0;
int n = context->n;
void * charbuffer = malloc(n*MAX_BUFF);
if (charbuffer == NULL) {
exit(1);
}
MPI_File file;
MPI_Offset offset;
MPI_File_open(MPI_COMM_WORLD,"test_write.txt",
MPI_MODE_CREATE|MPI_MODE_WRONLY,
MPI_INFO_NULL, &file);
written_chars = snprintf((char *)charbuffer, n*MAX_BUFF, "%d %d %d %d\n", n, context->BOX_SIDE, context->MAX_X, context->MAX_Y);
if (written_chars < 0){ exit(1); }
written_chars_accumulator += written_chars;
int i,j;
for(i=0;i<n;i++){
if(context->allNBfrom[i]>0){
written_chars = snprintf((char *)charbuffer+written_chars_accumulator, (n*MAX_BUFF - written_chars_accumulator), "%d %d %d ", i, context->x[i], context->y[i]);
if (written_chars < 0){ exit(1); }
written_chars_accumulator += written_chars;
for(j=0;j<context->allNBfrom[i];j++){
written_chars = snprintf((char *)charbuffer+written_chars_accumulator, (n*MAX_BUFF - written_chars_accumulator), "%d ", context->delaunayEdges[i][j]);
if (written_chars < 0){ exit(1); }
written_chars_accumulator += written_chars;
}
written_chars = snprintf((char *)charbuffer+written_chars_accumulator, (n*MAX_BUFF - written_chars_accumulator), "\n");
if (written_chars < 0){ exit(1); }
written_chars_accumulator += written_chars;
}
}
int length = strlen((char*)charbuffer);
offset = (length-40)*my_rank; //Why is this correct? the constant = 40 needs to be computet in some way...
//printf("proc=%d:\n%s",my_rank,charbuffer);
MPI_File_seek(file,offset,MPI_SEEK_SET);
MPI_File_write(file,charbuffer,length,MPI_CHAR,&status);
MPI_File_close(&file);
return 0;
}
Her is my current result, with this solution which is also correct: 10 4 16 16 0 2 2 3 1 3 4 2 4 5 1 0 4 6 2 8 5 3 8 10 4 9 5 4 10 4 16 16 1 2 6 0 3 5 2 2 2 8 1 5 6 5 6 6 4 8 9 7 6 2 1 3 6 4 10 2 5 7 7 6 10 6 5 9 9 10 6 7 5 8
But it will not scale because, I dont know how to compute number of jiberish elemtens. Does anybody have a clue ?
If I understand your code your goal is to remove the NULL-chars in between your text blocks. In this parallel writing approach there is no way to solve this without violating the safe boundaries of your buffers. None of the threads now how long the output of the other threads is going to be in advance. This makes it hard (/impossible) to have dynamic ranges for the write offset.
If you shift your offset then you will be writing in a aria not reserved for that thread and the program could overwrite data.
In my opinion there are two solutions to your problem of removing the nulls from the file:
Write separate files and concatenate them after the program is finished.
Post-process your output-file with a program that reads/copy chars form your output-file and skips NULL-bytes (and saves the result as a new file).
offset = (length-40)*my_rank; //Why is this correct? the constant = 40 needs to be computet in some way...
The way you compute this is with MPI_Scan. As others have pondered, you need to know how much data each process will contribute.
I'm pretty sure I've answered this before. Adapted to your code, where each process has computed a 'length' of some string:
length = strlen(charbuffer);
MPI_Scan(&length, &new_offset, 1, MPI_LONG_LONG_INT,
MPI_SUM, MPI_COMM_WORLD);
new_offset -=length; /* MPI_Scan is inclusive, but that
also means it has a defined value on rank 0 */
MPI_File_write_at_all(fh, new_offset, charbuffer, length, MPI_CHAR, &status);
The important feature of MPI_Scan is that it runs through your ranks and applies an operation (in this case, SUM) over all the preceding ranks. Afte r the call, Rank 0 is itself. Rank 1 holds the sum of itself and rank 0; rank 2 holds the sum of itself, rank 1 and rank 0... and so on.

Incorrect output with counting and tallying bits in C

This is only my 2nd programming class. There are 30 rooms. We have to see what is in each room and tally it. I already used the for loop to go through the 30 rooms and I know I have tried to use a bit counter to see what is in each room. I am not getting the correct sample output after I redirect the sample output. When I printf("%d", itemCnt[loc]);, my output is 774778414trolls
When I printf("%d", itemCnt[0]);, my output is 0trolls. I'm just trying to get one output right so I can figure out how to get the rest of the 8 outputs. From the sample output, the first number is supposed to be 6, followed by 6, 1, 4, 4 ... and so on. Below are sample inputs/outputs and what I have so far in code.
Sample input:
1 20 ##
2 21 #A
3 22 ##
4 23 #1
5 22 ##
6 22 ##
7 22 ##
8 22 ##
9 23 #Z Here be trolls � not!
10 23 #+
12 23 ##
13 24 ##
11 22 ##
14 22 #2
15 21 #1
16 20 ##
17 19 ##
18 20 ##
19 19 ##
20 18 ##
21 17 #*
22 16 #*
23 15 #%
0 14 #7
0 gold_bar
1 silver_bar
2 diamond
3 copper_ring
4 jumpy_troll
5 air
6 angry_troll
7 plutonium_troll
Sample Output:
6 gold_bar
6 silver_bar
1 diamond
4 copper_ring
4 jumpy_troll
8 air
15 angry_troll
0 plutonium_troll
code
int main()
{
// contains x and y coordinate
int first, second;
char third[100];
char fourth[100];
char Map[30][30];
// map initialization
for(int x=0; x<30; x++){
for(int y=0; y<30; y++){
Map[x][y] = '.';
}
}
while(scanf("%d %d %s",&first, &second, third) != -1) {
// Condition 1: a zero coordinate
if (first==0 || second==0) exit(0);
// Condition 2: coordinate out of range
if (first<0 || first>30 || second<0 || second>30){
printf("Error: out of range 0-30!\n");
exit(1);
}
Map[second-1][first-1] = third[1];
fgets(fourth, 100, stdin);
// bit counter
int itemCnt[8] = {0}; // array to hold count of items, index is item type
unsigned char test; // holds contents of room.
int loc;
for(loc = 0; loc < 8; loc++) // loop over every bit and see if it is set
{
unsigned char bitPos = 1 << loc; // generate a bit-mask
if((test & bitPos) == bitPos)
++itemCnt[loc];
}
// print the map
for(int h=0; h<30; h++){
for(int v=0; v<30; v++){
printf("%c", Map[h][v]);
}
printf("\n");
}
// print values
printf("%d", itemCnt[0]);
}
return 0;
}
test is not initialized. It looks like you intended to assign 'third[1]' to test.
Also, 774778414 = 0x2E2E2E2E in hex, and 0x2E is the numeric value of ASCII '.', your initial value for map locations. (Tip: when you see wild decimals like that, try Google. I entered, "774778414 in hex" without the quotes.)
I would also suggest breaking down the code into two functions: the first reads from stdin to populate Map (like you do), and the second reads from stdin to populate 8 C strings to describe your objects. It's important to note, the first loop should not go until end of input, because your posted input continues with descriptions, not strictly 3 fields like the beginning.

Read integers from file and ignore whitespace in C

I'm learning C, and part of a program I'm writing in C is to check whether my txt file contains less than or more than 81 values, and if all of the values are integers. I use fscanf to read value from file, but it also reads whitespace. How can I ignore whitespaces and make it read only integers or characters?
My code returns 162, which contains 81 integers and whitespaces.
This is the txt file:
1 2 3 4 5 6 7 8 9
2 3 4 5 6 7 8 9 1
3 4 5 6 7 8 9 1 2
4 5 6 7 8 9 1 2 3
5 6 7 8 9 1 2 3 4
6 7 8 9 1 2 3 4 5
7 8 9 1 2 3 4 5 6
8 9 1 2 3 4 5 6 7
9 1 2 3 4 5 6 7 8
#include<stdio.h>
int main() {
FILE * input_values;
input_values = fopen("text.txt","r");
if (input_values == NULL) {
fprintf(stderr, "Error! Could not open file.\n");
}
int ch, counter = 0;
ch = fscanf(input_values, "%d");
while (ch != EOF) {
counter++;
ch = fscanf(input_values, "%d");
}
printf("num %i",counter);
fclose(input_values);
}
You need to pass in an output variable for fscanf, I'm surprised your code isn't crashing:
int num;
fscanf(input_values, "%d", &num);
It works as expected if you change both your fscanf's

Resources