+1I have a 2D array in which I need to calculate the mean/average and variance. Problem is that when I do it, I get number bigger than I should. IE: My max value in my 2D array is 256 however I can end up with averages as high as 303.
As such, it is clear that I am calculating mean and variance incorrectly. Can someone tell me where I am going wrong here? Code in entirety below.
Here is one of the files if you would like to try and compile and see the results: http://shawndibble.com/baboon.pgma
#include <cstdlib>
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
const int THRESHOLD = 2048; //random threshold variable to determine when to replace a row.
void optimizeImage(int (*imageFile)[512], int mincol, int maxcol, int row) {
int sum, average;
double temp, variance, elements;
elements = (maxcol-mincol+1)*row;
if(mincol != maxcol) { // if maxcol and mincol are the same. We are on a single row & don't need to do anything.
// Figure out average
for (int i = mincol; i < maxcol; i++) {
for (int j = 0; j < row; j++) {
sum += imageFile[i][j];
}
}
average = sum / elements;
// figure out variance
for (int i = mincol; i < maxcol; i++) {
for (int j = 0; j < row; j++) {
temp += (imageFile[i][j] - average) * (imageFile[i][j] - average);
}
}
variance = temp / elements; //calculate variance
//cout << "var: " << variance << " thresh: " << THRESHOLD << endl;
cout << "rows : " << maxcol-mincol+1 << " | average: " << average << endl;
// if threshold is higher than variance, replace entire row with average
if(THRESHOLD >= variance) {
for(int i = mincol; i < maxcol; i++) { // if quad variance is < THRESHOLD, write whole quad to output array
for (int j = 0; j < row; j++) {
imageFile[i][j] = average;
}
}
cout << "run average" << endl;
// otherwise break in half and repeat.
} else {
int mid = ((maxcol+mincol)/2) ;
optimizeImage(imageFile, mincol, mid, row);
optimizeImage(imageFile, mid+1 , maxcol, row);
}
}
}
int main() {
ifstream inFile;
inFile.open ("baboon.pgma");
if (!inFile) {
cout << inFile << " is a not working for me.";
} else {
//time to read the file,
string line1, line2;
int row, col, maxval;
getline (inFile, line1);
getline (inFile, line2);
inFile >> row;
inFile >> col;
inFile >> maxval;
int imageFile [512][512];
// read each integer and place it into a 2D array
for (int i=0; i < col ; i++) {
for (int j=0; j<row; j++){
inFile >> imageFile[i][j];
}
}
inFile.close();
ofstream dataOut;
dataOut.open ("BaboonOptimized.pgma");
dataOut << line1 << endl << line2 << endl << row << " " << col << endl << maxval << endl;
optimizeImage(imageFile, 0, col, row);
for (int i=0; i < col ; i++) {
for (int j=0; j<row; j++){
dataOut << imageFile[i][j] << " ";
}
}
dataOut.close();
}
return 0;
};
You have not initialized sum and temp.
Related
I've been struggling on this for about an hour now so I'm turning to the almighty entity that is the internet for assistance.
I'm trying to write a program that will A) read a matrix from a txt file in the following format where the first number is the columns (4) and the second number is the rows(3) in the matrix. And each row of numbers corresponds to a row in the matrix.
4 3
1 2 3 4
0 1 2 7
4 1 9 2
and B) calculate the number of ones in the matrix. So the above example would return 3. My code is below.
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
void count_ones(int matrix[][], int rows, int columns)
{
int count = 0;
for(int i = 0; i < rows; i++)
{
for( int j = 0; j < columns; j++)
{
if( matrix[i][j] == 1)
{ count++;}
}
}
cout << "There are " << count << " ones in this matrix.";
}
int main(int argc, char* argv[])
{
int rows, columns;
string file_name = argv[1];
ifstream reader("m1.txt");
reader >> columns;
reader >> rows;
int matrix[rows][columns];
for(int i = 0; i < rows; i++)
{
for(int j = 0; j < columns; j++)
{
reader >> matrix[i][j];
}
}
cout << columns << " " << rows;
cout << endl;
for( int k = 0; k < rows; k++) {
for( int l = 0; l < columns; l++)
cout << matrix[k][l] << " ";
cout << endl;
reader.close();
count_ones(matrix, rows,columns);
return 0;
}
}
Right now I have two issues. The code i'm using to print the matrix I'm reading from the "m1.txt" file is only printing the first two lines and I have absolutely no clue what could be causing this but I'm guessing it has something to do with my ifstream reader.
4 3
1 2 3 4
Secondly, I'm getting a bunch of errors I don't understand when I try to pass my matrix to my count_ones function. I'm not very good with C++ so I would appreciate all the help I can get.
In a comment, you asked
Does anyone have a better way to pass the matrix to the count_ones method?
Don't use
int matrix[rows][columns];
This is not standard C++. It is supported by some compilers as an extension.
Use
std::vector<std::vector<int>> matrix;
You can initialize it with the correct sizes for rows and columns using
std::vector<std::vector<int>> matrix(rows, std::vector<int>(columns));
Change the declaration of count_ones to accept a std::vector<std::vector<in>>.
int count_ones(std::vector<std::vector<in>> const& matrix);
Update its implementation accordingly.
Suggestion for improvement
You can avoid the error of putting the closing } in the wrong place by using helper functions to write the matrix to cout.
std::ostream& operator<<(std::ostream& out, std::vector<int> const& row)
{
for ( int item : row )
out << item << " ";
return out;
}
std::ostream& operator<<(std::ostream& out, std::vector<std::vector<int>> const& matrix)
{
for ( auto const& row : matrix )
out << row << std::endl;
return out;
}
and then use
std::cout << matrix;
in main.
You have done a mistake in the last for loop.
for( int k = 0; k < rows; k++) {
for( int l = 0; l < columns; l++)
cout << matrix[k][l] << " ";
cout << endl;
reader.close();
count_ones(matrix, rows,columns);
return 0;
}
}
It should be like this
for( int k = 0; k < rows; k++) {
for( int l = 0; l < columns; l++)
cout << matrix[k][l] << " ";
cout << endl;
}
reader.close();
count_ones(matrix, rows,columns);
return 0;
}
Because of this the outer for loop in your code runs only once and prints only first row of matrix.
Edit:
Some more things to correct. You can not use matix[][] as a function parameter, it will through the error multidimensional array must have bounds for all dimensions except the first
You can use double pointer for this work. Change the check ones function declaration to this
void count_ones(int **matrix, int rows, int columns)
replace
int matrix[rows][columns];
with
int **matrix = (int **)malloc(sizeof(int *)*columns);
for(int i=0; i < columns; i++)
*(matrix + i) = (int *)malloc(sizeof(int)*rows);
and the code should work like a charm. And also remove this line, its redundant as file_name is not being used.
string file_name = argv[1];
So, I don't know what the errors are until you post them, but I have an idea why your output is cut off prematurely.
So, to recap, let's look at your code again (the relevant part":
cout << columns << " " << rows;
cout << endl;
for( int k = 0; k < rows; k++) {
for( int l = 0; l < columns; l++) /* { */
cout << matrix[k][l] << " ";
/* } */
cout << endl;
reader.close();
count_ones(matrix, rows,columns);
return 0;
}
I've indented it so it's easier to read as well as added the comment braces, just so it's clearer what is getting executed by what.
And now, the output:
4 3
1 2 3 4
Okay, now let's break down what's happening.
cout << columns << " " << rows;
cout << endl;
This is creating the line:
4 3
So far so good, right?
Now, we enter the lop:
for( int k = 0; k < rows; k++) {
for( int l = 0; l < columns; l++) /* { */
cout << matrix[k][l] << " ";
/* } */
cout << endl;
and get this:
1 2 3 4
This must be the first line of the matrix.
More code executes:
reader.close();
count_ones(matrix, rows,columns);
which isn't relevant to your problem.
And now this:
return 0;
}
Whoops! We've just left the function by calling return.
The loop will no longer execute because we've terminated it prematurely by returning, only outputting the first line of the matrix.
Solution: Just move the return statement outside the loop like so:
cout << columns << " " << rows;
cout << endl;
for( int k = 0; k < rows; k++) {
for( int l = 0; l < columns; l++) /* { */
cout << matrix[k][l] << " ";
/* } */
cout << endl;
reader.close();
count_ones(matrix, rows,columns);
}
return 0;
And that should fix the problem.
Finally, some friendly advice, take Sami Kuhmonen's advice and indent your code. It makes it easier to read and catch things like this.
EDIT: One more point, as R.k. Lohana mentioned, you probably want to pull these lines out of the loop too:
reader.close();
count_ones(matrix, rows,columns);
Like so:
for( int k = 0; k < rows; k++) {
for( int l = 0; l < columns; l++) /* { */
cout << matrix[k][l] << " ";
/* } */
cout << endl;
}
reader.close();
count_ones(matrix, rows,columns);
return 0;
Since you probably only want to do them once and not multiple times.
After running this code , it will generate a random array of desired rows and columns . Then a loop will divide the array by its diagonal into an upper side and lower side.In the upper side the loop will look for a max number and in the lower side the loop will look for a min number . Then in the final stage I need to change the positions of min and max . Max in place of min and vice versa.The code runs and finds the min and max.Don't know how to change their places.
Code
#include <iostream>
#include <time.h>
#include <limits.h>
using namespace std;
int main(){
int rows, columns;
int max = INT_MAX;
int min = INT_MIN;
int XindexOfMax, YindexOfMax;
int XindexOfMin, YindexOfMin;
cout << "Enter rows: ";
cin >> rows;
cout << "Enter columns: ";
cin >> columns;
int **array = new int *[rows]; //generating random array
for(int i = 0; i < rows; i++)
array[i] = new int[columns];
srand((unsigned int)time(NULL)); //generating randoms
for(int i = 0; i < rows; i++){ //loop for the main array
for(int j = 0; j < columns; j++){
array[i][j] = rand() % 10;
cout << array[i][j] << " ";
}
cout << "\n";
}
cout << "For finding Max: " << endl;
for(int i = 0; i < rows; i++){ //upper half of the diagonal
for(int j = 0; j < columns - i; j++){
cout << array[i][j] << " ";
if(array[i][j] > max){
max = array[i][j];
XindexOfMax = i; //find x and y coordinates if max
YindexOfMax = j;
}
}
cout << "\n";
}
cout << "For finding Min: " << endl;
for (int i = 0; i < rows; i++){ // lower half of the diagonal
for (int j = 0; j < columns; j++){
if (j < columns - i - 1){
cout << " ";
}
else{
cout << array[i][j] << " ";
if(array[i][j] < min){
min = array[i][j];
XindexOfMin = i; //find x and y coordinates if min
YindexOfMin = j;
}
}
}
cout << "\n";
}
cout << "Result" << endl;
//swapping positions of min and max
std::swap(array[XindexOfMax][YindexOfMax], array[XindexOfMin][YindexOfMin]);
for(int i = 0; i < rows; i++){
for(int j = 0; j < columns; j++){
cout << array[i][j] << " "; //Printing the final array
}
cout << "\n";
}
return 0;
}
In addition to the min and max values, you need to remember the indizes where you found min and max, respectively. Then you can exchange the values (either manually or by using std::swap).
BTW: you need to initialize max and min with INT_MIN and INT_MAX, respectively, and not the other way around.
So it needs to be
int max = INT_MIN;
int min = INT_MAX;
Otherwise, if you write int max = INT_MAX, then no comparison like if(array[i][j] > max) will ever evaluate to true, since there is no integral value greater than INT_MAX.
The swapping is done at the end of main() using std::swap().
I broke a couple of routines into functions. The answer would be improved by breaking out more functions so that each function performs a single task. Still, I added a class, yet tried to stay true to your original design for printing the triangle halves. Hope you can handle some classes at this point.
#include <iostream>
#include <time.h>
#include <limits.h>
#include <cmath>
using namespace std;
class Point {
public:
Point(int x, int y, int value) : x(x), y(y), value(value) {}
int X() { return x; }
int Y() { return y; }
int Value() { return value; }
void SetValue(int valueArg) { value = valueArg; }
void SetPoint(int xArg, int yArg, int valueArg) {
x = xArg;
y = yArg;
value = valueArg;
}
string to_string() {
return std::to_string(value);
}
private:
int x;
int y;
int value;
};
void PrintArray(int **array, int rows, int columns) {
for (int i = 0; i < rows; i++) {
for (int j = 0; j < columns; j++) {
cout << array[i][j] << " ";
}
cout << "\n";
}
}
int main() {
int rows, columns;
cout << "Enter rows: ";
cin >> rows;
cout << "Enter columns: ";
cin >> columns;
int **array = new int *[rows]; //generating random array
for (int i = 0; i < rows; i++)
array[i] = new int[columns];
srand((unsigned int) time(NULL));
for (int i = 0; i < rows; i++) {
for (int j = 0; j < columns; j++) {
array[i][j] = rand() % 10; //generating randoms
}
}
PrintArray(array, rows, columns);
Point maxPoint = Point(0, 0, INT_MIN); // initialize max
Point minPoint = Point(0, 0, INT_MAX);;
cout << "For finding Max: " << endl;
for (int i = 0; i < rows; i++) { //separating the upper half
for (int j = 0; j < columns - i; j++) {
if (j > columns - i) {
cout << array[i][j] << " ";
} else {
cout << array[i][j] << " ";
if (array[i][j] > maxPoint.Value()) {
maxPoint.SetPoint(i, j, array[i][j]);
}
}
}
cout << "\n";
}
cout << "For finding Min: " << endl;
for (int i = 0; i < rows; i++) { //separating the lower half
for (int j = 0; j < columns; j++) {
if (j < columns - i - 1) {
cout << " ";
} else {
cout << array[i][j] << " ";
if (array[i][j] < minPoint.Value()) {
minPoint.SetPoint(i, j, array[i][j]);
}
}
}
cout << "\n";
}
cout << "array before: " << endl;
PrintArray(array, rows, columns);
cout << "Swapping " << "maxPoint(" << maxPoint.X() << ", " <<
maxPoint.Y() << ") with minPoint("
<< minPoint.X() << ", " << minPoint.Y() << ")" << endl;
std::swap(
minPoint.GetCellReference(array),
maxPoint.GetCellReference(array));
PrintArray(array, rows, columns);
return 0;
}
As mentioned in one of the comments, std::swap() is one method of performing a swap. I have modified the example to use std:swap() at the end of main();
Earlier I asked how to export a 2D array with random numbers as the data.
Link: Converting 2D array to text using c++ functions
Now I'm trying to write a separate program that can calculate the average of each column of that array.
But now I'm having issues with "uninitialized variables" that I'm pretty sure are initialized.
Not really sure what to do from here. Any help would be appreciated!
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
using namespace std;
int main ()
{
string Data, FileName;
int row, col, x, y;
float Matrix[50][50], sum, average;
cout << "Enter the name you gave the matrix file.\n";
cout << "(DO NOT INCLUDE ANY SPACES OR EXTENSIONS!)\n";
cin >> FileName;
FileName = "C:\\Users\\Public\\Documents\\" + FileName + ".ascii";
ifstream Fin(FileName);
if (Fin.is_open())
{
row=0;
while(!Fin.eof())
{
getline(Fin, Data);
stringstream ss(Data);
col=0;
while(ss >> Matrix[row][col])
{
col++;
}
row++;
}
Fin.close();
}
else
cout << "Unable to open file";
for (int y = 0; y < col; y++)
{
for (int x = 0; x < row; x++)
{
sum = sum + Matrix[x][y];
}
average = sum / row;
cout << average << " for column " << col << "\n";
}
system("pause");
return 0;
}
UPDATE:
Solved the "uninitialized variables" error.
But now get "-nan(ind)" when I try to calculate the average.
Here's the new code...
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
using namespace std;
int main ()
{
string Data, FileName;
int row, col;
float Matrix[50][50], sum, average;
sum = 0;
cout << "Enter the name you gave the matrix file.\n";
cout << "(DO NOT INCLUDE ANY SPACES OR EXTENSIONS!)\n";
cin >> FileName;
FileName = "C:\\Users\\Public\\Documents\\" + FileName + ".ascii";
ifstream Fin(FileName);
if (Fin.is_open())
{
row=0;
while(!Fin.eof())
{
getline(Fin, Data);
stringstream ss(Data);
col=0;
while(ss >> Matrix[row][col])
{
col++;
}
row++;
}
Fin.close();
}
else
cout << "Unable to open file";
for (int y = 0; y < row; y++)
{
for (int x = 0; x < col; x++)
{
sum = sum + Matrix[x][y];
}
average = sum / col;
cout << average << "\n";
}
system("pause");
return 0;
}
UPDATE 2:
All I can seem to get is the average for the first column. Can't really work out how to repeat this step. I've tried using do and for loops, but this got me a bunch of errors and losing the only average I get.
If anyone want's to take a look, be warned its very messy...
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
using namespace std;
int main ()
{
string Data, FileName;
int row, col;
float Matrix[50][50], sum, average;
sum = 0;
cout << "Enter the name you gave the matrix file.\n";
cout << "(DO NOT INCLUDE ANY SPACES OR EXTENSIONS!)\n";
cin >> FileName;
FileName = "C:\\Users\\Public\\Documents\\" + FileName + ".ascii";
ifstream Fin(FileName);
if (Fin.is_open())
{
row=0;
while(!Fin.eof())
{
getline(Fin, Data);
stringstream ss(Data);
col=0;
while(ss >> Matrix[row][col])
{
col++;
}
row++;
}
Fin.close();
}
else
cout << "Unable to open file";
double AvgArray[50];
for (int y = 0; y < 50; y++)
{
for (int x = 1; x < 50; x++)
{
if (Matrix[x][y]<0)
{
break;
}
sum = sum + Matrix[x][y];
average = sum / x;
}
if (Matrix[y][y]<0)
{
break;
}
average = AvgArray[y];
}
cout << average << "\n";
system("pause");
return 0;
}
You forgot to set sum to 0 before the second for-loop. In UPDATE 2 you still don't set sum to 0!?
after the first 'for' and before the second ... before you start adding the sums for a column ...
like this
for (int y = 0; y < col; y++)
{
sum = 0;
for (int x = 0; x < row; x++)
{
sum = sum + Matrix[x][y];
}
average = sum / row;
cout << average << " for column " << y << "\n";
}
You gave this:
for (int y = 0; y < 50; y++)
{
for (int x = 1; x < 50; x++)
{
if (Matrix[x][y]<0)
{
break;
}
sum = sum + Matrix[x][y];
average = sum / x;
}
if (Matrix[y][y]<0)
{
break;
}
average = AvgArray[y];
}
In this part of your code, it appears that you are trying to calculate the average at every row in every column (because you put average = sum / x; inside both of the for loops.) I would recommend calculating the sum of the entire column before calculating the average, in order to save code/time. Furthermore, you also put average = AvgArray[y];. Assuming you're trying to fill this array with the averages for each column, you will want to assign average to AvgArray[y] instead. Currently, you never assign any values to AvgArray[].
cout << average << "\n";
Like in the code Zsolt Marx gave, you will want to put this line inside the larger of the two for loops. Otherwise, if you leave it the way you have it, the code will only display the average for the last column calculated.
Hi guys I am trying to make a program that takes some user input and maps it to a 2d array and then encrypts it by mixing up the columns. For example if the user enters "my name is fred" the program creates an array that is 3x6 filling the last column with y's and the remain empty spaces with x's so it should be something like
mynamy
eisfry
edxxxx
instead I wind up with
mynam
eisfr
edxx
#include <iostream>
#include<cctype>
#include<algorithm>
using namespace std;
main(){
string input;
cout << "Enter information to be encrypted" << endl;
getline(cin,input);
input.erase(std::remove (input.begin(), input.end(), ' '), input.end());
int columns = 6;
int rows;
if (input.size() <= 5){
rows = 1;
}
else if (input.size()% 5 > 0){
rows = input.size()/5 + 1;
}
else
rows = input.size()/5;
char message[rows][columns];
int place = 0;
for(int i = 0; i < rows; i++){
for(int j = 0; j < (columns-1); j++){
if(place <= input.size()){
message[rows][columns] = input[place];
}
else {
message[rows][columns] = 'x';
}
place++;
message[rows][5] = 'y';
cout << message[rows][columns];
}
cout << endl;
}
}
this should do it..
#include <iostream>
#include <cctype>
#include <algorithm>
using namespace std;
int main()
{
string input;
cout << "Enter information to be encrypted" << endl;
getline(cin,input);
input.erase(std::remove (input.begin(), input.end(), ' '), input.end());
int columns = 6;
int rows;
if (input.size() <= 5){
rows = 1;
}
else if (input.size()% 5 > 0){
rows = input.size()/5 + 1;
}
else
rows = input.size()/5;
char message[rows][columns];
for(int i = 0; i < rows; i++){
for(int j = 0; j < (columns-1); j++){
if ((i*5 + j) < int(input.size())){
message[i][j] = input[i*5 + j];
}
else {
message[i][j] = 'x';
}
// place++;
if (i != rows-1) message[i][5] = 'y';
else message[i][5] = 'x';
// cout << "i: " << i << " | j: " << j << " | " << message[i][j] << endl;
}
cout << endl;
}
for (int i = 0; i < rows; i++) {
for (int j = 0; j < columns; j++) {
cout << message[i][j];
}
cout << " ";
}
cout << endl;
}
Your code isn't actually doing anything to transpose the matrix! It's writing the message into the matrix, but it's printing each entry out right after it's written, so it doesn't end up changing the order at all.
You'll need a separate set of loops to read data out of the matrix.
I have a data file comprised of thousands of float values and I want to read them into a 2D vector array and pass that vector to another routine once it's stored the floats from the file. When I run this code it prints out;
[0][0] = 0, [0][1] = 0, etc.
The data file contains values like;
0.000579, 27.560021, etc.
int rows = 1000;
int cols = 2;
vector<vector<float>> dataVec(rows,vector<float>(cols));
ifstream in;
in.open("Data.txt");
for(int i = 0; i < rows; i++){
for(int j = 0; j < 2; j++){
in >> dataVec[i][j];
cout << "[ " << i << "][ " << j << "] = " << dataVec[i][j] << endl;
}
}
in.close();
It looks to me like the file could not be opened. You did not test for success, so it will plough on regardless. All your values were initialized to zero and will stay that way because every read fails. This is conjecture, I admit, but I'd put money on it. =)
Try this solution, it works according to your specs:
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
using namespace std;
int main(void)
{
ifstream infile;
char cNum[10] ;
int rows = 1;
int cols = 2;
vector<vector<float > > dataVec(rows,vector<float>(cols));
infile.open ("test2.txt", ifstream::in);
if (infile.is_open())
{
while (infile.good())
{
for(int i = 0; i < rows; i++)
{
for(int j = 0; j < 2; j++)
{
infile.getline(cNum, 256, ',');
dataVec[i][j]= atof(cNum) ;
cout <<dataVec[i][j]<<" , ";
}
}
}
infile.close();
}
else
{
cout << "Error opening file";
}
cout<<" \nPress any key to continue\n";
cin.ignore();
cin.get();
return 0;
}
#include <vector>
#include <fstream>
#include <iostream>
using namespace std;
void write(int m, int n)
{
ofstream ofs("data.txt");
if (!ofs) {
cerr << "write error" << endl;
return;
}
for (int i = 0; i < m; i++)
for (int j = 0; j < n; j++)
ofs << i+j << " ";
}
void read(int m, int n)
{
ifstream ifs("data.txt");
if (!ifs) {
cerr << "read error" << endl;
return;
}
vector<float> v;
float a;
while (ifs >> a) v.push_back(a);
for (int i = 0; i < m; i++)
for (int j = 0; j < n; j++)
cout << "[" << i << "][" << j << "] = "
<< v[i*n+j] << ", ";
}
int main()
{
write(2,2);
read(2,2);
return 0;
}