I was trying to write a simple Monte Carlo simulation program. To be exact, I wanted to analyze the combat results depending on the varying army sizes on both offense and defense - something in tune of this: http://en.wikipedia.org/wiki/Risk_(game)#Dice_probabilities
Now... Risk II Same time rule offers different kind of challenge: varying army size means different color of dice (which means different distribution function for the numbers) In short, the smaller the size of your army is, the more likely you'll end up with 1s, while the larger the size of your army is, the more likely you'll end up with higher number of rolls.
Since using if statements for all the possible condition was a colossal stupidity at its finest, I tabulated all the possible rolling results in 5x12 array. (12 sides in all of the dice, and 5 varying strength, so you get 5x12)
I thought of carrying out 10000 simulations for each offense/defense combinations but once I realized that would mean over 9 million calculations, I decided to cut it short at 100 per combination.
The following is the code; once I run it, it gives me the Access Violation error. I don't know where I made an error. If there is any advice you could offer, I'd appreciate that too. Thanks in advance.
/* Risk II Combat Result Table
For starter, we shall consider one-direction attack in RISK II
and generate the combat table for use.
Machine: Pentium Dual Core E6600
Ram: 6G
OS: Windows 7
Compiler: Visual Studio 2010
Jimmy Smith, 24-March-2012
*/
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <iostream>
#include <algorithm>
using namespace std;
/* Initializing:
Range legend:
White = 1 ~ 6
Yellow = 7 ~ 12
Orange = 13 ~ 20
Red = 21 ~ 30
Black = 31 ~
First row of Dice array corresponds to white dice, and so on.
*/
int Dice[5][12] = { {1, 1, 1, 1, 2, 2, 2, 3, 3, 4, 5, 6},
{1, 1, 2, 2, 2, 2, 3, 3, 4, 4, 5, 6},
{1, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 6},
{1, 2, 3, 3, 4, 4, 5, 5, 5, 5, 6, 6},
{1, 2, 3, 4, 4, 5, 5, 5, 6, 6, 6, 6} };
int Roll_Index [30]= {0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4};
int main() {
float Table[30][30];
for (int i = 0; i < 30; i ++)
for (int j = 0; j < 30; j ++)
Table [i][j] = 0.0;
int Result[100];
for (int i = 0; i < 100; i++) Result[i] = 0;
float prob = 0.0;
int Atk = 0;
int Def = 0; //Number of attackers and defenders
int A_Ind = 0;
int D_Ind = 0; //Dice side index
int A_Roll_Index = 0;
int D_Roll_Index = 0; //Roll index on both sides
int A_Dice = 0;
int D_Dice = 0; //Roll result
int Damage = 0;
int Sum = 0; //Internal sum
FILE* fp;
//Time for hard core Monte-Carlo shit! 100 simulation for each situation
for (Atk = 0; Atk<30; Atk++) {
for (Def = 0; Def < 30; Def++) {
for (int i = 0; i < 100; i++) {
int Attacker = Atk +1;
int Defender = Def +1;
while((Attacker>0)&&(Defender>0)) {
A_Ind = (int)(rand()*12);
D_Ind = (int)(rand()*12); //The die is cast!
A_Roll_Index = Roll_Index[Attacker-1];
D_Roll_Index = Roll_Index[Defender-1];
A_Dice = Dice[A_Roll_Index][A_Ind];
D_Dice = Dice[D_Roll_Index][D_Ind];
Damage = min(A_Roll_Index, D_Roll_Index) + 1;
if (A_Dice >= D_Dice) {
Defender -= Damage;
if (Defender == 0) Result[i] = 1;
}
else {
Attacker -= Damage;
if (Attacker == 0) Result[i] = 0;
}
}
}
for (int i = 0; i < 100; i++) Sum+=Result[i];
prob = (float)(Sum/100);
Table[Atk][Def] = prob;
}
}
/* open new file for output and write a title */
fp = fopen( "Combat.dat", "w+");
if( NULL == fp ) {
printf( "cannot open file\n" );
return( 0 );
}
for (Atk = 0; Atk < 30; Atk++){
for (Def = 0; Def < 30; Def++)
fprintf(fp, "%16.8f", Table[Atk][Def]);
fprintf (fp, "\n");
}
fclose( fp );
return(EXIT_SUCCESS);
}
Your code
A_Ind = (int)(rand()*12);
D_Ind = (int)(rand()*12);
indicates that you seem to think that rand() returns a number in the range [0,1), which is not the case. Instead, int returns an integer in the range [0, RAND_MAX], so you need something like:
A_Ind = rand() * 12.0 / RAND_MAX;
If your simulation has to be statistically accurate, you are probably better off with a random number generator from the <random> library:
#include <random>
typedef std::mt19937 rng_type;
std::uniform_int_distribution<std::size_t> udist(0, 11);
rng_type rng;
// ...
// seed rng first:
rng.seed(some_seed_value);
// roll dice
std_size_t A_Ind = udist(rng), D_Ind = udist(rng);
Related
For a sequence of numbers a1, a2,...,an, we say that there is a period if 1≤p<n and if it holds that it is ai=ai+p for all values for which this equality makes sense.
For example, the sequence of numbers 1, 3, 1, 4, 2, 1, 3, 1, 4, 2, 1, 3 has period 5, because ai=ai+5 for all values such that both indices i and i+5 are within the allowable range (i.e. for 1 to 7 inclusive). The same sequence also has a period of 10. Next, we say that the sequence of numbers is periodic if it exists at least one number that is the period of that sequence, with the smallest such number being called the base sequence period. If such a number does not exist, the sequence is not periodic. For example, the above the sequence of numbers is periodic with the base period 5, while the sequence of numbers 4, 5, 1, 7, 1, 5 is not periodic.
#include <iostream>
#include <vector>
int period(std::vector<double> vektor) {
int p;
for (int i : vektor) {
for (int j : vektor) {
if (vektor[i] == vektor[j])
p = j;
}
}
return p;
}
int main() {
std::vector<double> vektor{1, 3, 1, 4, 2, 1, 3, 1, 4, 2, 1, 3};
std::cout << period(vektor);
return 0;
}
This should be solved using vector.
Could you help me fix this code? This returns 3 as base period of sequence.
For starters it is unclear why you are using a vector with the value type double instead of the type int when all initializers have the type int.
The function period should accept a vector by constant reference.
The variable p is not initialized. As a result the function can return an indeterminate value.
The range based for loop does not return indices in a container as you think
for (int i : vektor) {
It returns stored in the vector objects of the type double.
So the condition in the if statement
if (vektor[i] == vektor[j])
makes no sense.
The function can look the following way as it is shown in the demonstration program below.
#include <iostream>
#include <vector>
size_t period( const std::vector<double> &v )
{
size_t p = 0;
for (size_t i = 1; !p && i < v.size(); i++)
{
size_t j = 0;
while (j < v.size() - i && v[j] == v[j + i]) ++j;
if ( j + i == v.size() ) p = i;
}
return p;
}
int main()
{
std::vector<double> v = { 1, 3, 1, 4, 2, 1, 3, 1, 4, 2, 1, 3 };
std::cout << period( v ) << '\n';
}
The program output is
5
A prime p is fixed. A sequence of n numbers is given, each from 1 to p - 1. It is known that the numbers in the sequence are chosen randomly, equally likely and independently from each other. Choose some numbers from the sequence so that their product, taken modulo p, is equal to the given number x. If no numbers are selected, the product is considered equal to one.
Input:
The first line contains three integers separated by spaces: the length of the sequence n, the prime number p and the desired value x
(n=100, 2<=p<=10^9, 0<x<p)
Next, n integers are written, separated by spaces or line breaks: the sequence a1, a2,. . ., an
(0 <ai <p)
Output:
Print the numbers from the sequence whose product modulo p is equal to x. The order in which numbers are displayed is not important. If there are several possible answers, print any of them
Example:
INPUT:
100 11 4
9 6 1 1 10 4 9 10 3 1 10 1 6 8 3 3 9 8
10 3 7 7 1 3 3 1 5 2 10 4 1 5 6 7 2 6
2 8 3 3 6 7 6 3 1 5 10 2 2 10 9 6 8 6
2 10 3 2 7 4 3 2 8 6 4 1 7 2 10 8 4 9
7 9 8 7 4 7 3 2 8 2 3 7 1 5 2 10 7 1 8
6 4 10 10 3 6 10 2 1
OUTPUT:
4 6 10 9
My solution:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main()
{
int n,p,x,y,m,k,tmp;
vector<int> v;
cin >> n >> p >> x;
for (int i = 0; i<n; i++){
cin >> tmp;
v.push_back(tmp);
}
sort(v.begin(), v.end());
v.erase(v.begin(), upper_bound(v.begin(), v.end(), 1));
k=-1;
while(1){
k++;
m = 1;
y = x+p*k;;
vector<int> res;
for (int i = 0; i<n; i++){
if (y == 1) break;
if ( y%v[i] == 0){
res.push_back(v[i]);
m*=v[i];
m%=p;
y = y/v[i];
}
}
if (m==x) {
for (int i = 0; i<res.size(); i++){
cout << res[i] << " ";
}
break;
}
}
return 0;
}
In my solution, I used condition (y=x+k*p, where y is the product of numbers in the answer, and k is some kind of natural number). And also iterated over the value k.
This solution sometimes goes beyond the allotted time. Please tell me a more correct algorithm.
I would consider a backtracking routine over the hashed multiset of the input list. Since p is a prime, at any point we can consider if the current multiple, m, has (multiplicative_inverse(m, p) * x) % p in our multiset (https://en.wikipedia.org/wiki/Multiplicative_inverse). If it exists, we're done. Otherwise, try multiplying either by the same number we are currently visiting in the multiset, or by the next one (keep the result of the multiplication modulo p).
Please see comment below for a link to example code in Python. The example you gave has trivial solutions so it would be helpful to have some non-trivial, as well as challenging examples to test and refine on. Please also clarify if more than one number is expected in the output.
You can use dynamic programming approach. It requires O(p) memory cells and O(p*n) loop iterations. There is possible several optimization (to exclude processing input duplicates, or print longest/shortest selection chain). Following is simplest and basic DP-program, demonstrating this approach.
#include <stdio.h>
#include <stdlib.h>
int data[] = {
9, 6, 1, 1, 10, 4, 9, 10, 3, 1, 10, 1, 6, 8, 3, 3, 9, 8,
10, 3, 7, 7, 1, 3, 3, 1, 5, 2, 10, 4, 1, 5, 6, 7, 2, 6,
2, 8, 3, 3, 6, 7, 6, 3, 1, 5, 10, 2, 2, 10, 9, 6, 8, 6,
2, 10, 3, 2, 7, 4, 3, 2, 8, 6, 4, 1, 7, 2, 10, 8, 4, 9,
7, 9, 8, 7, 4, 7, 3, 2, 8, 2, 3, 7, 1, 5, 2, 10, 7, 1, 8,
6, 4, 10, 10, 3, 6, 10, 2, 1
};
struct elm {
int val; // Value
int prev; // from which elemet we come to this
int n; // add loop cound for prevent multiple use same val
};
void printsol(int n, int p, int x, const int *in) {
struct elm *dp = (struct elm *)calloc(p, sizeof(struct elm));
int i, j;
for(i = 0; i < n; i++) // add initial elements into DP array
dp[in[i]].val = in[i];
for(i = 0; i < n; i++) { // add elements, one by one, to DP array
if(dp[in[i]].val <= 1) // skip secondary "1" multipliers
continue;
for(j = 1; j < p; j++)
if(dp[j].val != 0 && dp[j].n < i) {
int y = ((long)j * in[i]) % p;
dp[y].val = in[i]; // current value, for printout
dp[y].prev = j; // reference to prev element
dp[y].n = n; // loop num, for prevent double reuse
if(x == y && dp[x].n > 0) {
// targed reached - print result, by iterate linklist
int mul = 1;
while(x != 0) {
printf(" %d ", dp[x].val);
mul *= dp[x].val; mul %= p;
x = dp[x].prev;
}
printf("; mul=%d\n", mul);
free(dp);
return;
}
} // for+if
} // for i
free(dp);
}
int main(int argc, char **argv) {
printsol(100, 11, 4, data);
return 0;
}
When enumerating all partitions of a positive integer with the following 2 restrictions:
the size of each partition is always PartitionSize
all elements of these partitions are less than or equal to MaxVal, and greater than zero.
...I am faced with a task of numbering/indexing these partitions, in such manner that I can store their indices and later retrieve them to quickly regenerate the elements of one partition from an arbitrary index. The indices do not need to be consecutive.
Q: What would be the best way to go about calculating such partition indices?
The function that generates these partitions is listed below:
void GenPartitions(const unsigned int myInt, const unsigned int PartitionSize, unsigned int MaxVal)
{
if ((MaxVal = MaxPartitionVal(myInt, PartitionSize, MaxVal)) == 0)
return;
unsigned int MinVal = 1;
unsigned int idx_Last = PartitionSize - 1;
unsigned int RightSum = MaxVal; //Sum to the right of the Decrement Point (inclusive)
unsigned int idx_Dec = idx_Last; //The point that needs to be decremented
vector<unsigned int> partition(PartitionSize);
partition[idx_Last] = MaxVal; //Initiallize first partition
do {
unsigned int cur = idx_Dec - 1;
unsigned int LeftRemain = myInt - RightSum - (idx_Dec - 1) * MinVal; //Calculate the remainder to the left
while (LeftRemain > partition[idx_Dec]) //While the remainder is too big to satisfy the left to right ascending ordering.
{
LeftRemain -= partition[idx_Dec] - 1; //
partition[cur--] = partition[idx_Dec];
}
partition[cur] = LeftRemain; //Last remainder
for (unsigned int i = 0; i < cur; i++) //Set the elements where the reminder did not reach.
partition[i] = MinVal;
for (auto d : partition) //DISPLAY THE PARTITON HERE ...or do sth else with it.
std::cout << setw(2) << d << ",";
std::cout << endl;
for (idx_Dec = 0; (idx_Dec < idx_Last) && (partition[idx_Dec] + 1 > partition[idx_Dec + 1]); idx_Dec++); //Find the rising edge
unsigned int val_1stUp = partition[idx_Dec]+1;
for (++idx_Dec; (idx_Dec <= idx_Last) && (val_1stUp > partition[idx_Dec] - 1); idx_Dec++); //Find the falling edge occuring AFTER the rising edge.
if (idx_Dec > idx_Last)
break; //Could not find the falling edge. We are done.
partition[idx_Dec]--; //Decrement at the Decrement Point
//std::cout << setw((idx_Dec*3)+1) << "" << "v" << endl; //Show the Decrement Points
RightSum = 0; //This needs optimization. There is no need to start from the Decrement Point every time. This sum can be adjusted on-the-go, as changes are made to the partition.
for (unsigned int i = idx_Dec; i <= idx_Last; i++) //Calculate the sum to the right of the Decrement Point (inclusive). This needs optimization.
RightSum += partition[i];
} while(true);
}
Note, that this functions generates partitions in which all elements in each partition are ordered from smallest to largest (left to right). This feature cannot become broken.
The ordering between partitions themselves (vertical) is lexicographic. I would not be happy to lose it, but I could live without it.
SAMPLE OUTPUT OF: GenPartitions(20, 4, 10):
1, 1, 8,10
1, 2, 7,10
1, 3, 6,10
2, 2, 6,10
1, 4, 5,10
2, 3, 5,10
2, 4, 4,10
3, 3, 4,10
1, 1, 9, 9
1, 2, 8, 9
1, 3, 7, 9
2, 2, 7, 9
1, 4, 6, 9
2, 3, 6, 9
1, 5, 5, 9
2, 4, 5, 9
3, 3, 5, 9
3, 4, 4, 9
1, 3, 8, 8
2, 2, 8, 8
1, 4, 7, 8
2, 3, 7, 8
1, 5, 6, 8
2, 4, 6, 8
3, 3, 6, 8
2, 5, 5, 8
3, 4, 5, 8
4, 4, 4, 8
1, 5, 7, 7
2, 4, 7, 7
3, 3, 7, 7
1, 6, 6, 7
2, 5, 6, 7
3, 4, 6, 7
3, 5, 5, 7
4, 4, 5, 7
2, 6, 6, 6
3, 5, 6, 6
4, 4, 6, 6
4, 5, 5, 6
5, 5, 5, 5
Also, I purposely elected not to implement this as a recursive function, because of low performance and RAM/stack impact that recursive solutions have for very large partitions (despite their simpler implementations).
Below are the helper functions if anyone wants to compile it.
#include <iostream>
#include <iomanip>
#include <vector>
unsigned int MaxPartitionVal(const unsigned int myInt, const unsigned int PartitionSize, unsigned int MaxVal)
{
if ((myInt < 2) || (PartitionSize < 2) || (MaxVal < 1) || (PartitionSize > myInt) || (myInt > (PartitionSize*MaxVal))) //Sanity checks
return 0;
unsigned int last = PartitionSize - 1;
if (MaxVal + last > myInt)
MaxVal = myInt - last; //It is not always possible to start with the MaxValue. Decrease it to sth possible
return MaxVal;
}
This answer is provided in the hope that it is useful, but without any warranty of being optimal :).
Notations
First, a few typedefs (change as needed):
using iType = uint_fast64_t; // Type of the generated indices.
using pType = unsigned; // Type of the parts in a partition.
using pSize = std::vector<pType>::size_type; // Size of a partition.
Notations:
parts(num, size, max) is the set of integer partitions of num, having size parts inferior or equal to max.
p is an element of parts (a std::vector, so 0 indexed).
getIndex(p, num, size, max) computes the index of p.
getPartition(index, num, size, max) computes the partition of the given index.
Basic idea
Since indices don't have to be consecutive, we can rephrase the problem as such:
getIndex(...) multiplexes (or compresses) multiple integers into a single one.
getPartition(...) demultiplexes (or decompresses) the single integer into the original ones.
A common solution to that is:
multiplexing using consecutives additions & multiplications.
demultiplexing using consecutives euclidian divisions & modulos.
Since we know that each part of a partition verifies 1 <= part && part <= max, a first implementation can be:
iType getIndex(const std::vector<pType>& partition, pType max) {
pSize i = partition.size();
iType result = 0;
while (i > 0) {
i--;
const pType iMin = 1;
const pType iMax = max;
pType part = partition[i];
result = result*(iMax+1-iMin) + (part-iMin);
}
return result;
}
std::vector<pType> getPartition(iType index, pSize size, pType max) {
std::vector<pType> result(size,0);
iType currentIndex = index;
for (pSize i = 0; i < size; i++) {
const pType iMin = 1;
const pType iMax = max;
pType divider = iMax + 1 - iMin;
result[i] = iMin + currentIndex % divider;
currentIndex = currentIndex / divider;
}
return result;
}
Live demo
This works, however computed indices are quite large. The trick to get lower indices is to compute finer values of iMax and iMin at each loop iteration, using the fact that we're working on partitions, not on an aribrary vector in [1;max].
Better compression with range constraints
Adding a self-imposed constraint:
partitions are sorted from largest to lowest part: p[i] >= p[i+1]
We can deduce, for p in parts(num, size, max):
p[0] >= 1 + (num-1) / size
p[0] <= num + 1 - size
Constraints 2 & 3 can be applied recursively to all p[i], by noting that p[1..size-1] is in parts(num-p[0], size-1, p[0])
Therefore we can compute better iMin & iMax, and inject them in the previous implementation:
// !! Requires a sorted partition, from greatest to lowest part.
iType getIndex2(const std::vector<pType>& partition, pType max) {
pSize size = partition.size();
iType result = 0;
pType currentNum = 0;
pSize i = partition.size();
while (i > 0) {
i--;
pType part = partition[i];
currentNum = currentNum + part;
pType iMax = currentNum+1-(size-i); // constraint 3
if (i > 0) {
iMax = std::min<pType>(iMax, partition[i-1]); // constraint 1
} else {
iMax = std::min<pType>(iMax, max);
}
pType iMin = 1+(currentNum-1)/(size-i); // constraint 2
result = result*(iMax+1-iMin) + (part-iMin);
}
return result;
}
std::vector<pType> getPartition2(iType index, pType num, pSize size, pType max) {
std::vector<pType> result(size,0);
iType currentIndex = index;
pType iMax = std::min<pType>(max, num + 1 - size); // constraint 3
pType currentNum = num;
for (pSize i = 0; i < size; i++) {
pType iMin = 1+(currentNum-1)/(size-i); // constraint 2
pType diviser = iMax+1-iMin;
result[i] = iMin + currentIndex % diviser;
currentIndex = currentIndex / diviser;
currentNum = currentNum - result[i];
iMax = std::min<pType>(result[i], currentNum + 1 - (size - i -1)); // constraint 1 & 3 for step (i+1)
}
return result;
}
Live demo
TODO
sanity checks: the provided implementations can go into undefined behaviour if the partition is not sorted, or the partition/index is not valid.
evaluate when iType will be overflowed (and check if it's good enough for you). I don't know how fast the indices grows depending on num,size and max.
I have known java for a while and I was trying to translate a java program i wrote to c++ but the copy function gives an odd result:
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
long gcd2(long a, long b) {
if ( a == 0 )
return b;
return gcd2(b%a,a);
}
long gcd(long nums[]) {
long ans = nums[0];
int len = sizeof(nums);
for (int i = 1; i < len; i++)
ans = gcd2( nums[i] , ans );
return ans;
}
string com(string s) {
s = s+",";
return (","+s);
}
void printa(long array[]) {
for (int i = 0 ; i < sizeof(array); i++)
cout << array[i] << ", ";
cout << "\n";
}
int main()
{
int length;
cin >> length;
long input[length];
for (int i = 0; i < length; i++)
cin >> input[i];
string possible = "";
int ans = 0;
for (int a = 0; a < length; a++) {
for (int b = length; b > a; b--) {
long arr[b-a];
std::copy(input+a,input+b,arr);
printa(arr);
long gcdans = gcd(arr);
if (possible.find( com(gcdans+"") ) == -1 ) {
possible += com(gcdans+"");
ans++;
}
}
}
cout << (ans);
return 0;
}
I give it the input of:
4
9 6 2 4
and it returns:
9, 6, 2, 4, 140725969483488, 4197851, 9, 6,
9, 6, 2, 4197851, 9, 6, 2, 4,
9, 6, 2, 4197851, 9, 6, 2, 4,
9, 4197851, 9, 6, 2, 4, 140725969483488, 4197766,
6, 2, 4, 4197851, 9, 6, 2, 4,
6, 2, 4, 4197851, 9, 6, 2, 4,
6, 4197851, 9, 6, 2, 4, 140725969483488, 4197766,
2, 4, 6, 4197851, 9, 6, 2, 4,
2, 4197851, 9, 6, 2, 4, 140725969483488, 4197766,
4, 4197851, 9, 6, 2, 4, 140725969483488, 4197766,
1
the number at the very end is what i want the program to output at the end, all the numbers above are me test printing the array to see its contents. Basically I am trying to copy a range of the array(for example (2,3,4) from (1,2,3,4,5,6)) But it gives weird numbers like 140725969483488 and 4197766 when the only numbers I input are 9 6 2 4
Variable length arrays is a C++ extension, not standard C++. If your compiler will allow them, then OK. However standard C++ would use an std::vector container which is dynamically sized at runtime, meaning you can initialise them with any size or numbers at runtime, and add anything you want at runtime.
Also note when passing an array in C++ to functions which take an array argument always (with the exception of explicitly declared sized reference to an array) gets passed as a pointer, so you can't know the size of the array once passed as an argument. So this:
void printa(long array[])
{
for (int i = 0 ; i < sizeof(array); i++) {}
// At this point of the code the sizeof(array) will return the size of
// a pointer, usually 4 or 8 bytes.
// It's a quirk that this happens, and is a holdover from C.
}
By taking an argument of std::vector you can know the size of the array. You can take the argument by value or by reference or pointer.
void printa(const std::vector<long>& array)
{
for (int i = 0 ; i < array.size(); i++)
{
cout << array[i] << ", ";
cout << "\n";
}
}
This is the better way to do it. If you want to use a C array or raw array the way you did, you will have to pass both the array and the size of the array as separate arguments.
Also, about the variable length array extension feature, I'm not sure whether it is reliable or not because I've never used the extension. Again, standard C++ requires that size of arrays are constant values, (known at compile time). Edit: actually (known at compile-time) is a bad description because:
int main()
{
int num = 6;
int myarray[num]; // In standard C++ this won't compile
//but
const int num = 6;
int myarray[num]; // Will
}
And one last thing, as SolutionMill pointed out, even if the sizeof(array) does give the right size and not the size of a pointer, it is the size given in bytes, not the number of elements, which was not you were wanting in:
for (int i = 0 ; i < sizeof(array); i++)
If the array is of 2 elements of 32 bit int, then the sizeof() operator will return size 8. A common but by no means pretty way to get the number of elements in an array is something like sizeof(array) / sizeof(array[0])
Given some input keys and values, I am trying to count how many consecutive values with the same key exist. I will give an example to make this more clear.
Input keys: { 1, 4, 4, 4, 2, 2, 1 }
Input values: { 9, 8, 7, 6, 5, 4, 3 }
Expected output keys: { 1, 4, 2, 1 }
Expected output values: { 1, 3, 2, 1 }
I am trying to solve this problem on a GPU using CUDA. The reduction capabilities of the Thrust library seemed like a good solution for this and I got to the following:
#include <thrust/reduce.h>
#include <thrust/functional.h>
struct count_functor : public thrust::binary_function<int, int, int>
{
__host__ __device__
int operator()(int input, int counter)
{
return counter + 1;
}
};
const int N = 7;
int A[N] = { 1, 4, 4, 4, 2, 2, 1 }; // input keys
int B[N] = { 9, 8, 7, 6, 5, 4, 3 }; // input values
int C[N]; // output keys
int D[N]; // output values
thrust::pair<int*, int*> new_end;
thrust::equal_to<int> binary_pred;
count_functor binary_op;
new_end = thrust::reduce_by_key(A, A + N, B, C, D, binary_pred, binary_op);
for (int i = 0; i < new_end.first - C; i++) {
std::cout << C[i] << " - " << D[i] << "\n";
}
This code is pretty similar to an example from the Thrust documentation. However, instead of the plus operation, I am trying to count. The output from this code is the following:
1 - 9
4 - 7
2 - 5
1 - 3
However, I would expected the second column to contain the values 1, 3, 2, 1. I think the counts are off because the reduction starts with the first value it finds and does not apply the operator until it has a second value, but I am not sure this is the case.
Am I overlooking something about the reduce_by_key function that could solve this problem or should I use a completely different function to achieve what I want?
For your use case you don't need the values of B, the values of D are only dependent on the values of A.
In order to count how many consecutive values are in A you can supply a thrust::constant_iterator as the input values and apply thrust::reduce_by_key:
#include <thrust/reduce.h>
#include <thrust/functional.h>
#include <iostream>
#include <thrust/iterator/constant_iterator.h>
int main()
{
const int N = 7;
int A[N] = { 1, 4, 4, 4, 2, 2, 1 };
int C[N];
int D[N];
thrust::pair<int*, int*> new_end;
thrust::equal_to<int> binary_pred;
thrust::plus<int> binary_op;
new_end = thrust::reduce_by_key(A, A + N, thrust::make_constant_iterator(1), C, D, binary_pred, binary_op);
for (int i = 0; i < new_end.first - C; i++) {
std::cout << C[i] << " - " << D[i] << "\n";
}
return 0;
}
output
1 - 1
4 - 3
2 - 2
1 - 1