memory error with heap-sort C++ - c++

So I have written a heap-sort program in C++ which takes in an array of doubles and the size of the array and then sorts it. The program works however when I attempt to pass it arrays larger then 1000 I get "Bus error: 10" I think this has to do with how memory is being allocated, however I can not seem to find a solution.
#ifndef _HEAPSORT_
#define _HEAPSORT_
void Heapsort(double arrayToSort[], int sizeOfArray);
void Heapsort(double arrayToSort[], int sizeOfArray)
{
// Building Heap:
// ==========================
int halfSize = sizeOfArray-1 / 2;
for(int i = halfSize; i >= 0; i--){
double temp = arrayToSort[i];
int I1 = i, I2 = i+i;
do {
if( I2 < sizeOfArray - 1 && arrayToSort[I2+1] > arrayToSort[I2] ) { I2++; }
if( arrayToSort[I2] > temp ){
arrayToSort[I1] = arrayToSort[I2];
I1 = I2;
I2 = I1+I1;
} else {
I2 = sizeOfArray;
}
} while ( I2 < sizeOfArray );
arrayToSort[I1] = temp;
}
// Sorting Heap:
// =========================
for(int i = sizeOfArray-1; i >= 2; i--){ // i is the number of still competing elements
double temp = arrayToSort[i];
arrayToSort[i] = arrayToSort[0]; // store top of the heap
int I1 = 0, I2 = 1;
do {
if((I2+1) < i && arrayToSort[I2+1] > arrayToSort[I2] ) { I2++; }
if(arrayToSort[I2] > temp ){
arrayToSort[I1] = arrayToSort[I2];
I1 = I2;
I2 = I1+I1;
} else {
I2 = i;
}
} while( I2 < i );
arrayToSort[I1] = temp;
}
double Temp = arrayToSort[1];
arrayToSort[1] = arrayToSort[0];
arrayToSort[0] = Temp;
}
#endif /* _HEAPSORT_ */
Any insight into how I can fix this would be greatly appreciated.
Here is the code where I allocate the memory.
#include <iostream>
#include "heapsort.h"
#include "rmaset.h"
#include "ranmar.h"
#include "common.h"
using namespace std;
int main(void)
{
const int size = 1000;
struct Common block;
rmaset(block);
double array[size];
for(int i = 0; i < size; i++){
array[i] = ranmar(block);
}
Heapsort(array,size);
return 0;
}
This just creates a struct which then gets passed to a function which initializes it and then to another function ranmar which populates it with random numbers. I have checked all other functions thoroughly and am sure that the error is coming from the Heapsort function.

In the following line int halfSize = sizeOfArray-1 / 2; the right side is evaluated as sizeOfArray-(1 / 2). The integer division (1 / 2) results in 0 so it initializes halfSize with the value sizeOfArray. You begin the loop off the end of the array. I think you meant to do (sizeOfArray-1) / 2 instead.

Related

Need to add elements of two array together

