Can't find the right max Value in my Array loop - c++

So my professor gave us this project to read a text file and find the max value, min value, sum. But for some reason when I write the for loop to find the max value it returns a number thats not even in the text file... and I don't know what i did wrong. I'll attach my code and also the output. Thank you
int main () {
ifstream myFile;
char myArray[210];
int i;
int maxVal;
int j;
int minValue;
double myAverage;
myFile.open("Lab #5A Data File.Txt", ios::in | ios::out);
if (myFile.is_open()) {
cout << "The file is open." << endl;
myFile >> noskipws;
while (!myFile.eof()){
for (i=0; i<210; ++i) {
myFile >> myArray[i];
cout << myArray[i];
}
myFile >>myArray[i];
}
maxVal=myArray[0];
for (j=0; j< 210; j++)
if (myArray[j] > maxVal){
maxVal=myArray[j];
}
What i get when I run the code :
The file is open.
346 130 982 90 656 117 595
415 948 126 4 558 571 87
42 360 412 721 463 47 119
441 190 985 214 509 2 571
77 81 681 651 995 93 74
310 9 995 561 92 14 288
466 664 892 8 766 34 639
151 64 98 813 67 834 369
The max value is: 51 <--- I have no idea where this number came from...

The 51 is coming from the line:
maxVal=myArray[0];
In your loop to try to find the biggest element you have:
for (j=0; j< 210; j++)
if (myArray[j] > maxVal){
myArray[i]=maxVal;
}
}
However this will assign maxVal to myArray[i] which is not what you want. First of all you need to be assigning myArray[j], not myArray[i], and secondly you need to assign maxVal to the bigger value. As it is maxVal=myArray[0]; is the only time you assign anything to maxVal, which is why it is 51 (The ASCII value of the character 3, which is the first character you read). You need to do something along the lines of:
if (myArray[j] > maxVal){
maxVal = myArray[j];
}
I believe you wanted myArray to be an int[]. Also a better way of doing this is instead of having two for loops and looping until EOF, loop while myFile >> myArray[i]:
int myArray[210];
int i = 0;
//...
while (myFile >> myArray[i]) {
cout << myArray[i] << " ";
if (myArray[i] > maxVal) {
maxVal = myArray[i];
}
i++;
}
Which for the input file:
346 130 982 90 656 117 595
415 948 126 4 558 571 87 42
360 412 721 463 47 119 441
190 985 214 509 2 571 77 81
681 651 995 93 74 310 9 995
561 92 14 288 466 664 892 8
766 34 639 151 64 98 813 67 834 369
Returns:
995

To achieve what you want, you cannot do a comparison like this
if (myArray[j] > maxVal){
because myArray[j] is a char (definitely not holding the integers you are interested in) and maxVal is an int. This is also the reason you see a 51 - when you try to store an integer into your char, you essentially only read 8 bits from the stream (which results in some value between 0 and 254 which is basically just some 8-bit block from your input stream).
You definitely want something like
char myArray[32][210];
to be able to read your full integers from the stream into one of these 210 char* slots.
Then, when comparing (and assigning to maxValue), you need to convert the textual int value to a numeric value, e.g., using atoi().

Related

Read rows of numbers from txt file in C++

Good morning guys,
I have an assignment for school and I hoped you could help me on this one.
The goal of the program is very simple. Calculate the sum of the numbers
on each line of the file, and display on the screen the N highest distinct results in decreasing rorder, with N the number of occurrences for each result, N being supplied as a parameter by the user (default value = 3).
So as the title says i'm working in C++, and my program has to read rows of numbers (double) from a txt file provided. I already know the concept ot ifsream types, and managed to open the file. I know that I can use the >> operator to read from the file, but the number of doubles per row is not fixed, so i can't make a simple loop. Here is how it looks so far on my side :
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
using namespace std;
int main(){
int nbresult=3;
string filename;
double tmp;
cin >> filename;
cin >> nbresult;
ifstream file;
file.open(filename.c_str());
if(file.is_open())
{
cout << "Opening file: " << filename << endl;
while(file.eof() == false)
{
vector<double> nbres;
file >> tmp;
nbres.push_back(tmp);
}
fichier.close();
}
else
{
cout << "Erreur à l'ouverture !" << endl;
}
return 0;
}
So my idea was putting the numbers in a vector and summing up, but I've realized that I would need to create an instance of vector for each row. Plus, my reading method wouldn't allow me to create multiple vectors because it reads without acknowledging the fact that the numbers are in different rows.
Can you guy guide me to an efficient solution ? I'm really starting to loose it lol.
Thanks in advance !
matt
If I understand your questions, and if you are still stuck, the overview of the process would simply be filling a vector with the top n sums (default: 3) computed from each line of values within a file. You want the value in descending order.
Whenever you need to get an unknown number of values from a line within a file (regardless whether the values are delimited by commas, or spaces, etc..), your approach should be to read an entire line of data into a string, creating a stringsteam from the line, and then looping inputting values from the stringstream until EOF is encountered on the stringstream.
Why a stringstream and not just read values directly from the file? (Answer: line-control). Since cin discards leading whitespace, and '\n' (the newline) is whitespace, there is no way to determine when you reach the end of a line reading directly from the file. By reading the line first and then creating a stringstream, you can simply read until you reach the end of the stringstream you have created -- and you have input all the values in a single line.
The only vector you need to maintain throughout your code is the vector of sums in decreasing order. When reading each of the values from the stringstream you create, you can simply use a temporary vector for purposed of storing each of the values in a given line and then call accumulate on the temporary vector to provide the sum.
The challenge is maintaining the top X number of sums in your final results vector to output at the end of the program. The approach there is actually fairly straight-forward. If the sum is the first sum, just use push_back() to store it. For all subsequent sums, use an iterator to traverse the vector comparing what is already stored against the current sum until the sum is greater than the element of the vector and then call the .insert() method to insert the current sum in your results vector before the element referenced by the iterator.
When you are done, simply output the results vector using an auto-ranged for loop.
There are many different ways to approach it, but sticking to what is above, you could do something like the following. The code is commented to help walk you through it:
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
#include <numeric> /* for accumulate */
int main (int argc, char **argv) {
if (argc < 2) { /* validate at least filename given */
std::cerr << "error: insufficient arguments\n"
"usage: " << argv[0] << " filename (nresults: 3)\n";
return 1;
}
std::string filename = argv[1], /* string for filename */
line; /* string to hold line */
std::vector<int> results; /* vector of results */
std::ifstream f; /* input file stream */
size_t nresults = 3, n = 0; /* num of results, countner */
if (argc >= 3) /* if addition arg given, set nresults */
nresults = std::stoi(argv[2]);
f.open (filename); /* open filename */
if (! f.is_open()) { /* validate file open for reading */
perror (("error file open failed " + filename).c_str());
return 1;
}
while (std::getline (f, line)) { /* read each row of values */
int val, sum; /* current value, line sum */
std::vector<int> v; /* vector to hold values */
std::stringstream s (line); /* create stringstream from line */
while ((s >> val)) /* read each value */
v.push_back (val); /* add it to vector v */
sum = accumulate (v.begin(), v.end(), 0); /* sum values in v */
if (results.empty()) /* if empty */
results.push_back (sum); /* just add */
else /* otherwise insert in decreasing order */
for (auto it = results.begin(); it != results.end(); it++)
if (sum > *it) {
results.insert (it, sum);
break;
}
if (results.size() > nresults) /* trim excess elements */
results.pop_back();
n++; /* increment line count */
}
/* output results */
std::cout << nresults << " greatest sums from " << n << " lines in " <<
filename << '\n';
for (auto& p : results)
std::cout << " " << p;
std::cout << '\n';
}
(note: the code expects the filename as the 1st argument, and then takes an optional argument of the number of top sums to report -- using a default of 3)
Example Input File
The following input was simply produced by writing 50 lines containing 5 random values between 0 - 999:
$ cat dat/50x5.txt
106 114 604 482 340
815 510 690 228 291
250 341 774 224 545
174 546 537 278 71
706 139 767 320 948
328 683 410 401 123
140 507 238 744 990
810 559 732 732 20
24 982 361 30 439
139 204 217 676 714
288 615 853 287 935
801 847 851 211 249
206 583 756 676 328
978 486 119 711 219
139 967 433 733 997
872 104 433 89 12
147 609 627 0 897
795 34 744 878 477
225 84 61 982 761
621 960 479 740 903
930 112 870 364 77
99 468 181 532 790
193 911 399 53 912
296 80 178 273 958
887 498 274 180 712
267 801 905 747 774
40 677 118 911 273
195 242 974 376 775
764 801 686 163 854
830 692 166 240 197
124 128 927 399 540
640 898 342 777 645
348 817 555 466 960
60 661 203 34 269
978 798 302 896 194
389 959 886 555 199
83 680 559 10 311
100 882 209 442 659
87 22 709 874 488
669 934 381 104 969
650 314 999 952 211
193 341 170 79 129
601 394 809 161 637
352 261 519 793 935
411 112 957 352 986
677 21 153 58 358
122 708 672 353 892
883 547 466 285 858
595 887 253 636 48
122 220 541 641 245
If you want to validate the sums, you can use a short awk script[1].
Example Use/Output
$ ./bin/vector_n_greatest dat/50x5.txt
3 greatest sums from 50 lines in dat/50x5.txt
3703 3494 3302
$ ./bin/vector_n_greatest dat/50x5.txt 4
4 greatest sums from 50 lines in dat/50x5.txt
3703 3494 3302 3269
$ ./bin/vector_n_greatest dat/50x5.txt 10
10 greatest sums from 50 lines in dat/50x5.txt
3703 3494 3302 3269 3268 3168 3146 3126 3057 3039
Look things over and let me know if you have further questions.
footnotes:
(1.) to output the sorted line sums for verification, you can use a short awk script and sort, e.g.
awk '{
sum = 0
for (i=1; i<=NF; i++)
sum += $i
printf "%-20s (%4d)\n", $0, sum
}' file | sort -r -b -k6.2
The awk output would for the example file would show:
$ awk '{
> sum = 0
> for (i=1; i<=NF; i++)
> sum += $i
> printf "%-20s (%4d)\n", $0, sum
> }' dat/50x5.txt | sort -r -b -k6.2
621 960 479 740 903 (3703)
267 801 905 747 774 (3494)
640 898 342 777 645 (3302)
139 967 433 733 997 (3269)
764 801 686 163 854 (3268)
978 798 302 896 194 (3168)
348 817 555 466 960 (3146)
650 314 999 952 211 (3126)
669 934 381 104 969 (3057)
883 547 466 285 858 (3039)
389 959 886 555 199 (2988)
...

