I have created a simple mode calculator and I am displaying random list - something like this:
12 14 11 10 15 13 16 13 14 14 11 13 16 15 15 15 10 14 13 14 12 13 14 12
The mode value is 6
The mode is 14
. But my problem is I can't get the pair list to show instead of showing the list way - I want to display it this as a item-count pair list :
{2,3}, {4,3}, {5,2}, {3,2}, {1,2}
and the modes are clearly 2 and 4.
can anyone help me solve this issue? thanks for the help.
Here is an image for more details: https://imgur.com/a/FYNcxkv
here is my code:
#include <ctime>
#include <iomanip>
#include <iostream>
#include <string>
#include <random>
using namespace std;
default_random_engine e(static_cast<unsigned>(time(NULL)));
void fill(int a[], int size, int value)
{
for(int i = 0; i < size; i++)
a[i] = value;
}
void randomFill(int a[], int size, int lb, int up)
{
uniform_int_distribution<int> u(lb, up);
for(int i = 0; i < size; i++)
a[i] = u(e);
}
void show(int a1d[], int size)
{
for(int i = 0; i < size; i++)
cout << setw(2) << a1d[i] << ' ';
cout << endl;
}
int count(int a1d[], int size, int value)
{
int vcount = 0;
for(int i = 0; i < size; i++)
if(a1d[i] == value) vcount++;
return vcount;
}
int findLargest(int a1d[], int size)
{
int largest = a1d[0];
for(int i = 1; i < size; i++)
if(a1d[i] > largest) largest = a1d[i];
return largest;
}
/*
the mode of a set of things is that thing that appears the greater number of times in the set
a set may have several modes
*/
int computemodes(int source[], int size, int modes[], int& msize)
{
/*
1. fill the modes array with zeroes
*/
fill(modes, size, 0);
/*
2. store the number of times each source element appears in the modes array.
if an element appears more than once in the source array then its counts appears
more than once the modes array.
source and modes form a parallel array structure
*/
for(int i = 0; i < size; i++)
modes[i] = count(source, size, source[i]);
/*
3. calculate the largest number in the modes array. this number is the number of
times the mode or modes appears in the source array
*/
int modevalue = findLargest(modes, size);
/*
4. assign -1 to the mode array elements that are less than the mode value
now only mode values in the modes array are not equal to -1.
the corresponding elements in the source array are the modes.
*/
for(int i = 0; i < size; i++)
if(modes[i] != modevalue) modes[i] = -1;
/*
5. we use the modes array to identify the source elements that are modes:
any element in the modes array that is not -1 corresponds to a mode in the
source array. if the mode is 1 then every source element is a mode
and no element in the modes array is -1; if the mode is greater than 1 then
a. many modes array entries are -1
b. the number of times a mode appears in the source equals its corresponding modes value
c. the number of modes array entries that are not -1 are the number of times the modes
appear in the source array
the following nested for loop transforms the modes array into an array in which
the first appearance of a mode in the source corresponds to a modes array entry
that is not -1 and subsequent appearances of this mode in the source correspond to
modes array entries that are -1.
*/
for(int i = 0; i < size; i++)
if(modes[i] != -1) //first appearance of the mode in the source
for(int j = i + 1; j < size; j++)
if(source[i] == source[j]) modes[j] = -1;
//subsequent appearances
/*
at this point the usage of the modes array changes.
heretofore, an entry that is not -1 in the modes array is the number of times
a mode appears in the source array. now an entry in the modes array is a mode.
the loop adds modes from the source array to the modes array.
msize serves 2 purposes:
a. it is number of modes copied so far.
b. it is the next free modes array position.
*/
msize = 0;
for (int i = 0; i < size; i++)
if (modes[i] != -1) //first occurrence of a mode in the source
{
modes[msize] = source[i];
msize++;
}
return modevalue;
}
int main()
{
const int size = 24;
int a[size];
int m[size];
randomFill(a, size, 10, 16);
show(a, size);
int msize = 0;
int modevalue = computemodes(a, size, m, msize);
cout << "The mode value is " << modevalue << endl;
if (msize == 1)
cout << "The mode is ";
else
cout << "The modes are ";
show(m, msize);
system("pause");
return 0;
}
You can create your map count with:
template <typename T>
std::map<T, std::size_t> map_count(const std::vector<T>& v)
{
std::map<T, std::size_t> res;
for (const auto& e: v) { res[e]++; }
return res;
}
and from that:
template <typename T>
std::pair<const T, std::size_t> find_mode(const std::map<T, std::size_t>& m)
{
if (m.empty()) {throw std::runtime_error("empty map");}
return *std::max_element(m.begin(),
m.end(),
[](const auto& lhs, const auto& rhs){ return lhs.second < rhs.second; }
);
}
Demo
I would design your code problem something like this:
#include <iostream>
#include <string>
#include <random>
#include <vector>
#include <map>
#include <algorithm> // could be used in your calculate function - algorithm
#include <numeric> // same as above.
class ModeCaclulator {
private:
std::vector<int> generatedNumbers_;
int highestModeCount_;
int highestModeValue;
typedef std::map<int,int> Modes;
Modes allModeCounts_;
public:
ModeCalculator() = default; // default constructor
template<typename T = int> // variadic constructor
ModeCalculator( T&&... t ) : generatedNumbers_{ t... } {
calculateModes();
}
std::vector<int>& getAllNumbers() const { return generatedNumbers_; }
int getHighestModeCount() const { return getHighestModeCount_; }
int getHighestModeValue() const { return getHighestModeValue_; }
Modes getAllModes() const { return allModeCounts_; }
void generateNumbers(int count, int lower, int upper) {
std::random_device rd;
std::mt19937 gen( rd() );
std::uniform_int_distribution<> dis( lower, upper );
for ( int i = 0; i < count; i++ )
generateNumbers_.push_back( dis( gen ) );
}
void calculateModes() {
// This is where you would perform your algorithm
// After doing the proper calculations this is where you would
// save the highestModeValue_ & highestModeCount_ as well as
// populating the vector of maps member.
// In this function you can use local lambdas to find the highest mode count and value.
}
void displayModeInformation() const {
std::cout << Random Values: << '\n';
for ( auto& v : generatedNumbers )
std::cout << v << " ";
std::cout << '\n'
std::cout << "Highest Mode Count: " << highestModeCount_ << '\n';
std::cout << "Highest Mode Value: " << highestModeValue_ << '\n';
std::cout << "\n"
std::cout << "All Mode Count & Value Pairs:\n";
for ( auto& p : allModeCounts_ ) {
std::cout << "{" << p.first << "," << p.second << "}" << " "
}
std::cout << '\n';
}
};
int main() {
ModeCalculator mc;
mc.generateNumbers( 15, 1, 16 );
mc.calculateModes();
mc.displayModeInformation();
// If using variadic constructor
ModeCalculate mc2( 12, 15, 14, 19, 18, 12, 15, 19, 21, 12, 18, 19, 21, 14 );
// no need to call calculateModes() this constructor does that for u
mc2.displayModeInformation();
return 0;
}
This makes the code much more readable, and look how clean main is, and all of the functionality is encapsulated into a single class instead of a handful of floating functions... Internal data is protected or hidden and can only be retrieved through accessor functions. The use of stl containers provides a clean interface instead of the use of C style arrays and also helps to prevent the use of raw pointers, and dynamic memory - via new & delete or new[] & delete[]. It also allows the code to be easier to manage and to debug, and provides a user with a generic reusability.
Related
Below I have attached code for a project that is intended to find the lowest value in a user-inputed vector, return -1 if the vector is empty, and 0 if the vector only has one index. I have run into an issue with the condition in which a vector is empty as the unit test continues to fail the returns_negative_one_for_empty_vector test.
main.cc
#include <iostream>
#include <vector>
#include "minimum.h"
int main() {
int size;
std::cout << "How many elements? ";
std::cin >> size;
std::vector<double> numbers(size);
for (int i = 0; i < size; i++) {
double value;
std::cout << "Element " << i << ": ";
std::cin >> value;
numbers.at(i) = value;
}
double index;
index = IndexOfMinimumElement(numbers);
std::cout << "The minimum value in your vector is at index" << index << std::endl;
}
minimum.cc
#include "minimum.h"
#include <vector>
int IndexOfMinimumElement(std::vector<double> input) {
int i, min_index;
double min_ = input.at(0);
for (int i = 0; i < input.size(); i++) {
if (input.at(i) < min_) {
min_index = i;
return min_index;
}
else if (input.size() == 0) {
return -1;
}
else if(input.size() == 1) {
return 0;
}
}
};
minimum.h
#include <vector>
int IndexOfMinimumElement(std::vector<double> input);
find the lowest value in a user-inputed vector, return -1 if the
vector is empty, and 0 if the vector only has one index.
Instead of writing raw for loops, this can be accomplished much more easily by using the STL algorithm functions.
There are other issues, one being that the vector should be passed by const reference, not by value. Passing the vector by-value incurs an unnecessary copy.
#include <algorithm>
#include <vector>
#include <iostream>
int IndexOfMinimumElement(const std::vector<double>& input)
{
if (input.empty())
return -1;
auto ptrMinElement = std::min_element(input.begin(), input.end());
return std::distance(input.begin(), ptrMinElement);
}
int main()
{
std::cout << IndexOfMinimumElement({ 1.2, 3.4, 0.8, 7.8 }) << std::endl;
std::cout << IndexOfMinimumElement({}) << std::endl; // empty
std::cout << IndexOfMinimumElement({3}) << std::endl; // only 1 element
return 0;
}
Output:
2
-1
0
The relevant functions are std::min_element and std::distance. The std::min_element returns an iterator (similar to a pointer) to the minimum element in the range.
The code is written with a clear understanding of what each function does -- it is practically self-documenting. To get the minimum element, you call std::min_element. To get the distance from the first to the found minimum element, you call std::distance with an iterator to the starting position and an iterator to the ending position.
The bottom line is this: the STL algorithm functions rarely, if ever, fail when given the proper input parameters. Writing raw for loops will always have a much greater chance of failure, as you have witnessed. Thus the goal is to minimize having to write such for loops.
In IndexOfMinimumElement you return on the very first iteration, as all branches of your if/else lead to a return.
If your vector contained {14, 2, 10, 1} the index it would return would be 1, because 2 is less than 14.
Instead, you want to have a couple of conditional checks at the top of your function that return based on the length of the vector.
If the function call gets past those, it should iterate over the values in the vector, checking if they are less than the running minimum value, and update the minimum index accordingly.
int IndexOfMinimumElement(std::vector<double> input) {
if (input.size() == 0) return -1;
if (input.size() == 1) return 0;
int i = 0;
double min = input[0];
int min_idx = 0;
for (auto &v : input) {
if (v < min) {
min = v;
min_idx = i;
}
++i;
}
return min_idx;
}
A minimal test:
int main() {
std::vector<double> foo { 1.2, 3.4, 0.8, 7.8 };
std::cout << IndexOfMinimumElement(foo) << std::endl;
return 0;
}
Prints, as expected:
2
I know how to check if number exist in the array, but not in a 2D array.
Please help me in 2D.
#include<iostream>
using namespace std;
int main()
{
int a[3] = { 4,5,6 };
int b, c;
int x = 1, fact = 1;
cout << "enter no ";
cin >> b;
for (int i = 0; i < 3; i++)
{
if (b == a[i]) {
c = a[i];
break;
}
}
cout << "no entered is present" << endl;
}
I know how to check if number exist in the array, but not in 2D array!
It is like you did for the one-dimensional array, instead of one, you need to now iterate through the rows and column. In another word, you need one more iteration.
#include<iostream>
int main()
{
int a[2][3]{ { 1,2,3 }, { 4,5,6 } };
int userInput = 5;
bool found = false;
for (int row = 0; !found && row < 2; ++row) // if not found and row size < 2
{
for (int col = 0; col < 3; ++col) // if column size < 3
{
if (userInput == a[row][col]) // access the element like this
{
// other codes
std::cout << "No entered is present\n";
found = true;
break;
}
}
}
}
However, using the row size and column size like this, I will not recommend so. You should be using better std::array(if you know the size at compile time), or std::vector(if the sizes are known at run time).
For example, using std::array you could have the following code(example code). Using the range based for-loop, and a simple function makes the code more readable and less error-prone. Also, you need to know the sizes known at compile time. (See live demo)
#include <iostream>
#include <array> // std::array
bool isIn2DArray(const std::array<std::array<int, 3>, 2>& arr, int val) /* noexcept */
{
// range based for-loop instead of index based looping
for (const std::array<int, 3> & row : arr)
for (const int element : row)
if (element == val)
return true; // if found in the array, just return the boolean!
return false; // if not found!
}
int main()
{
std::array<std::array<int, 3>, 2> a{ { { 1,2,3 }, { 4,5,6 } } };
int userInput = 5;
if (isIn2DArray(a, userInput)) // you call the function like this!
{
std::cout << "Found in the array!\n";
}
else
{
std::cout << "Didn't find!\n";
}
}
In case of wondering, how to provide isIn2DArray for any arbitrary array, do it by providing the sizes as non-template parameters as below. (See live demo)
#include <array> // std::array
template<std::size_t Row, std::size_t Col>
bool isIn2DArray(const std::array<std::array<int, Col>, Row>& arr, int val)/* noexcept */
{
// range based for-loop instead of index based looping
for (const std::array<int, 3> & row : arr)
for (const int element : row)
if (element == val)
return true; // if found in the array, just return the boolean!
return false; // if not found!
}
If the array is an actual 2D array, if you know how to check if a number exists in a 1D array, you can use the exact same code to determine if a value exists in a regular 2D array.
The trick is to write the code using pointers to the start and ending elements of the array. The reason why is that a 2D array stores its data in contiguous memory, no different than a 1D array.
Here is an example of the same search function working for both 1-dimensional and 2-dimensional arrays:
#include<iostream>
bool exists(int *start, int *end, int value)
{
while (start != end)
{
if ( value == *start )
return true;
++start;
}
return false;
}
int main()
{
int a[3] = {4,5,6};
bool found = exists(a, a + 3, 5);
if ( found )
std::cout << "The number 5 was found\n";
else
std::cout << "The number 5 was not found\n";
// now a 2d array
int a2[3][4] = {{1,2,3,4},{7,8,9,10},{2,43,2,0}};
found = exists(&a2[0], &a2[2][4], 43);
if ( found )
std::cout << "The number 43 was found\n";
else
std::cout << "The number 43 was not found\n";
found = exists(&a2[0][0], &a2[2][4], 11);
if ( found )
std::cout << "The number 11 was found\n";
else
std::cout << "The number 11 was not found\n";
// Let's try a 3D array for fun
int a3[2][3][4] = {{{1,2,3,4},{7,8,9,10},{2,43,2,0}},
{{6,9,1,56},{4,8,2,10},{2,43,2,87}}};
found = exists(&a3[0][0][0], &a3[1][2][4], 56);
if ( found )
std::cout << "The number 56 was found\n";
else
std::cout << "The number 56 was not found\n";
}
Output:
The number 5 was found
The number 43 was found
The number 11 was not found
The number 56 was found
Surprisingly, the same function worked for 1-dimensional, 2-dimensional arrays, and even 3 dimensional arrays, all due to the data being stored in contiguous memory.
The address of the starting element, and the address of one past the ending element in the array are provided to the function, thus the function knows where to start and where to end the search.
bool check2dArray(vector<vector<int>> mat, int n){
int rows = mat.size();
if (rows==0) return false;
int cols = mat[0].size();
for (int i=0; i<rows; i++){
for (int j=0; j<cols; j++){
if (n == mat[i][j]) return true;
}
}
return false;
}
template <class Matrix, class CheckValue>
bool CheckExists(const Matrix& M, const CheckValue& Value) {
for (const auto& m : M)
for (const auto& v : m)
if (v == Value)
return true;
return false;
}
int main(int, char**)
{
int cArray[10][100]; auto exists = CheckExists(cArray, 10);
std::vector<std::vector<int>> vec; exists = CheckExists(vec, 0);
std::array<std::array<int, 10>, 100> arr; exists = CheckExists(arr, 0);
return 0;
}
I am new to c++ programming and am taking a computational physics class where we are analyzing the problem of percolation on a square lattice using a single-cluster algorithm. My professor has given us some base code, and asked us to modify it as well as write some additional code and scripts within and without this specific program. I have written the majority of the code and scripts necessary to solve and plot this problem, but I am having an issue with my main data output program, specifically that of an infinite loop when I set an input parameter to any value other than 0.
Three main function comprise this program, namely LATTICE::LATTICE, CLUSTER::grow, and CUSTER::print, and also uses a standard Mersenne Twister header file. The heavily modified, commented, and toyed with c++ program is as follows:
#include <fstream>
#include <iostream>
#include <math.h>
#include <string>
#include <sstream>
#include <iomanip>
#include <vector>
#include <cstdlib>
#include "MersenneTwister.h"
using namespace std;
class PARAMS
{
public:
int Nlin; // linear size of lattice
double pr; // probability for a site
double Nclust; // number of clusters in a bin
double Nbin; // number of bins of data to output
int SEED; // seed for mersenne twister
string latt_; // which lattice
PARAMS();//constructor
};
class LATTICE
{
public:
LATTICE(const PARAMS&);//constructor
int Nsite;// number of lattice sites
int Lx,Ly;
vector<vector<int> > nrnbrs;
void print ();
};
class CLUSTER
{
public:
CLUSTER(const PARAMS&, const LATTICE&);//constructor
void grow(const PARAMS&, const LATTICE&, MTRand&);
void meas_clear(const LATTICE&);
void meas(const LATTICE&);
void binwrite(const PARAMS&, const LATTICE&);
//void print(const LATTICE& latt, int index);
void print(const PARAMS& p, const LATTICE& latt);
~CLUSTER();// destructor
//private:
int size;
vector <int> conf;
vector <int> stack;
double pr;
//int stck_pnt,stck_end;
double avg_size;
ofstream dfout;
vector <int> stck_pnt;
vector <int> stck_end;
int z, pnt, prob, val, row, column;
vector< vector< vector <int> > > imax;
};
int main(void)
{
PARAMS p;
LATTICE latt(p);
CLUSTER cluster(p,latt);
MTRand ran(p.SEED);
latt.print();
/*for (int bin=0;bin<p.Nbin;bin++)
{
cluster.meas_clear(latt);
for(int clust=0;clust<p.Nclust;clust++)
{
cluster.grow(p,latt,ran);
cluster.meas(latt);
}
cluster.binwrite(p,latt);
}
*/
cluster.grow(p, latt, ran);
cluster.print(p,latt);
}
PARAMS::PARAMS(){
//initializes commonly used parameters from a file
ifstream pfin;
pfin.open("param.dat");
if (pfin.is_open()) {
pfin >> Nlin;
pfin >> pr;
pfin >> Nclust;
pfin >> Nbin;
pfin >> SEED;
pfin >> latt_;
}
else
{cout << "No input file to read ... exiting!"<<endl;exit(1);}
pfin.close();
// print out all parameters for record
cout << "--- Parameters at input for percolation problem ---"<<endl;
cout <<"Nlin = "<<Nlin<<"; prob. of site = "<<pr<<endl;
cout <<"Number of clusters in a bin = "<<Nclust<<"; Number of bins = "<<Nbin<<endl;
cout <<"RNG will be given SEED of = "<<SEED<<endl;
cout <<"Percolation problem on lattice --> "<<latt_<<endl;
};//constructor
LATTICE::LATTICE (const PARAMS& p)
{
string latt_=p.latt_;
if(p.latt_=="sqlatt_PBC")
{
Lx=p.Nlin;Ly=p.Nlin;
Nsite=Lx*Ly;
int i;
nrnbrs = vector<vector<int> >(Nsite, vector<int>(4));
for (i=0; i<Nsite; i++){
if((i+1) % p.Nlin != 0) nrnbrs[i][0] = i+1;
else nrnbrs[i][0] = i - p.Nlin + 1 ;
if(i + p.Nlin < Nsite ) nrnbrs[i][1] = i+p.Nlin;
else nrnbrs[i][1] = i - (Nsite-p.Nlin);
if(i % p.Nlin > 0) nrnbrs[i][2] = i-1;
else nrnbrs[i][2] = i-1+p.Nlin;
if(i - p.Nlin >= 0) nrnbrs[i][3] = i-p.Nlin;
else nrnbrs[i][3] = i + (Nsite-p.Nlin);
}
}
else if(p.latt_=="sqlatt_OBC")
{
Lx=p.Nlin;Ly=p.Nlin;
Nsite=Lx*Ly;
nrnbrs = vector<vector<int> >(Nsite, vector<int>(0));
for (int i=0; i<Nsite; i++){
if((i+1) % p.Nlin != 0){
nrnbrs[i].push_back(i+1);
}
if(i + p.Nlin < Nsite ){
nrnbrs[i].push_back(i+p.Nlin);
}
if(i % p.Nlin > 0){
nrnbrs[i].push_back(i-1);
}
if(i - p.Nlin >= 0){
nrnbrs[i].push_back(i-p.Nlin);
}
}
}
else
{cout <<"Dont know your option for lattice in param.dat .. exiting"<<endl;exit(1);}
}
void LATTICE::print()
{
//THIS FUNCTIONS MAY BE CALLED DURING DEBUGGING TO MAKE SURE LATTICE HAS BEEN DEFINED CORRECTLY
cout <<"---printing out properties of lattice ---"<<endl;
cout<<"size is "<<Lx<<"x"<<Ly<<endl;
cout <<"neighbors are"<<endl;
for (int site=0;site<Nsite;site++)
{
cout <<site<<" : ";
for (size_t nn=0;nn<nrnbrs.at(site).size();nn++)
cout<<nrnbrs.at(site).at(nn)<<" ";
cout <<endl;
}
cout << endl;
}
CLUSTER::CLUSTER(const PARAMS& p, const LATTICE& latt)
{
conf.resize(latt.Nsite);
stack.resize(latt.Nsite);
pr=p.pr;// store prob in a private member of cluster
dfout.open("data.out");
}
CLUSTER::~CLUSTER()
{
dfout.close();
}
void CLUSTER::grow(const PARAMS& p, const LATTICE& latt, MTRand& ran)
{
conf.resize(latt.Nsite); // Initalize Nsite elements of lattice to 0 in conf
// 0 = Not Asked; 1 = Asked, Joined; 2 = Asked, Refused
for (int i = 0; i < p.Nclust; ++i) { // Iterate for Nclust values
z = ran.randInt(latt.Nsite - 1); // Random integer between 0 and Nsite; Selects first lattice element in the cluster algorithm per Nclus
stck_pnt.resize(0); // Set stck_pnt and stck_end vectors to size 0; Will be filled when iterating through each Nclust
stck_end.resize(0); //-----------------------------------------------------------------------------------------------
//while (conf[z] != 0) { z = ran.randInt(latt.Nsite - 1); } // Iterate through lattice elements until we select one that has not been asked to join
conf[z] = 1; // Set element z in conf to have been asked to join and accepted
stck_pnt.push_back(z); // Add z to both stck_pnt and stck_end
stck_end.push_back(z);
for (int j = 0; j = 3; ++j) { // Add z's nearest neighbors to stck_end; Ignore if already been asked
if (conf[latt.nrnbrs[z][j] == 0]) {
stck_end.push_back(latt.nrnbrs[z][j]);
}
}
pnt = 1; // Initialize pnt for trasnferral of stack_end values to stck_pnt
while (stck_pnt.size() < stck_end.size()) {
stck_pnt.push_back(stck_end[pnt]); // Add pnt element of stck_end to stck_pnt
double prob = ran.rand(); // Get probability value for testing if cluster grows
if (prob <= pr) {
conf[stck_pnt[pnt]] = 1; // Set the current stck_pnt element to joined in conf
for (int j = 0; j = 3; ++j) { // Add z's nearest neighbors to stck_end; Ignore if already been asked
if (find(stck_end.begin(), stck_end.end(), latt.nrnbrs[stck_pnt[pnt]][j]) != stck_end.end()) {
// The given value already exists in stck_end, don't add it again
}
else { // The given value is not contained in stck_end, add it to stck_end
stck_end.push_back(latt.nrnbrs[z][j]);
}
}
}
else {
conf[stck_pnt[pnt]] = 2; // Set the given value to haven been asked and refused in conf
}
++pnt; // Increment pnt; ++p is more efficient then p++ due to lack of copying value
}
}
}
/*
void CLUSTER::print(const LATTICE& latt, int index)
{
stringstream ss;
string file_name;
ss << index << ".clust";
file_name = ss.str();
ofstream clout;
clout.open(file_name.c_str());
clout << "#" << latt.Lx << " x " << latt.Ly << endl;
for (int y = 0; y < latt.Ly; y++)
{
for (int x = 0; x < latt.Lx; x++)
clout << conf[x + y*latt.Lx] << " ";
clout << endl;
}
clout.close();
}
*/
void CLUSTER::print(const PARAMS& p, const LATTICE& latt)
{
//vector< vector< vector<int> > > imax(latt.Lx, vector< vector<int>>(latt.Ly, vector<int>(1)));
// Resize and allocate memeory for imax
//-------------- Row = y-position = i/Lx --------------- Column = x-position = i%Lx ---------------- val = conf[i]
ofstream myFile;
myFile.open("imax.out");
cout << "THe following output was calculated for the input parameters; Recorded to 'imax.out'" << endl;
cout <<"[index]" << "\t" << "[x-position]" << "\t" << "[y-position]" << "\t" << "[conf val]" << endl << endl;
for (int i = 0; i < latt.Nsite; ++i) {
val = conf[i]; // Find color value
row = i / latt.Lx; // Find row number
column = i%latt.Lx; // Find column number
cout << i << "\t" << column << "\t" << row << "\t" << val << endl;
myFile << i << "\t" << column << "\t" << row << "\t" << val << endl;
}
myFile.close();
double size = 0.0; // Initialize size
for (int i = 0; i < latt.Nsite; ++i) {
if (conf[i] == 1) {
size += 1;
}
}
double avg_size = size / p.Nclust; // Find avg_size
}
void CLUSTER::meas(const LATTICE& latt)
{
avg_size+=(double)size;
}
void CLUSTER::meas_clear(const LATTICE& latt)
{
avg_size=0.;
}
void CLUSTER::binwrite(const PARAMS& p, const LATTICE& latt)
{
dfout << avg_size/((double)p.Nclust)<<endl;
}
When I set Nclust=0 in the input file, the code runs as expected and gives the proper output in the file and console. However, when I set Nclust equal to any other value, I get the proper lattice console output but the program hangs for the cluster algorithm. I at first assumed that my computer and algorithm were slow and inefficient and that the program was working in some non-linear time. However, after leaving the program running for around 30 minutes for a 4x4 lattice (only 16 elements in the conf[] vector), no progress had been made and I assumed that the program was stuck in a loop.
After spending several hours going over the CLUSTER::grow() method line-by-line and experimenting with changing various bits of code, I have been unable to resolve where this loop error originates from. I would assume it is somewhere in the while loop that compares the size of stck_pnt and stck_end, but I cannot figure out why or where this is. Any help with this would be very greatly appreciated.
Tl;dr: For Nclust !=0, CLUSTER:grow gets stuck in an infinite loop
You have infinite loop here:
stck_end.push_back(z);
for (int j = 0; j = 3; ++j) { // <======== HERE
and here:
conf[stck_pnt[pnt]] = 1; // Set the current stck_pnt element to joined in conf
for (int j = 0; j = 3; ++j) { // <======== HERE
This should be really simple, but I'm used to higher level languages and am missing something. I'm just trying to make sure the input is five numbers long, and then find the highest number. Unfortunately, something goes wrong in that second part.
#include <iostream>
#include <string>
bool isFiveDigits(int num) {
if (std::to_string(num).length() == 5) {
return true;
} else {
return false;
}
}
int highestInArr(int *nums) {
int highest = nums[0];
for (int i = 1; i < sizeof(nums); i++) {
int temp = nums[i];
if (temp > highest) {
highest = temp;
}
}
return highest;
}
int main() {
using namespace std;
int num;
int nums [5];
cout << "Enter a five digit number!\n";
cin >> num;
if (!isFiveDigits(num)) {
cout << "Not five digits, can you even count?";
return 1;
}
string numstr = to_string(num);
for (int i = 0; i < numstr.length(); i++) {
cout << numstr[i] << " ";
nums[i] = (int)numstr[i];
}
cout << "\n" << highestInArr(nums);
}
When this runs, I get:
Enter a five digit number!
12345
1 2 3 4 5
1424080487
Of course, 1,424,080,487 is not in [1, 2, 3, 4, 5].
You cannot pass a pointer into a function and get the size of it without template deduction. At runtime, all the function receives is a pointer. When you call sizeof(nums), you are not getting the size of the original array. You are simply getting the size of the pointer, which is the same as saying sizeof(int_ptr). Instead, you should be using a std::vector when using collections whose sizes are dynamic.
Now, you CAN receive the size by doing something like this:
#include <iostream>
template<typename num_t, size_t N>
num_t max_num(num_t(&arr)[N]) {
num_t m = (num_t)0;
for (size_t i = 0; i < N; ++i)
if (arr[i] > m)
m = arr[i];
return m;
}
int main(){
int foo[] = { 1, 5, 2, 4, 3 };
int m = max_num(foo);
std::cout << m << std::endl;
std::cin.get();
return 0;
}
However, this is not necessarily preferred and assumes that the array was created on the caller's stack. It does not work for dynamically allocated arrays that were created with new[]. If you do this multiple times with different sizes, you will have multiple implementations of the same function (that's what templates do). The same goes for using an std::array<int, N>. If you use N as a size_t template parameter, it will do the same thing.
There are two preferred options:
Send the size of the array into the function so that the caller is responsible for the size.
Use a different container such as std::vector so the callee is responsible for the size.
Example:
#include <vector>
#include <iostream>
#include <algorithm>
int main(){
std::vector<int> vec{ 1, 5, 2, 4, 3 };
int m = *std::max_element(std::cbegin(vec), std::cend(vec));
std::cout << m << std::endl;
std::cin.get();
return 0;
}
As for the is_5_digits, you should use the base-10 logarithm function.
#include <cmath>
// ...
int i = 12345;
size_t length = (i > 0 ? (int)log10(i) : 0) + 1;
std::cout << length << std::endl; // prints 5;
First of all, you can't simply convert a char to int just like (int)numstr[i] assuming that it will return the digit which it contains.
See, if you have a char '0', it means it's ASCII equivalent is stored, which is 48 in case of 0, 49 in case of '1' and so on.
So in order to get that digit (0,1,2,...,9), you've to substract 48 from the ASCII value.
So change this line:
nums[i] = (int)numstr[i];
to:
nums[i] = (int)numstr[i] - 48; // or nums[i] = (int)numstr[i] - '0';
And another thing, in your highestInArr function, you're getting a pointer as parameter, and in the function, you're using sizeof to determine the size of the array. You can't simply do that, the sizeof will return the size of int*, which is not the size of the array, so you've to pass size as the second argument to the function, and use it in the loop.
Like this:
int highestInArr(int *nums, int size) {
// ...
for (int i = 1; i < size; i++) {
// ...
}
// ...
}
I have a matrix of values (stored as an array of values) and a vector with the matrix dimensions( dims[d0, d1, d2]).
I need to build a string like that:
"matA(j, k, l) = x;"
where j, k, l are the indices of the matrix and x the value of the element. I need to write this for each value of the matrix and for matrices with 2 to n dimensions.
I have a problem isolating the base case and replicating it in a useful way. I did a version in a switch case with a case for each dimension and a number of for cycles equal to the number of dimensions:
for (unsigned int k=1; k<=(dims[2]); k++)
{
for (unsigned int j=1; j<=(dims[1]); j++)
{
for (unsigned int i=1; i<=(dims[0]); i++)
{
strs << matName << "(" << i << "," << j << ","<< k << ")="<< tmp[t]<< "; ";
....
but is not what I wanted.. Any idea for a more general case with a variable number of dimensions?
You need a separate worker function to recursively generate the series of indices and main function which operates on it.
For example something like
void worker(stringstream& strs, int[] dims, int dims_size, int step) {
if (step < dims_size) {
... // Add dims[step] to stringstream. Another if may be necessary for
... // whether include `,` or not
worker(strs, dims, dims_size, step + 1);
} else {
... // Add cell value to stringstream.
}
}
string create_matrix_string(int[] dims, int dims_size, int* matrix) {
... // Create stringstream, etc.
strs << ... // Add matrix name etc.
worker(strs, dims, dims_size, 0);
strs << ... // Add ending `;` etc.
}
The main problem here is the value, since the dimension is not known during compilation. You can avoid that by encoding matrix in single-dimensional table (well, that's what C++ is doing anyway for static multidimensional tables) and call it using manually computed index, eg. i + i * j (for two-dimensional table). You can do it, again, by passing an accumulated value recursively and using it in final step (which I omitted in example above). And you probably have to pass two of them (running sum of polynomial components, and the i * j * k * ... * x product for indices from steps done so far.
So, the code above is far from completion (and cleanliness), but I hope the idea is clear.
You can solve this, by doing i, j and k in a container of the size of dim[] - sample:
#include <iostream>
#include <vector>
template< typename Itr >
bool increment( std::vector< int >& ijk, Itr idim, int start )
{
for( auto i = begin(ijk); i != end(ijk); ++i, ++idim )
{
if( ++*i <= *idim )
return true;
*i = start;
}
return false;
}
int main()
{
using namespace std;
int dim[] = { 5, 7, 2, 3 };
const int start = 1;
vector< int > ijk( sizeof(dim)/sizeof(*dim), start );
for( bool inc_done = true; inc_done
; inc_done = increment( ijk, begin(dim), start ) )
{
// .. here make what you want to make with ijk
cout << "(";
bool first = true;
for( auto j = begin(ijk); j != end(ijk); ++j )
{
if( !first )
cout << ",";
else
first = false;
cout << *j;
}
cout << ")= tmp[t] " << endl;
}
return 0;
}