Adding two integer array elements
if array1 = {0,0,0,0,9,9,9,9}—————> 00009999
and
array2 = {0,0,0,0,0,0,0,1}————————> 00000001
adding the two arrays together should result in 10000 being in array1, since 9999 + 1 = 10000
therefore, the result should be
array1 = {0,0,0,1,0,0,0,0}
Does anyone know how to write a code for this? I was trying to use a while loop which didn't work effectively within another for loop. Fairly new to coding and stack overflow, any help will be appreciated!
CODE THAT I TRIED
Note: both arrays will have the same number of elements, they were initialized with the same size
int length = sizeof(array1)/sizeof(array1[0]);
for(int i = length; i>0; i--){
if(array1[i-1] + array2[i-1] < 10){
array1[i-1] += array2[i-1];
}else{
array1[i-1] = array1[i-1] + array2[i-1] - 10;
if(array1[i-2]!=9){
array1[i-2]++;
} else{
int j = i-2;
while(j == 9){
array1[j] = 0;
j--;
}
array1[j-1]++;
}
}
}
Code below performs base10 arithmetic: you need to iterate the arrays in reverse, do the addition of i-th digit by modulo 10, then carry over any excess digits to the next array element:
#include <iostream>
#include <iterator>
using namespace std;
int main()
{
int a1[] = { 0,0,0,0,9,9,9,9 };
int a2[] = { 0,0,0,0,0,0,0,1 };
const int b = 10;
int s = 0;
for (int i = size(a1) - 1; i >= 0; --i)
{
a1[i] += a2[i] + s;
s = a1[i] / b;
a1[i] %= b;
}
std::copy(a1, a1 + size(a1), ostream_iterator<int>(cout, " "));
cout << endl;
}
Alternative with C arrays and transform algorithm + make_reverse_iterator looks too heavy. Variant with std::arrays looks better:
#include <algorithm>
#include <array>
#include <iterator>
#include <iostream>
using namespace std;
int main()
{
std::array<int, 8> a1 = { 0,0,0,0,9,9,9,9 };
std::array<int, 8> a2 = { 0,0,0,0,0,0,0,1 };
const int b = 10;
int s = 0;
transform(a1.rbegin(), a1.rend(), a2.rbegin(), a1.rbegin(), [b, &s](int &i, int &j)
{
i += j + s;
s = i / b;
return i % b;
});
copy(a1.begin(), a1.end(), ostream_iterator<int>(cout, " "));
cout << endl;
}
It looks like you've overcomplicated the problem a bit. Your task is to perform base 10 addition on two arrays, carrying excess digits. You can simply iterate both arrays in reverse, perform addition on the individual elements, and ensure you carry over a digit when you exceed 10.
Here is an example based on the requirements you've described. You can further abstract this as needed.
I updated this code such that the result is now in array1.
#include <iostream>
int main(int argc, char *argv[], char *argp[]){
/* Initialize arrays and calculate array size */
int array1[] = {0,0,0,0,9,9,9,9};
int array2[] = {0,0,0,0,0,0,0,1};
int array_size = sizeof(array1) / sizeof(int);
/* Iterate the arrays in reverse */
int carry = 0;
for (int i = array_size - 1; i >= 0; i--) {
/* Perform addition on the current elements, remembering to include the carry digit */
int result = array1[i] + array2[i] + carry;
/* Determine if the addition should result in another carry */
if (result >= 10) {
carry = 1;
} else {
carry = 0;
}
/* Store the non-carried addition result */
array1[i] = result % 10;
}
/* View result */
for (int i = 0; i < array_size; i++) {
std::cout << array1[i];
}
std::cout << std::endl;
return 0;
}
uint32_t decode(int array[8]){
uint32_t multiple_of_ten=10000000;
uint32_t result = 0;
for(int i=0;i<8;i++){
result += (array[i] * multiple_of_ten);
multiple_of_ten = multiple_of_ten / 10;
}
return result;
}
int* encode(uint32_t number){
int result[8]={0,0,0,0,0,0,0,0};
uint32_t multiple_of_ten=10000000;
uint32_t recent = number;
for(int i=0;i<8;i++){
if(recent>0 && recent / multiple_of_ten > 0)
{
result[i] = recent / multiple_of_ten;
recent %= multiple_of_ten;
}
multiple_of_ten /= 10;
}
return result;
}
in your case , use encode(decode(array1) + decode(array2))

Weird crashing program while debug runs smoothly (Eclipse C++)

I'm writing a program for my algorithmic math class at university and I'm using Win 7 (x64), Eclipse Oxygen.1a Release (4.7.1a) with MinGW 6.3.0.
Whenever I build and run the program it crashes with windows claiming 'Abgabe3.exe stopped working' but when trying to find the problem using the debugger and breakpoints I step trough the whole program and it finishes without errors...
I stripped everything not used by the problematic function and copied everything into a seperate file and the exact problem occurs.
Maybe somebody has a clue what happened at my side. ^^
#include <math.h> /* pow, sqrt */
#include <iostream> /* cin, cout */
#include <new> /* new */
#include <string> /* string */
#include <stdlib.h> /* srand, rand */
#include <time.h> /* time */
using namespace std;
void NORM(double* res, double* x, int n){
res[0] = 0.0;
for(int i = 0; i < n; i++){
res[0] += pow(x[i], 2);
}
res[0] = sqrt(res[0]);
}
void initRand(double* x, int n){
srand (time(NULL) * rand());
for(int i = 0; i < n; i++){
x[i] = (((double) rand()) / ((double) RAND_MAX));
}
}
void createArray(double* &x, int n){
if (n > 0){
x = new double[n];
initRand(x, n);
}
}
void printArray(double* x, int n){
if (x != NULL){
cout<<"(\n";
for(int i = 0; i < n; i++){
if(i+1 == n) cout<<x[i];
else if ((i % 5) == 0) cout<<x[i];
else if ( ((i+1) % 5) == 0 ){
cout<<", "<<x[i]<<"\n";
}
else {
cout<<", "<<x[i];
}
}
cout<<"\n)\n";
}
else cout<<"\nError: pointer = NULL\n";
}
unsigned long long int bin(unsigned int n, unsigned int k){
unsigned long long res = 1;
if(k == 0) return 1;
else if( n >= k){
for(unsigned long long int i = 1; i <= k; i++){
res *= (n + 1 - i) / i;
}
}
else return 0;
return res;
}
void newArray(double** x, unsigned int v, unsigned int n){
for(unsigned int i = 0; i < v; i++){
double* ptr = x[i];
createArray(ptr,n);
x[i] = ptr;
}
}
void experiment(double** vektorArray){
unsigned int n = 10, v = 20;
cout<<"Dimension n = "<<n<<"\nAnzahl Versuche v = "<<v<<endl;
//Erstellen der Vektoren
cout<<"Erstellen - starte\n";
vektorArray = new double*[n];
newArray(vektorArray, v, n);
cout<<"Erstellen - fertig\n";
for(unsigned int i = 0; i < v; i++){
if(i%10 == 0) printArray(vektorArray[i], n);
}
}
int main(int argc, char** argv){
double** vektorArray = NULL;
experiment(vektorArray);
return 0;
}
vektorArray = new double*[n];
created an array of size n, but
void newArray(double** x, unsigned int v, unsigned int n)
{
for (unsigned int i = 0; i < v; i++)
{
double* ptr = x[i];
createArray(ptr, n);
x[i] = ptr;
}
}
and
for (unsigned int i = 0; i < v; i++)
{
if (i % 10 == 0)
printArray(vektorArray[i], n);
}
index that array with v. Looks like you got your variables crossed. Strongly recommend giving variables better, more descriptive names to help make this more obvious.