Why are my bit shifts giving incorrect numbers

I'm trying to store a number in an array of 4 integers. The array is in the class Num. My problem is that when I call getValue, the function returns numbers that aren't correct. I tried go through the program on paper, doing all the calculations in Microsoft's calculator, and the program should give the correct output. I don't even know which function could be problematic since there aren't any errors or warnings, and both worked on paper.
21 in binary:10101
What I'm trying to do:
Input to setValue function: 21
setValue puts the first four bits of 21 (0101) into num[3]. So num[3] is now 0101 in binary. Then it should put the next four bits of 21 into num[2]. The next four bits are 0001 so 0001 goes into num[2] The rest of the bits are 0 so we ignore them. Now num is {0,0,1,5}. getValue first goes to num[3]. There is 5 which is 0101 in binary. So it puts that into the first four bits of return value. It then puts 0001 into the next four bits. The rest of the numbers are 0 so it is supposed to ignore them. Then the output of the function getValue is directly printed out. The actual output is at the bottom.
My code:
#include <iostream>
class Num {
char len = 4;
int num[4];
public:
void setValue(int);
int getValue();
};
void Num::setValue(int toSet)
{
char len1=len-1;
for (int counter = len1;counter>=0;counter--)
{
if(toSet&(0xF<<(len1-counter))!=0)
{
num[counter]=(toSet&(0xF<<(len1-counter)))>>len1-counter;
} else {
break;
}
}
}
int Num::getValue()
{
char len1 = len-1;
int returnValue = 0;
for(char counter = len1; counter>=0;counter--)
{
if (num[counter]!=0) {
returnValue+=(num[counter]<<(len1-counter));
} else {
break;
}
}
return returnValue;
}
int main()
{
int x=260;
Num number;
while (x>0)
{
number.setValue(x);
std::cout<<x<<"Test: "<<number.getValue()<<std::endl;
x--;
}
std::cin>>x;
return 0;
}
Output:
260Test: -1748023676
259Test: 5
258Test: 5
257Test: 1
256Test: 1
255Test: 225
254Test: 225
253Test: 221
252Test: 221
251Test: 213
250Test: 213
249Test: 209
248Test: 209
247Test: 193
246Test: 193
245Test: 189
244Test: 189
243Test: 181
242Test: 181
241Test: 177
240Test: 177
239Test: 177
238Test: 177
237Test: 173
236Test: 173
235Test: 165
234Test: 165
233Test: 161
232Test: 161
231Test: 145
230Test: 145
229Test: 141
228Test: 141
227Test: 133
226Test: 133
225Test: 1
224Test: 1
223Test: 161
222Test: 161
221Test: 157
220Test: 157
219Test: 149
218Test: 149
217Test: 145
216Test: 145
215Test: 129
214Test: 129
213Test: 125
212Test: 125
211Test: 117
210Test: 117
209Test: 113
208Test: 113
207Test: 113
206Test: 113
205Test: 109
204Test: 109
203Test: 101
202Test: 101
201Test: 97
200Test: 97
199Test: 81
198Test: 81
197Test: 77
196Test: 77
195Test: 5
194Test: 5
193Test: 1
192Test: 1
191Test: 161
190Test: 161
189Test: 157
188Test: 157
187Test: 149
186Test: 149
185Test: 145
184Test: 145
183Test: 129
182Test: 129
181Test: 125
180Test: 125
179Test: 117
178Test: 117
177Test: 113
176Test: 113
175Test: 113
174Test: 113
173Test: 109
172Test: 109
171Test: 101
170Test: 101
169Test: 97
168Test: 97
167Test: 81
166Test: 81
165Test: 77
164Test: 77
163Test: 69
162Test: 69
161Test: 1
160Test: 1
159Test: 97
158Test: 97
157Test: 93
156Test: 93
155Test: 85
154Test: 85
153Test: 81
152Test: 81
151Test: 65
150Test: 65
149Test: 61
148Test: 61
147Test: 53
146Test: 53
145Test: 49
144Test: 49
143Test: 49
142Test: 49
141Test: 45
140Test: 45
139Test: 37
138Test: 37
137Test: 33
136Test: 33
135Test: 17
134Test: 17
133Test: 13
132Test: 13
131Test: 5
130Test: 5
129Test: 1
128Test: 1
127Test: 225
126Test: 225
125Test: 221
124Test: 221
123Test: 213
122Test: 213
121Test: 209
120Test: 209
119Test: 193
118Test: 193
117Test: 189
116Test: 189
115Test: 181
114Test: 181
113Test: 177
112Test: 177
111Test: 177
110Test: 177
109Test: 173
108Test: 173
107Test: 165
106Test: 165
105Test: 161
104Test: 161
103Test: 145
102Test: 145
101Test: 141
100Test: 141
99Test: 133
98Test: 133
97Test: 1
96Test: 1
95Test: 161
94Test: 161
93Test: 157
92Test: 157
91Test: 149
90Test: 149
89Test: 145
88Test: 145
87Test: 129
86Test: 129
85Test: 125
84Test: 125
83Test: 117
82Test: 117
81Test: 113
80Test: 113
79Test: 113
78Test: 113
77Test: 109
76Test: 109
75Test: 101
74Test: 101
73Test: 97
72Test: 97
71Test: 81
70Test: 81
69Test: 77
68Test: 77
67Test: 5
66Test: 5
65Test: 1
64Test: 1
63Test: 161
62Test: 161
61Test: 157
60Test: 157
59Test: 149
58Test: 149
57Test: 145
56Test: 145
55Test: 129
54Test: 129
53Test: 125
52Test: 125
51Test: 117
50Test: 117
49Test: 113
48Test: 113
47Test: 113
46Test: 113
45Test: 109
44Test: 109
43Test: 101
42Test: 101
41Test: 97
40Test: 97
39Test: 81
38Test: 81
37Test: 77
36Test: 77
35Test: 69
34Test: 69
33Test: 1
32Test: 1
31Test: 97
30Test: 97
29Test: 93
28Test: 93
27Test: 85
26Test: 85
25Test: 81
24Test: 81
23Test: 65
22Test: 65
21Test: 61
20Test: 61
19Test: 53
18Test: 53
17Test: 49
16Test: 49
15Test: 49
14Test: 49
13Test: 45
12Test: 45
11Test: 37
10Test: 37
9Test: 33
8Test: 33
7Test: 17
6Test: 17
5Test: 13
4Test: 13
3Test: 5
2Test: 5
1Test: 1
I compiled this with g++ 6.3.0 with the command g++ a.cpp -o a.exe
When compiling with -Wall, there are a number of warnings:
orig.cpp: In member function ‘void Num::setValue(int)’:
orig.cpp:15:39: warning: suggest parentheses around comparison in operand of ‘&’ [-Wparentheses]
if(toSet&(0xF<<(len1-counter))!=0)
~~~~~~~~~~~~~~~~~~~~~^~~
orig.cpp:17:61: warning: suggest parentheses around ‘-’ inside ‘>>’ [-Wparentheses]
num[counter]=(toSet&(0xF<<(len1-counter)))>>len1-counter;
~~~~^~~~~~~~
orig.cpp: In member function ‘int Num::getValue()’:
orig.cpp:30:24: warning: array subscript has type ‘char’ [-Wchar-subscripts]
if (num[counter]!=0) {
^
orig.cpp:31:38: warning: array subscript has type ‘char’ [-Wchar-subscripts]
returnValue+=(num[counter]<<(len1-counter));
^
If you were to print the values of num before changing them, you'd see that some might be non-zero (i.e. they are uninitialized), which causes undefined behavior and probably breaks your for loops in getValue and setValue.
So change:
int num[4];
Into:
int num[4] = { 0 };
Here's a cleaned up version with the warnings fixed:
#include <iostream>
class Num {
int len = 4;
int num[4] = { 0 };
public:
void setValue(int);
int getValue();
void showval();
};
void Num::setValue(int toSet)
{
int len1=len-1;
for (int counter = len1;counter>=0;counter--)
{
if ((toSet & (0xF << (len1-counter))) != 0)
{
num[counter] = (toSet & (0xF << (len1-counter))) >> (len1-counter);
} else {
break;
}
}
}
int Num::getValue()
{
int len1 = len-1;
int returnValue = 0;
for(int counter = len1; counter>=0;counter--)
{
if (num[counter]!=0) {
returnValue+=(num[counter]<<(len1-counter));
} else {
break;
}
}
return returnValue;
}
void Num::showval()
{
for (int i = 0; i < len; ++i)
std::cout << i << ": show: " << num[i] << "\n";
#if 0
for (int i = 0; i < len; ++i)
num[i] = 0;
#endif
}
int main()
{
int x=260;
Num number;
number.showval();
while (x>0)
{
number.setValue(x);
std::cout << x << " Test: " << number.getValue() << std::endl;
x--;
}
std::cin>>x;
return 0;
}
To break a number into nibbles, the shift counts should be multiples of 4. Otherwise slices of 4 bits are extracted that don't line up.
00010101 (21)
^^^^ first nibble
^^^^ second nibble
The second nibble is displaced by 4 bits so it needs to be shifted right by 4, not by 1.
You could multiply your shift counts by 4, but there is an easier way: only ever shift by 4. For example:
for (int i = len - 1; i >= 0; i--) {
num[i] = toSet & 0xF;
toSet >>= 4;
}
Then every iteration extracts the lowest nibble in toSet, and shifts toSet over so that the next nibble becomes the lowest nibble.
I didn't put in a break and there should not be one. It definitely shouldn't be the kind of break that you had, which stops the loop also whenever a number has a zero in the middle of it (for example in 0x101 the middle 0 causes the loop to stop). The loop also should not stop when the entire rest of the number is zero, since that leaves junk in the other entries of num.
It's more common to store the lowest nibble in the 0th element and so on (then you don't have to deal with all the "reverse logic" with down-counting loops and subtracting things from the length) but that's up to you.
Extracting the value can be done symmetrically, building up the result while shifting it, instead of shifting every piece into its final place immediately. Or just multiply (len1-counter) by 4. While extracting the value, you also cannot stop when num[i] is zero, since that does not prove that the rest of the number is zero too.

