Computing avg test scores using a while loop - c++

Ok so, I am trying to write a program using a 'while' loop to compute the the average of a certain # of test scores. My 1st input is the amount of tests, and every input afterwards is a set of scores (so say 1st input is 5, then the next 5 inputs are 5 different test scores). I have to input all the variables at once in order to find the sum of all the test scores and then the computed average.
I am completely stuck on how to do this and don't even know where to start.

Some pseudocode
total <- 0
N <- input number of tests
i <- 1
while i <= N
data[i] <- input data
total <- total + data[i]
i <- i + 1
avg <- total / N

To get you started but not give too much away...
To do this the way I think you want to do this:
First take input for the # of tests.
Cin >> test_amt;
Okay, so now you know how many tests there are. Great! So now you should use a while loop to go through each test and take in input for the score! I would use a for loop here, but if you want to use a while loop, then sure.
counter = 0;
while(counter != test_amt-1)
{
cin >> score;
//I would use a vector to store each score.
//this way, you easily know which score matches up with which test
score = 0;
counter++;
}
I hope this can get you started. If not, just let me know and I would be glad to help more.

You can store scores in a std::vector and calculate the sum with std::accumulate.

Take all the scores in a single variable by adding them one after other and finally get the average. Below I have given a hint that will help you to use while loop. But you can use your own logic for it:
int test_amount, counter = 0, total = 0, score;
int avg;
cout<<"Enter test amount"<<endl;
cin>>test_amount;
while(counter < (test_amount-1))
{
cout<<"Enter the test score"<<endl;
cin>>score;
total=total+score;
counter++;
}
avg = total/test_amount;
If you wish to store the scores as well you may think of vector or array. As the number of 'test amount' is not fixed, you can also go for dynamic array, linked list etc. Think about other approaches, post your own code and Google is also there with all kind of help.

Related

Go through the array from left to right and collect as many numbers as possible