Need to insert random numbers of 1-100 into a three dimensional array

I need to create a program in which random numbers between 1 and 100 are placed in each dimension of a 3D array. The arrays are of varying sizes, and thus far have only encountered crashes upon execution. Tried on a smaller scale with a 1D array and got it to work fine. Cant seem to translate on larger scale. My code so far...
int const STOCK_AMOUNT = 1000, DAY_AMOUNT = 366, TIME_AMOUNT = 480;
int randomGenerator();
void randomInsert(int array0[DAY_AMOUNT][TIME_AMOUNT][STOCK_AMOUNT]);
int main()
{
int cube[DAY_AMOUNT][TIME_AMOUNT][STOCK_AMOUNT];
srand((unsigned)time(0));
randomInsert(cube);
return 0;
}
void randomInsert(int array0[DAY_AMOUNT][TIME_AMOUNT][STOCK_AMOUNT])
{
for (int count1 = 0; count1 < DAY_AMOUNT; count1++)
{
for (int count2 = 0; count2 < TIME_AMOUNT; count2++)
{
for (int count3 = 0; count3 < STOCK_AMOUNT; count3++)
{
int randomGenerator();
array0[count1][count2][count3] = randomGenerator();
cout << endl;
}
}
}
}
int randomGenerator()
{
int randNum;
int lowerLimit = 1;
int upperLimit = 100;
randNum = (rand() % upperLimit) + lowerLimit;
return randNum;
}
You seem to be exceeding stack size. your array, created on the stack, holds about 175M integers, that is, about 700MB of memory. You need to setup compilation options to increase the stack size.
EDIT: moreover, please be aware that putting such huge arrays on the stack is generally considered bad practice. Ideally, use STL vectors, that is the modern way to deal with arrays.
Here’s a more complex version using the STL:
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <ctime>
#include <functional>
#include <iostream>
#include <random>
using std::cout;
using std::endl;
// The size of a type that can hold values from 1 to 100. Used for storage. (Copy to int for calculation.)
using elem_t = int_least8_t;
// Lower and upper bounds:
constexpr int lb = 1;
constexpr int ub = 100;
constexpr size_t stocks = 100, days = 300, times = 400;
using pricearray_t = elem_t[days][times][stocks];
pricearray_t& init_prices()
/* Returns a heap-allocated array that must be deleted with delete[]. */
{
// This ugly little cast is brought to us by the C++ rules for array types.
pricearray_t &to_return = *(pricearray_t*) new pricearray_t;
const std::default_random_engine::result_type seed = std::time(NULL) * CLOCKS_PER_SEC + std::clock();
std::default_random_engine generator(seed);
std::uniform_int_distribution<int_fast8_t> distribution( lb, ub );
auto x = std::bind( distribution, generator );
for ( size_t i = 0; i < days; ++i )
for ( size_t j = 0; j < times; ++j )
for ( size_t k = 0; k < stocks; ++k )
to_return[i][j][k] = static_cast<elem_t>(x());
return to_return;
}
int main(void)
{
const pricearray_t &prices = init_prices();
long long int sum = 0;
for ( size_t i = 0; i < days; ++i )
for ( size_t j = 0; j < times; ++j )
for ( size_t k = 0; k < stocks; ++k ) {
const int x = prices[i][j][k];
assert( x >= lb );
assert( x <= ub );
sum += x;
}
cout << "The mean is " << static_cast<double>(sum) / days / times / stocks << "." << endl;
delete[] &prices;
return EXIT_SUCCESS;
}
Here’s a version that uses smart pointers to manage memory automatically:
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <ctime>
#include <functional>
#include <iostream>
#include <memory>
#include <random>
using std::cout;
using std::endl;
// The size of a type that can hold values from 1 to 100. Used for storage. (Copy to int for calculation.)
using elem_t = int_least8_t;
// Lower and upper bounds:
constexpr int lb = 1;
constexpr int ub = 100;
constexpr size_t stocks = 100, days = 300, times = 400;
// The unique_ptr type doesn’t play nicely with arrays of known size.
using pricearray_t = elem_t[][times][stocks];
std::unique_ptr<pricearray_t> init_prices()
/* Returns a managed pointer to an array of uniformly-distributed values.
*/
{
// This smart pointer will use its move constructor to avoid copying the entire array.
std::unique_ptr<pricearray_t> to_return = std::make_unique<pricearray_t>(days);
const std::default_random_engine::result_type seed = std::time(NULL) * CLOCKS_PER_SEC + std::clock();
std::default_random_engine generator(seed);
std::uniform_int_distribution<int_fast8_t> distribution( lb, ub );
auto x = std::bind( distribution, generator );
for ( size_t i = 0; i < days; ++i )
for ( size_t j = 0; j < times; ++j )
for ( size_t k = 0; k < stocks; ++k )
to_return[i][j][k] = static_cast<elem_t>(x());
return to_return;
}
int main(void)
{
/* The contents of the smart pointer will be deleted automatically when it goes out of scope.
*/
const std::unique_ptr<pricearray_t> prices = init_prices();
long long int sum = 0;
for ( size_t i = 0; i < days; ++i )
for ( size_t j = 0; j < times; ++j )
for ( size_t k = 0; k < stocks; ++k ) {
const int x = prices[i][j][k];
assert( x >= lb );
assert( x <= ub );
sum += x;
}
cout << "The mean is " << static_cast<double>(sum) / days / times / stocks << "." << endl;
return EXIT_SUCCESS;
}
It seems the specifications for the original cube provided by the professor were clearly much too large....odd how a professor wouldnt catch that? Scaled back the specs, and now have something that works. The bit in the main is supposed to find the average of the stock price each day(50) for each stock(100).
#include<iostream>
#include<ctime>
#include <cstdlib>
#include <fstream>
using namespace std;
const int STOCK_AMOUNT = 100, DAY_AMOUNT = 50, TIME_AMOUNT = 8;
int randomGenerator();
void priceGenerator(int [STOCK_AMOUNT][DAY_AMOUNT][TIME_AMOUNT]);
int main()
{
ofstream outputFile;
int cube[STOCK_AMOUNT][DAY_AMOUNT][TIME_AMOUNT];
double total;
srand((unsigned)time(0));
priceGenerator(cube);
outputFile.open("Average_Day_Price");
for (int row = 0; row < STOCK_AMOUNT; row++)
{
total=0;
for (int col = 0; col < DAY_AMOUNT; col++)
{
for (int layer = 0; layer < TIME_AMOUNT; layer++)
{
total = cube[row][col][layer];
double average = (total / TIME_AMOUNT);
outputFile << "STOCK Id:" << (row+1) << "--" << "--" << average <<endl:
}
}
}
outputFile.close();
return 0;
}
void priceGenerator(int array0[STOCK_AMOUNT][DAY_AMOUNT][TIME_AMOUNT])
{
int i,y, z;
for ( i = 0; i < STOCK_AMOUNT; i++)
{
for ( y = 0; y < DAY_AMOUNT; y++)
{
for (z = 0; z < TIME_AMOUNT; z++)
{
int randNum;
int lowerLimit = 1;
int upperLimit = 100;
randNum = (rand() % upperLimit) + lowerLimit;
array0[i][y][z] = randNum;
}
}
}
}