Insertion Array Sorting Method

I am currently a student working on an insertion sort method.
Below is the code:
//Insertion Sorting of an Integer array
void InsertionSort(int insertVals[]){
//Systematic processing of the Array
for(int i = 0; i < INITSIZE - 1; i++){
//Value to check
int temp = insertVals[i];
//Index placeholder for the insterion sort
int k;
//Shifts the int array
for(k = i; k > 0 && insertVals[k-1] > temp; k--){
insertVals[k] = insertVals[k-1];
}
//Inserts the checked value back into the array
insertVals[k] = temp;
}
}
In my tests, I have given it the array from left to right:
307 249 73 158 430 272 44 378 423 209
440 165 492 42 487 3 327 229 340 112
303 169 209 157 60 433 99 278 316 335
97 326 12 267 310 133 479 149 79 321
467 172 393 336 485 245 228 91 194 357
1 153 208 444 168 490 124 196 30 403
222 166 49 24 301 353 477 408 228 433
298 481 135 13 365 314 63 36 425 169
115 94 129 1 17 195 105 404 451 298
188 123 5 382 252 66 216 337 438 144
The method produces from left to right:
314 63 314 63 36 425 36 169 425 169
115 115 94 129 94 129 1 17 195 105
404 451 298 188 123 5 382 252 66 216
337 438 144 1 17 195 105 404 451 298
188 123 5 382 252 66 216 337 438 144
228 229 245 249 252 267 272 278 298 298
301 303 307 310 314 316 321 326 327 335
336 337 340 353 357 365 378 382 393 403
404 408 423 425 430 433 433 438 440 444
451 467 477 479 481 485 487 490 492 144
What am I incorrectly coding?
Thanks!
EDIT:
//In main...
Printing(insertionSortValues, "Insertion Sorted Array");
//Function for Print
void Printing(int vals[], string s){
cout << s << ":" << endl;
for(int i = 0; i < INITSIZE; i++){
if(i % 10 == 0){
cout << endl;
}
cout << setw(3) << vals[i] << " ";
}
cout << endl;
}
The solution to this problem was solved through #PaulMcKenzie.
The line:
for(int i = 0; i < INITSIZE - 1; i++){
needed to become:
for(int i = 0; i <= INITSIZE - 1; i++){
Below is the corrected function.
//Insertion Sorting of an Integer array
void InsertionSort(int insertVals[]){
//Systematic processing of the Array
for(int i = 0; i <= INITSIZE - 1; i++){
//Value to check
int temp = insertVals[i];
//Index placeholder for the insterion sort
int k;
//Shifts the int array
for(k = i; k > 0 && insertVals[k-1] > temp; k--){
insertVals[k] = insertVals[k-1];
}
//Inserts the checked value back into the array
insertVals[k] = temp;
}
}

How to generate only so many permutations more efficiently in C++?

I'm trying to solve a problem and I feel like I'm really close to it but it's still a little slow because I'm generating so many permutations.
I need the permutations of "0123456789". I know there are (10)! permutations which is a lot.
I use an std::unordered_set because I don't care about the order they are stored in and it seemed faster than using a regular std::set
Here is some core I wrote: max_perm_size is the size of the string of permutations I care about for a particular case.
void getPermutations(unordered_set<string> &permutations, int &max_perm_size)
{
string digits = "0123456789";
do{
permutations.insert(digits.substr(0, max_perm_size));
} while (next_permutation(digits.begin(), digits.end()));
}
I have two main questions about this code:
Above I'm still generating then entire "0123456789" permutation even for cases where I only care about permutations of size max_perm_size. I just trim them afterwords before storing them into my std::unordered_set. Is there a way to do this in a better way so it's faster?
For the worst case max_pem_size = 10, is there a more efficient way for me to generate and store all of these permutations in general?
As far as a I can tell, your result is numbers (without repeated digits) from 0 through some limit. Since you say you don't care about the order of the digits, it's probably easiest if we just stick to ascending ones. That being the case, we can generate results like this:
#include <iostream>
int main() {
for (int i=0; i<10; i++)
for (int j=i+1; j<10; j++)
for (int k=j+1; k<10; k++)
std::cout << i << j << k << "\t";
}
Result:
012 013 014 015 016 017 018 019 023 024 025 026 027
028 029 034 035 036 037 038 039 045 046 047 048 049
056 057 058 059 067 068 069 078 079 089 123 124 125
126 127 128 129 134 135 136 137 138 139 145 146 147
148 149 156 157 158 159 167 168 169 178 179 189 234
235 236 237 238 239 245 246 247 248 249 256 257 258
259 267 268 269 278 279 289 345 346 347 348 349 356
357 358 359 367 368 369 378 379 389 456 457 458 459
467 468 469 478 479 489 567 568 569 578 579 589 678
679 689 789
If your limit isn't a number of digits, you can put the digits together into an actual int and compare (then break out of the loops).
This is specific to your case, not a general solution, but for the case of digit permutations, you can do:
void getPermutations(unordered_set<string> &permutations, int max_perm_size)
{
if (max_perm_size < 1) return;
uint64_t stopat = 1;
for (int i = 1; i < max_perm_size; ++i) {
stopat *= 10;
}
for (uint64_t dig = 0; dig < stopat; ++dig) {
std::ostringstream ss;
ss << std::setw(max_perm_size) << std::setfill('0') << dig;
permutations.insert(ss.str());
}
}
You can take a substring of your digits string first. Then your loop will only deal with permutations of max_perm_size.
You could create a class that generates permutations on demand instead of pre-generating and storing them beforehand. Depending on your application, you may not even have to store them.

Why is it counting the last number twice?

My program is reading numbers from a file- and it reads the last number twice. What is wrong with my program and what can I do to fix it?
int main()
{
ifstream inputFile;
int number = 0; //the input for the numbers in the file
double total = 0; //the total of the numbers
double counter = 0;//number of numbers
double average = 0;//average of the number
inputFile.open("random.txt");//open file
if (!inputFile)//test for file open errors
{
cout<<"Error \n";
}
while (inputFile)
{
inputFile >> number ;
total+=number;
counter++;
cout<<"The running total is: " <<total <<"\n";
}
total=total*1.00;
counter=counter*1.00;
average = total/counter;
cout<<"\nthe final total is: \t" <<total;
cout<<"\nthe number of numbers is: \t";
cout<<counter;
cout<<"\nthe average of the numbers is: \t";
cout<<setprecision(8)<< fixed<< average<<"\n";
inputFile.close();
return 0;
}
the contents of the file:
42
468
335
501
170
725
479
359
963
465
706
146
282
828
962
492
996
943
828
437
392
605
903
154
293
383
422
717
719
896
448
727
772
539
870
913
668
300
36
895
704
812
323
334
674
665
142
712
254
869
548
645
663
758
38
860
724
742
530
779
317
36
191
843
289
107
41
943
265
649
447
806
891
730
371
351
7
102
394
549
630
624
85
955
757
841
967
377
932
309
945
440
627
324
538
539
119
83
930
542
834
116
640
659
705
931
978
307
674
387
22
746
925
73
271
830
778
574
98
513
987
291
162
637
356
768
656
575
32
53
351
151
942
725
967
431
108
192
8
338
458
288
754
384
946
910
210
759
222
589
423
947
507
31
414
169
901
592
763
656
411
360
625
538
549
484
596
42
603
351
292
837
375
21
597
22
349
200
669
485
282
735
54
1000
419
939
901
789
128
468
729
894
649
484
808
422
311
618
814
515
Because the inputFile becomes false1 after an unsuccessful reading attempt has been done, and not when there's just no more data to read. So, when you've read successfully the last element you are inputFile still evaluates to true, and the next iteration of the while is started. Now, at inputFile>>number the failbit is set, but you're not checking it immediately, so your code goes on normally, "thinking" that another element has been read (when actually is just the old one which happened to remain in number).
Quick solution: move the check after the read:
for(;;)
{
inputFile >> number;
if(!inputFile)
break;
total+=number;
counter++;
cout<<"The running total is: " <<total <<"\n";
}
or (better):
while(inputFile >> number)
{
total+=number;
counter++;
cout<<"The running total is: " <<total <<"\n";
}
This works because operator>> returns the stream object, which is evaluated just after the read in the while condition section.
1. I know, I know that it's not actually false but it's operator(void*)... but don't overcomplicate things :)
This line of code fails when it reaches the end of the file:
inputFile >> number;
but your code doesn't check to see if the stream is still valid until the beginning of the while loop.
Try:
while(inputFile >> number)
{
total+=number;
counter++;
cout<<"The running total is: " <<total <<"\n";
}
I suspect that the boolean test on inputfile (in the while-line) only fails if the eof has actually been read. So the loop will be executed one time too much and number will still have its old value, and therefore be added twice.
See http://www.cppreference.com/wiki/io/eof for an example on how to write a better while loop for reading files. You could do it like this:
while (inputFile >> number)
{
total+=number;
counter++;
cout<<"The running total is: " <<total <<"\n";
}
You've been given one approach. Here's another possibility:
int main() {
std::ifstream inputFile("random.txt");
std::vector<int> data;
std::copy(std::istream_iterator<int>(inputFile),
std::istream_iterator<int>(),
std::back_inserter(data));
double total = (double)std::accumulate(data.begin(), data.end(), 0);
std::cout << "The final total is: " << total << "\n";
std::cout << "The number of numbers is: " << data.size() << "\n";
std::cout << "The average is: " << total / data.size() << "\n";
return 0;
}
This produces slightly different output (i.e., minus the "running total") but I'm guessing you only added that for debugging.