CSES problem (https://cses.fi/problemset/task/2216/).
You are given an array that contains each number between 1…n exactly once. Your task is to collect the numbers from 1 to n in increasing order.
On each round, you go through the array from left to right and collect as many numbers as possible. What will be the total number of rounds?
Constraints: 1≤n≤2⋅10^5
This is my code on c++:
int n, res=0;
cin>>n;
int arr[n];
set <int, greater <int>> lastEl;
for(int i=0; i<n; i++) {
cin>>arr[i];
auto it=lastEl.lower_bound(arr[i]);
if(it==lastEl.end()) res++;
else lastEl.erase(*it);
lastEl.insert(arr[i]);
}
cout<<res;
I go through the array once. If the element arr[i] is smaller than all the previous ones, then I "open" a new sequence, and save the element as the last element in this sequence. I store the last elements of already opened sequences in set. If arr[i] is smaller than some of the previous elements, then I take already existing sequence with the largest last element (but less than arr[i]), and replace the last element of this sequence with arr[i].
Alas, it works only on two tests of three given, and for the third one the output is much less than it shoud be. What am I doing wrong?
Let me explain my thought process in detail so that it will be easier for you next time when you face the same type of problem.
First of all, a mistake I often made when faced with this kind of problem is the urge to simulate the process. What do I mean by "simulating the process" mentioned in the problem statement? The problem mentions that a round takes place to maximize the collection of increasing numbers in a certain order. So, you start with 1, find it and see that the next number 2 is not beyond it, i.e., 2 cannot be in the same round as 1 and form an increasing sequence. So, we need another round for 2. Now we find that, 2 and 3 both can be collected in the same round, as we're moving from left to right and taking numbers in an increasing order. But we cannot take 4 because it starts before 2. Finally, for 4 and 5 we need another round. That's makes a total of three rounds.
Now, the problem becomes very easy to solve if you simulate the process in this way. In the first round, you look for numbers that form an increasing sequence starting with 1. You remove these numbers before starting the second round. You continue this way until you've exhausted all the numbers.
But simulating this process will result in a time complexity that won't pass the constraints mentioned in the problem statement. So, we need to figure out another way that gives the same output without simulating the whole process.
Notice that the position of numbers is crucial here. Why do we need another round for 2? Because it comes before 1. We don't need another round for 3 because it comes after 2. Similarly, we need another round for 4 because it comes before 2.
So, when considering each number, we only need to be concerned with the position of the number that comes before it in the order. When considering 2, we look at the position of 1? Does 1 come before or after 2? It it comes after, we don't need another round. But if it comes before, we'll need an extra round. For each number, we look at this condition and increment the round count if necessary. This way, we can figure out the total number of rounds without simulating the whole process.
#include <iostream>
#include <vector>
using namespace std;
int main(int argc, char const *argv[])
{
int n;
cin >> n;
vector <int> v(n + 1), pos(n + 1);
for(int i = 1; i <= n; ++i){
cin >> v[i];
pos[v[i]] = i;
}
int total_rounds = 1; // we'll always need at least one round because the input sequence will never be empty
for(int i = 2; i <= n; ++i){
if(pos[i] < pos[i - 1]) total_rounds++;
}
cout << total_rounds << '\n';
return 0;
}
Next time when you're faced with this type of problem, pause for a while and try to control your urge to simulate the process in code. Almost certainly, there will be some clever observation that will allow you to achieve optimal solution.

getting infinte amount of inputs from the user than printing the biggest 3 , without using arrays

First time around, first time learning to code anything. Sorry for my ignorance.
So I've been asked to code a program that gets infinite amount of number from the users until he submits the number I manage to do so very well, but I also need to print the biggest sum of a following three inputs, for example, the user inputs 4,20,2,4,11,9,8,1 the program should print 11,9,8 because the sum of those 3 is greater than all other 3.
I must tell you I cannot use arrays, I know its a bummber but I know it is possible to do so without.
I was trying to build a function that tries to act like an array but I can't really call her back since its a two-variable function and one of them is the input, which I obviously don't know. was working on this question for 5 hours now and thought ill ask for your wisdom
cout << " enter numbers as long as you wish" << endl;
cout << "when you wish to stop enter the number 1" << endl;
int n;
int sum;
int i = 1;
while (n != 1) {
cin >> n;
remember(i, n);
if (n == 1) {
cout << "you choosed to stop " << endl;
break;
}
i++;
}
And the function I was trying to build is really simple but I can't call any specific value for example remember(1, n) when I want to sum them up and see who is bigger.
int remember(int i, int n){
return n;
}
*** Please note that the sums that are being tested are the sums of the numbers in the exact order that the user-submitted therefor 11,9,8 is the output and NOT 20,11,9
You need seven variables: Three which is the "window" you're currently reading, and which you check your sum with; Three which is the "biggest sum" triple; And one which is the current input.
For each input you read into the "current input" variable, you shift the window down one value and set the top variable to the just read input.
Then you take the sum of all three values in the window, and check if it's bigger than the sum of the current "biggest sum" triple. If it is, then you make the "biggest sum" triple equal to the current window values.
Iterate until there is no more input, and then print the "biggest" values.
Regarding the shifting of the three window values, lets say you have three variables named window1, window2 and window3 then you could shift like this:
window1 = window2;
window2 = window3;
window3 = current;
Checking the sum is as easy as
if ((window1 + window2 + window3) > (biggest1 + biggest2 + biggest3))
All window and biggest variables need to be initialized to the lowest possibly value for the type (for int that would be std::numeric_limits<int>::min()).
Since you initialize all values, there's no need to have special cases for the first and second input.
Iterating while there's input could be done by doing
while (std::cin >> current)
First of all, n is uninitialized, so it's undefined behavior when you do while (n != 1){. So technically, there's no guarantee that anything works past that. You should initialize it, for example by setting it to 0 (or any other value that's not 1, in this case):
int n = 0;
But the issue that you observe is because you have another int n; in your loop, which shadows the outer n (the one that is checked in the while condition). So the cin >> n; only ever modifies that inner n. The outer one will stay at the same uninitialized value. So if that value made it enter the loop, it will never exit the loop, because n != 1 is always true.
Remove the int n; inside the loop to solve the problem.
Basically, what you need is 4 variables to account the actual list and its sums (3 for the list and 1 for the sum of it)
You need 3 more variables to account the actual list.
At each interaction, you have two things to do:
Compare the sum of actual list with the stored one. If the sum the actual list is greater than that stored, actualize it
For each new number, rotate you variables that account for the actual list.
In pseudo code:
v3 = v2;
v2 = v1;
v1 = new_number;

Using for loops and nested lists in python

I am trying to add each row of nested loop independently in order to find averages. I am missing a detail which may or may not derail my whole code.The code should compute the average of a given row of scores but drops the lowest grade.
def printAverages():
scores = [[100,100,1,100,100],
[20,50,60,10,30],
[0,10,10,0,10],
[0,100,50,20,60]]
total = 0
minValue = 100
counter = -1
for row in scores:
counter = counter + 1
for n in scores[0]:
total = total+n
if minValue > n:
minValue = n
total = total - minValue
print("Average for row",counter,"is",total)
total = 0
How do i make it so for n in score [0] takes the average of each row instead of only computing the average of the first row? I know that scores[0] commands the program to only read the first row, I just don't know how to change it.
Thank you
Remember, the XY problem.
# Sum of a list of numbers divided by the number of numbers in the list
def average(numbers):
return sum(numbers)/len(numbers)
# This is your data
scores = [[100,100,1,100,100],
[20,50,60,10,30],
[0,10,10,0,10],
[0,100,50,20,60]]
# enumerate() allows you to write FOR loops naming both the list element and its index
for (i, row) in enumerate(scores):
print("Average for row ", i, "is ", average(row))
Keep in mind that Python supports functional programming and encourages the programmer to write pure functions when possible!
the statement for n in scores[0]: will only go through the first column.
What you want it to say is for n in row:. That will have it go through each row, one row per loop of the outer loop

How can I make it so that the results of a simulation will show up on top of output?

Question looks a little weird I accept.
What I want to ask is this:
int main(){
srand(time(NULL));
for(int x=0;x<10000;x++){
int result = rand()%2;
if(result==0) cout << "Heads" << endl;
if(result==1) cout << "Tails" << endl;
return 0;
}}
So what I want to do is to simulate a huge amount of coin tosses. The output will look like this:
Heads
Heads
Heads
Tails
Heads
Tails
Tails
....
But I want a statement like
Total number of Heads= 4900, Tails= 5100 Longest Heads streak=7,Tails
streak=8
at the top of the output. How can I do it? Since the loop involves cout best I have been able to do is to place the statement at the bottom of output.
EDIT: I managed to solve the problem by using arrays. I first used a loop and simulated the tosses and record them by assigning them to array elements, and then printed them using another loop, in the order I need them. Thanks for all answers, upvoted them all.
You will need to keep track (store) the results of each coin toss. After the tossing is finished, print your summary then the results of each coin toss.
Since each coin is either heads or tails, you could represent heads as false and tails as true. This allows you to use a container of bool.
Also, there are only ever two values, so you can represent them as bits. Let's say heads is 1 and tails is zero. The C++ language has a structure called bitset which can efficiently store the bits until the tossing is completed.
When printing the results, iterate through the bitset container. If the value is 1, print "heads"; otherwise print "tails". Simple. Fast.
The simplest solution is to keep track of the results of the tosses in a bitset, display the numbers of heads and tails, and then iterate through the bitset, display head for each 1 and tails for each zero.
Do you really need to keep printing Heads, Tails?
Why not just keep two counters. i.e.
int main(argc, char* argv[])
{
// Keep track of heads/tails counts
int heads = 0,
int tails = 0,
srand(time(NULL));
for (int x=0; x < 10000; x++){
int result = rand()%2;
if (result == 0) heads++;
if (result == 1) tails++;
}
// print results
printf("Heads=%d, Tails=%d otherstuff=TODO\n", heads, tails);
return 0;
}
Keep track of tails or heads streak with other variables. You'd need
the maximums of heads/tails inited to zero. And a variable to say what the current streak length is, and whether you are currently looking at a head or tail streak.
If you really want to be printing out head/tail you could do the bitset idea like #Arthur Laks suggests, or use an array of char's so that you don't need to deal with bitsets. Or you could write the results to a file and read them back which is rather ugly. There are many ways to do this.
For the array method something like this.
char* results = new char[10000];
char* p = results;
Inside the loop. To indicate heads:
p[x] = 'H';
For tails:
p[x] = 'T';
You can then run through the array again if needed to calculate other statistical patterns if required.
This is about all I'm going to say because I think if I give you a full answer you've not learned anything.

Display an updated average of random numbers in a file

I have a program that displays one random number in file .
#include <iostream>
#include <fstream>
#include <random>
using namespace std;
int main() {
std::ofstream file("file.txt",std::ios_base::app);
int var = rand() % 100 + 1;
file<<var ;
return 0;
}
Results after 4 trial :
1,2 2,20 3,40 1,88
I am looking to not display the numbers . but only there updated average after each try.
Is there any way to calculate the average incrementally ?
Inside the file should exist only the average value :
For example first trial :
1.2
second trial displays the average in the file (1.2+2.2)/2
1.7
Even though it's kind of strange, what you are trying to do, and I'm sure there is a better way of doing it, here's how you can do it:
float onTheFlyAverage()
{
static int nCount=0;
float avg, newAvg;
int newNumber = getRandomNum();
nCount++; //increment the total number count
avg = readLastAvgFromFile(); //this will read the last average in your file
newAvg = avg*(nCount-1)/nCount+ (float)(newNumber)/nCount;
return newAvg;
}
If for some reason you want to keep an average in a file which you provide as input to your program and expect it to keep on averaging numbers for you (a sort of stop and continue feature), you will have to save/load the total number count in the file as well as the average.
But if you do it in one go this should work. IMHO this is far from the best way of doing it - but there you have it :)
NOTE: there is a divide by 0 corner-case I did not take care of; I leave that up to you.
You can use some simple math to calculate the mean values incrementally. However you have to count how many values contribute to the mean.
Let's say you have n numbers with a mean value of m. Your next number x contributes to the mean in the following way:
m = (mn + x)/(n+1)
It's bad for performance to divide and then multiply the average back. I suggest you store the sum and number.
(pseudocode)
// these variables are stored between function calls
int sum
int n
function float getNextRandomAverage() {
int rnd = getOneRandom()
n++;
sum += rnd;
float avg = sum/n
return avg
}
function writeNextRandomAverage() {
writeToFile(getNextRandomAverage())
}
Also it seems strange to me that your method closes the file. How does it know that it should close it? What if the file should be used later? (Say, consecutive uses of this method).