Thrust CUDA allocating char * to device_vector of objects

I am having trouble making a deep copy of a host_vector to device_vector. I think that I am having an issue modifying the value of an element stored in a device_vector. You can find a compilable version at the bottom but the code in question is the following (i put stars on the rows that trigger the segmentation fault):
thrust::host_vector<CharArr> hostToSort(size);
thrust::host_vector<long long> hostToSortRow(size);
for(int i =0; i < size; i++){
CharArr sortRow;
sortRow.value = arrayToSort[i];
sortRow.length = strlen(arrayToSort[i]);
hostToSort[i] = sortRow;
hostToSortRow[i] = arrayToSortRow[i];
}
thrust::device_vector<CharArr> deviceArrayToSort =hostToSort;
//thrust::copy(hostToSort.begin(),hostToSort.end(),deviceArrayToSort.begin());
// = ;// (arrayToSort,arrayToSort + size);
thrust::device_vector<long long> deviceArrayToSortRow = hostToSortRow;//(arrayToSortRow,arrayToSortRow + size);
// thrust::sort(deviceArrayToSort.begin(),deviceArrayToSort.end());
for(int i = 0; i < size; i++){
char * hostString = hostToSort[i].value;
int sizeString = strlen(hostString);
char * deviceString = 0;
CharArr * deviceCharArr = (&deviceArrayToSort[i]).get();
cudaMalloc((void **) deviceString,sizeString);
cudaMemcpy(deviceString,hostString,sizeString,cudaMemcpyHostToDevice);
**** deviceCharArr->length = sizeString;
**** deviceCharArr->value = deviceString;
}
What happens is that when we arrive at the actual assignment
deviceCharArr->value = deviceString
It throws a Segmentation Fault error. I am very new to CUDA and apologize if there is an obvious answer but I have not been able to find many examples of people allocating char * on devices.
Complete Compilable version is here
#include <thrust/device_vector.h>
#include <thrust/host_vector.h>
#include <thrust/reduce.h>
#include <thrust/device_vector.h>
#include <thrust/host_vector.h>
#include <thrust/sort.h>
#include <thrust/reduce.h>
typedef struct{
char * value;
int length;
} CharArr;
struct CharArrayCmp{
__host__ __device__
bool operator()(const CharArr & o1, const CharArr & o2) {
return this->compare(o1.value,o1.length,o2.value,o2.length);
}
__host__ __device__ bool compare (const char * src, int lenSrc, const char * dst, int lenDest)
{
int end;
if(lenSrc > lenDest){
end = lenDest;
}else{
end = lenSrc;
}
for(int i = 0; i < end; i++){
if(src[i] > dst[i]){
return false;
}else if(src[i] < dst[i]){
return true;
}
}
if(lenSrc >= lenDest){
return false;
}
return true;
}
};
void sortCharArrayHost(char ** arrayToSort, long long * arrayToSortRow,long long size){
std::cout <<"about to start LongIndex" <<std::endl;
thrust::host_vector<CharArr> hostToSort(size);
thrust::host_vector<long long> hostToSortRow(size);
for(int i =0; i < size; i++){
CharArr sortRow;
sortRow.value = arrayToSort[i];
sortRow.length = strlen(arrayToSort[i]);
hostToSort[i] = sortRow;
hostToSortRow[i] = arrayToSortRow[i];
}
/*thrust::device_vector<CharArr> deviceArrayToSort =hostToSort;
//thrust::copy(hostToSort.begin(),hostToSort.end(),deviceArrayToSort.begin());
// = ;// (arrayToSort,arrayToSort + size);
thrust::device_vector<long long> deviceArrayToSortRow = hostToSortRow;//(arrayToSortRow,arrayToSortRow + size);
// thrust::sort(deviceArrayToSort.begin(),deviceArrayToSort.end());
for(int i = 0; i < size; i++){
char * deviceString = 0;
char * hostString = hostToSort[i].value;
int size = strlen(hostString)*sizeof(char);
int cudaStatus;
CharArr * deviceCharArr = (&deviceArrayToSort[i]).get();
cudaStatus = cudaMalloc((void **) deviceString,size);
cudaStatus = cudaMemcpy(deviceString,hostString,size,cudaMemcpyHostToDevice);
(&deviceArrayToSort[i]).get()->value = "";
}
*/
// thrust::sort_by_key(deviceArrayToSort.begin(),deviceArrayToSort.end(),deviceArrayToSortRow.begin(),CharArrayCmp());
thrust::sort_by_key(hostToSort.begin(),hostToSort.end(),hostToSortRow.begin(),CharArrayCmp());
//copy the contents back into our original array to sort now sorted
// hostToSort = deviceArrayToSort;
for(int i =0; i < size; i++){
arrayToSort[i] = hostToSort[i].value;
}
// thrust::copy(deviceArrayToSortRow.begin(),deviceArrayToSortRow.end(),arrayToSortRow);
thrust::copy(hostToSortRow.begin(),hostToSortRow.end(),arrayToSortRow);
}
void sortCharArrayDevice(char ** arrayToSort, long long * arrayToSortRow,long long size){
std::cout <<"about to start LongIndex" <<std::endl;
thrust::host_vector<CharArr> hostToSort(size);
thrust::host_vector<long long> hostToSortRow(size);
for(int i =0; i < size; i++){
CharArr sortRow;
sortRow.value = arrayToSort[i];
sortRow.length = strlen(arrayToSort[i]);
hostToSort[i] = sortRow;
hostToSortRow[i] = arrayToSortRow[i];
}
thrust::device_vector<CharArr> deviceArrayToSort =hostToSort;
//thrust::copy(hostToSort.begin(),hostToSort.end(),deviceArrayToSort.begin());
// = ;// (arrayToSort,arrayToSort + size);
thrust::device_vector<long long> deviceArrayToSortRow = hostToSortRow;//(arrayToSortRow,arrayToSortRow + size);
// thrust::sort(deviceArrayToSort.begin(),deviceArrayToSort.end());
for(int i = 0; i < size; i++){
char * hostString = hostToSort[i].value;
int sizeString = strlen(hostString);
char * deviceString = 0;
CharArr * deviceCharArr = (&deviceArrayToSort[i]).get();
cudaMalloc((void **) deviceString,sizeString);
cudaMemcpy(deviceString,hostString,sizeString,cudaMemcpyHostToDevice);
deviceCharArr->length = sizeString;
deviceCharArr->value = deviceString;
}
thrust::sort_by_key(deviceArrayToSort.begin(),deviceArrayToSort.end(),deviceArrayToSortRow.begin(),CharArrayCmp());
//copy the contents back into our original array to sort now sorted
for(int i =0; i < size; i++){
arrayToSort[i] = (&deviceArrayToSort[i]).get()->value;
}
thrust::copy(deviceArrayToSortRow.begin(),deviceArrayToSortRow.end(),arrayToSortRow);
}
int main()
{
char ** charArr = new char*[10];
charArr[0] = "zyxw";
charArr[1] = "abcd";
charArr[2] = "defg";
charArr[3] = "werd";
charArr[4] = "aasd";
charArr[5] = "zwedew";
charArr[6] = "asde";
charArr[7] = "rurt";
charArr[8] = "ntddwe";
charArr[9] = "erbfde";
long long * rows = new long long[10];
for(int i = 0; i < 10;i++ ){
rows[i] = i;
}
sortCharArrayHost(charArr,rows,10);
for(int i = 0; i < 10; i++){
std::cout<<"Row is "<<rows[i]<<" String is "<<charArr[i]<<std::endl;
}
charArr[0] = "zyxw";
charArr[1] = "abcd";
charArr[2] = "defg";
charArr[3] = "werd";
charArr[4] = "aasd";
charArr[5] = "zwedew";
charArr[6] = "asde";
charArr[7] = "rurt";
charArr[8] = "ntddwe";
charArr[9] = "erbfde";
for(int i = 0; i < 10;i++ ){
rows[i] = i;
}
sortCharArrayDevice(charArr,rows,10);
for(int i = 0; i < 10; i++){
std::cout<<"Row is "<<rows[i]<<" String is "<<charArr[i]<<std::endl;
}
}
As JackOLantern has already pointed out, this is not acceptable:
// this creates an allocation on the device
thrust::device_vector<CharArr> deviceArrayToSort =hostToSort;
// this takes the (device) address an element and assigns it to a pointer variable
CharArr * deviceCharArr = (&deviceArrayToSort[i]).get();
// this then dereferences a device pointer in host code which is illegal
deviceCharArr->length = sizeString;
In CUDA you are not allowed to dereference a device pointer in host code or vice-versa.
It seems you have the following data sets:
The strings to be sorted
An array of string "handles" consisting of CharArr objects each containing pointer to start of string and length
An array of string indices (i.e. 0, 1, 2, ...)
You want to sort 2, and 3 above, based on 1. Thrust "likes" to have everything in one or 2 vectors, if possible. Let's try the following:
concatenate all strings together into a single char vector.
mark the start index of each string in another int vector. The difference in successive start indices will constitute the length of each string. We'll combine the start and the length of each string into a thrust::tuple for use in the comparator, by using a zip_iterator
sort the "tuple array" (i.e. sort index and length at the same time) using the desired comparison functor. Any necessary rearrangement of other data can be accomplished using the reordered index vector.
If you want a re-ordered string index also (i.e. 0, 1, 2, ...) you can create that vector easily enough and add it as a third element to the tuple to be sorted.
Note that the above approach entirely avoids the use of pointers, which as you've seen can be troublesome to manage between host and device copies of the same data.
Here's a fully worked example:
$ cat t439.cu
#include <thrust/device_vector.h>
#include <thrust/host_vector.h>
#include <thrust/sort.h>
#include <thrust/copy.h>
#define NUM_STRINGS 10
struct stringCmp{
const char * strings;
stringCmp(char * _strings) : strings(_strings) {}
template<typename myTuple>
__host__ __device__
bool operator()(const myTuple & o1, const myTuple & o2) {
int idxSrc = thrust::get<0>(o1);
int lenSrc = thrust::get<1>(o1);
int idxDst = thrust::get<0>(o2);
int lenDst = thrust::get<1>(o2);
int end;
if(lenSrc > lenDst){
end = lenDst;
}else{
end = lenSrc;
}
for(int i = 0; i < end; i++){
if(strings[idxSrc+i] > strings[idxDst+i]){
return false;
}else if(strings[idxSrc+i] < strings[idxDst+i]){
return true;
}
}
if(lenSrc >= lenDst){
return false;
}
return true;
}
};
void sortCharArrayDevice(char ** arr, int *rows, int num_str){
thrust::host_vector<char> h_strings;
thrust::host_vector<int> h_st_idx(num_str);
thrust::host_vector<int> h_len(num_str);
thrust::host_vector<int> h_rows(num_str);
// concatenate strings
// assume no zero length strings
h_st_idx[0] = 0;
for (int i = 0; i < num_str; i++){
int sidx = 0;
while (arr[i][sidx] != '\0'){
h_strings.push_back(arr[i][sidx]);
sidx++;}
h_len[i] = sidx;
if (i < num_str-1) h_st_idx[i+1] = h_st_idx[i] + sidx;
h_rows[i] = rows[i];
}
// copy data to device
thrust::device_vector<char> d_strings = h_strings;
thrust::device_vector<int> d_st_idx = h_st_idx;
thrust::device_vector<int> d_len = h_len;
thrust::device_vector<int> d_rows = h_rows;
// sort on device
thrust::sort(thrust::make_zip_iterator(thrust::make_tuple(d_st_idx.begin(), d_len.begin(), d_rows.begin())), thrust::make_zip_iterator(thrust::make_tuple(d_st_idx.end(), d_len.end(), d_rows.end())), stringCmp(thrust::raw_pointer_cast(d_strings.data())));
thrust::copy(d_rows.begin(), d_rows.end(), rows);
}
int main()
{
char ** charArr = new char*[NUM_STRINGS];
charArr[0] = "zyxw";
charArr[1] = "abcd";
charArr[2] = "defg";
charArr[3] = "werd";
charArr[4] = "aasd";
charArr[5] = "zwedew";
charArr[6] = "asde";
charArr[7] = "rurt";
charArr[8] = "ntddwe";
charArr[9] = "erbfde";
int * rows = new int[NUM_STRINGS];
for(int i = 0; i < NUM_STRINGS;i++ ){
rows[i] = i;
}
sortCharArrayDevice(charArr,rows,NUM_STRINGS);
for(int i = 0; i < NUM_STRINGS; i++){
std::cout<<"Row is "<<rows[i]<<" String is "<<charArr[rows[i]]<<std::endl;
}
}
$ nvcc -arch=sm_20 -o t439 t439.cu
$ ./t439
Row is 4 String is aasd
Row is 1 String is abcd
Row is 6 String is asde
Row is 2 String is defg
Row is 9 String is erbfde
Row is 8 String is ntddwe
Row is 7 String is rurt
Row is 3 String is werd
Row is 5 String is zwedew
Row is 0 String is zyxw
$

<<method name>> was not declared in this scope for a private static method

I saw the thread earlier called " 'name of method' was not declared in this scope", but the answers didn't really help me at all. The method that this is happening for is a private static method. I am attempting to use it within the class, but it won't work. The name of the method is "nthCoeffCatalan". I'm getting the error every time I use it. I don't know if this will help, but I'm using Code::Blocks with wxWidgets and Mingw32 for a compiler.
Here's the .h file:
#ifndef CATALAN_H
#define CATALAN_H
#include <vector>
#include <cstring>
#include <cstdlib>
#include <string>
using namespace std;
class Catalan
{
public:
Catalan(int);
virtual ~Catalan( );
void recursiveRandomGenerator( );
void boltzmannRandomGenerator( );
int rank( );
void unrank(int, int);
void outputBinaryTree( );
void outputDyckPath( );
void outputTriangulation( );
private:
int n;
int catalanObject[];
int max_size;
static int nthCoeffCatalan(int);
};
#endif // CATALAN_H
Here's the .cpp file:
#include <Catalan.h>
#include <math.h>
#include <time.h>
using namespace std;
int catalanObject[] = {};
int n;
int max_size;
Catalan::Catalan(int sz){
n = sz;
//find out the position of the leaf in a tree which is just a node and n-1 right vertices
max_size = 0;
for(int i = 0; i <=n; i++){
max_size += pow(2,i);
}
catalanObject[max_size];
for (int i = 0; i < max_size; i++){
catalanObject[i] = 0;
}
}
Catalan::~Catalan( ){
delete &n;
delete &max_size;
delete catalanObject;
}
void recursiveRandomGenerator( ){
//initialize the random number generator
srand(time(NULL));
int r = n;
int i = 0;
//give the tree a root
catalanObject[i] = 1;
r--;
//decide size of left and right trees
float x = ((float) (rand()%10000))/(10000.0);
int k = -1;
float s = 0;
int a_r = 0;
int b_k = 0;
int c_rk = 0;
//calculate a_r
if (r == 0){
a_r = 1;
}
else{
//calculate [x^r] in B(x)^2
if (r > 1){
for (int j = r/2; j >= 1; j--){
int temp = 0;
if (r%2 == 0 && j == r/2){
temp = nthCoeffCatalan(j);
temp = temp*nthCoeffCatalan(r-j);
}
else{
temp = nthCoeffCatalan(j);
temp = temp*nthCoeffCatalan(r-j);
temp = temp*2;
}
a_r += temp;
}
}
//calculate [x^r] in 2B(x)
a_r += 2*nthCoeffCatalan(r);
}
while (x > s){
k = k + 1;
//calculate b_k
if (k == 0){
b_k = 1;
}
else{
b_k = nthCoeffCatalan(k);
}
//calculate c_rk
if (k == r){
c_rk = 1;
}
else{
c_rk = nthCoeffCatalan(r-k);
}
//re-calculate s
int temp;
temp = (float) b_k;
temp = temp * (float) c_rk;
temp = temp / (float) a_r;
s += temp;
}
}
void boltzmannRandomGenerator( ){
}
int rank( ){
return 0;
}
void unrank(int rnk, int n){
}
void outputBinaryTree( ){
}
void outputDyckPath( ){
}
void outputTriangulation( ){
}
static int nthCoeffCatalan(int n){
int num = 1;
int den = 1;
int retVal = 0;
for(int i = 0; i < n; i++){
num = num*(n+i+1); // runs from n+1 to 2n (=2n!/n!)
den = den*(i+1); // runs from 2 to n (=n!)
}
retVal = num/den;
return retVal;
}
Side Note
Also, as a side note I want to use an array as a class variable but in the constructor, on the line where I initialize the size of the array, my debugger says that the code has no effect. Did I do something wrong?
You are mistakenly providing definitions of global functions, but you actually wanted to define member functions (whose declarations appear in the class definition of Catalan).
So for instance, in your .cpp file:
static int nthCoeffCatalan(int n)
{
// ...
}
Should be:
int Catalan::nthCoeffCatalan(int n)
// ^^^^^^^^^
{
// ...
}
This applies also to other non-static member functions. So for instance (again in your .cpp file) instead of:
void recursiveRandomGenerator( )
{
// ...
}
You should write:
void Catalan::recursiveRandomGenerator( )
// ^^^^^^^^^
{
// ...
}
And so on.
All of your member function definitions should be qualified as belonging to Catalan. So, for example, the definition of recursiveRandomGenerator should actually look like:
void Catalan::recursiveRandomGenerator( ){
// ...
}
Also, you should not put the static keyword before the definition of nthCoeffCatalan. It should look like this:
int Catalan::nthCoeffCatalan(int n){
// ...
}
Your class definition declares a bunch of member functions, including nthCoeffCatalan. In the source file, only two members are defined: the constructor and the destructor. All of the rest of the functions are free functions. You have to mark them as member functions by adding Catalan:: to their names.