Can I make this more efficient with loop? - c++

if(diff != 0){
if(diff >= 50){
if(userGuess > toGuess){
cout << "Very high" << endl;
} else if (userGuess < toGuess){
cout << "Very low" << endl;
}
}
if(diff >= 30 && diff < 50){
if(userGuess > toGuess){
cout << "high" << endl;
} else if (userGuess < toGuess){
cout << "low" << endl;
}
}
if(diff >= 15 && diff < 30){
if(userGuess > toGuess){
cout << "Moderately high" << endl;
} else if (userGuess < toGuess){
cout << "Moderately low" << endl;
}
}
if(diff > 0 && diff < 15){
if(userGuess > toGuess){
cout << "Somewhat high" << endl;
} else if (userGuess < toGuess){
cout << "Somewhat low" << endl;
}
}
}
These if statement are in loops that run until the correct number is guessed, my question is, instead of having all these if statements can I make it better with a big loop.

You can certainly make it more readable, the approach is to make more functions and to group things together. And then you can do all your tests in a loop.
(You might want to refine the logic for negative numbers, I didn't test the correctness of all corner cases for you)
For example :
#include <iostream>
#include <string>
#include <string_view>
#include <vector>
#include <limits>
// group all information to be able to give a hint in one struct
struct hint
{
bool in_range(int v) const noexcept
{
return (v>= min) && (v< max);
}
int min;
int max;
std::string_view output;
};
// then make a function that will return the correct hint
// for a given difference value
std::string_view get_hint(const int dif)
{
// instead of having a global variable I use a static local variable, this is initialized only once.
// use initializer list to initialize all hint structures
static std::vector<hint> hints
{
{50,std::numeric_limits<int>::max(),"very high"},
{30,50,"high"},
{15,30,"moderately high"},
{0,15, "somewhat high" },
{-15,0, "somewhat low" },
{-30,-15, "moderately low"},
{-50,-30, "low"},
{std::numeric_limits<int>::min(), -50, "very low"}
};
// check which hint text to return
// This is the part where a loop helps
for (const auto& hint : hints)
{
if (hint.in_range(dif)) return hint.output;
}
return {};
};
int main()
{
std::cout << get_hint(-1) << "\n";
std::cout << get_hint(49) << "\n";
std::cout << get_hint(50) << "\n";
std::cout << get_hint(-17)<< "\n";
return 0;
}

The main lesson here is that the compiler will almost always outsmart you and do it the fastest way it knows how. The code you have posted seems extremely unlikely to have any meaningful impact on the speed of your program.
Instead, it is often better to choose an approach which makes your code easier to read and maintain. For example, you could try something like this:
// Add size prefix based on difference
if (diff > 50) {
cout << "Very ";
} else if (diff >= 30) {
// No prefix
} else if (diff >= 15) {
cout << "Moderatly ";
} else {
cout << "Somewhat ";
}
// State if code was low or high
if (userGuess > toGuess) {
cout << "high" << endl;
} else {
cout << "low" << endl;
}

Related

why does my code not read or follow the if statements?

Why does my code not read or follow the if statements?
#include<iostream>
using namespace std;
int main (){
int sum = 0;
int integer;
while ((integer != -1) && (sum < 2000)){
int integer;
cout<<"Enter an integer: ";
cin>>integer;
if (integer == -1){
cout<<"Program was terminated.\n"<<"Your total sales are: "<<sum<<endl;
break;
}
else if (sum >= 2000) {
cout<<"Congratulations!"<<"Your total sales are: "<<sum<<endl;
break;
}
sum = sum + integer;
if (sum > 499){
cout<<"You're off to a good start!"<<endl;
}
if (sum > 999){
cout<<"You're halfway through!"<<endl;
}
else if (sum > 1499){
cout<<"You're almost there!"<<endl;
}
}
return 0;
}
Expected:
Input looks like:
Enter an interger: 350, 500,800, 500
Then the out should look like:
Enter an integer 350
" " 500
youre off to a good start
800
youre halfway through
500
Congratualations! Youre total sales are: 2150
Reality:
Enter an integer: 350
Enter an integer: 500
You're off to a good start!
Enter an integer: 800
You're off to a good start!
You're halfway through!
Enter an integer: 500
You're off to a good start!
You're halfway through!
you want only 1 branch to be entered, so you need a if else if chain.
if (sum >= 2000) {
std::cout << "Congratulations!" << "Your total sales are: " << sum << std::endl;
break;
}
else if (sum > 1499) {
std::cout << "You're almost there!" << std::endl;
}
else if (sum > 999) {
std::cout << "You're halfway through!" << std::endl;
}
else if (sum > 499) {
std::cout << "You're off to a good start!" << std::endl;
}
You have to start with the largest number to the smallest one, since if you go from smaller to larger, if a branch is entered it will always be the first branch.
while ((integer != -1) && (sum < 2000)){
this is wrong, as integer is not initialiazed and this is therefore undefined behaviour. In some cases it might never enter the while loop because integer holds some random garbage value that happens to be -1.
You can replace it with a simple while true loop:
while (true) {
since you are calling break; in the final branches anyway (this escapes the while loop). This will also fix the bug, that the loop would terminate before the final print outs.
int integer;
while ((integer != -1) && (sum < 2000)) {
int integer;
you just declared integer twice, the second one is not needed.
Full code:
#include <iostream>
int main() {
int sum = 0;
int integer;
while (true) {
std::cout << "Enter an integer: ";
std::cin >> integer;
if (integer == -1) {
std::cout << "Program was terminated.\n" << "Your total sales are: " << sum << std::endl;
break;
}
sum = sum + integer;
if (sum >= 2000) {
std::cout << "Congratulations!" << "Your total sales are: " << sum << std::endl;
break;
}
else if (sum > 1499) {
std::cout << "You're almost there!" << std::endl;
}
else if (sum > 999) {
std::cout << "You're halfway through!" << std::endl;
}
else if (sum > 499) {
std::cout << "You're off to a good start!" << std::endl;
}
}
}
read Why is "using namespace std;" considered bad practice?

How should I do with "std::cerr" and "std::cin.fail()" using c++?

Could you please help me with the small question?
Question:
The program should return an error code(1) and print this exact string in case a failure is encountered:
“Error encountered, exiting...”
My code:
#include <iostream>
#include <random>
int main(int argc, char const *argv[])
{
int number, random;
random = (std::rand() % 100);
while (std::cin >> number)
{
if (number < random && number >= 0)
{
std::cout << "This number is larger." << std::endl;
}
else if (number > random && number <= 99)
{
std::cout << "This number is smaller." << std::endl;
}
else if (std::cin.fail())
{
std::cout << "Error encountered, exiting..." << std::endl;
}
else if (number < 0 || number > 99)
{
std::cout << "[WARNING] : Number must be between 0 and 99" << std::endl;
}
else if (number == random)
{
std::cout << "Great! You're right!" << std::endl;
break;
}
};
return 0;
}
After compilation, I will input e.g. 'write'. My programming is directly finished. I don't get 'Error encountered, exiting...' in my terminal.
Could you give some suggestions about std::cin.fail()? How should I do?
I also don't understand, could I change here std::cout using std::cerr? What is the big difference between std::cout and std::cerr?
Thanks so much
Best regards
You should test std::cin.fail() after the while loop because if std::cin >> number fails, the body of the while loop will not be entered.
You could also restructure the tests a bit to not have to perform the same tests over and over again. Also, std::endl flushes the output stream which is unnecessary in the vast majority of cases and just takes extra time.
// ...
while (std::cin >> number)
{
if (number < 0 || number > 99)
{
std::cout << "[WARNING] : Number must be between 0 and 99\n";
}
else if (number < random) // no need to test if it's out of bounds
{
std::cout << "This number is larger.\n";
}
else if (number > random) // no need to test if it's out of bounds
{
std::cout << "This number is smaller.\n";
}
else // no need to test anything
{
std::cout << "Great! You're right!\n";
break;
}
}
if(std::cin.fail())
{
std::cout << "Error encountered, exiting...\n";
return 1;
}
return 0;
}
The difference between std::cout and std::cerr is which output stream it'll use. People running your program can read both streams separately if they want to do logging of errors for example.

expected unqualified id before return 0

I'm new to C++. I have errors. But, i dont know how to fix it. Could anyone please help me? Thank you.
P - Print numbers
A - Add a number
M - Display mean of the numbers
S - Display the smallest number
L - Display the largest number
Q - Quit
Errors : expected unqualified id before return 0
error : expected ';' before {}
#include <iostream>
#include <vector>
using namespace std;
int main(){
char input {};
vector <double> numbers {};
int number{};
int sum{};
int min_number{};
int max_number{};
bool condition {true};
cout << "Enter a command" << endl;
cin >> input;
if(numbers.size() > 0){
while(condition){
if (input == 'P' || input == 'p'){
for(auto x: numbers)
cout << x << endl;
}
else if(input == 'A' || input == 'a'){
cout << "Enter a number";
cin >> number;
numbers.push_back(number);
}
else if(input == 'M' || input == 'm'){
for(auto x : numbers)
sum += x;
cout << sum / numbers.size() << endl;
}
else if(input =='S' || input == 's'){
for(size_t i {0}; i < numbers.size(); ++i)
if(numbers.at(i) < min_number)
min_number =numbers.at(i);
}
else if(input =='L' || input == 'l'){
for(size_t i {0}; i < numbers.size(); ++i)
if(numbers.at(i) > max_number)
max_number =numbers.at(i);
}
else if(input =='Q' || input == 'q'){
condition {false};
}
}
cout << "[] - list is empty, unable to calculate" << endl;
}
return 0;
}
In your section dealing with Q/q, the statement:
condition {false};
is not a valid form of assignment, you should instead use:
condition = false;
The braces are fine for initialisation, but that's not what you're trying to do on that line.
As an aside, this line:
if(numbers.size() > 0){
seems a little strange. Since you initialise the list to empty, the main loop will never start (because it's inside the if block) even though you have already asked the user for input.
That's a runtime error rather than a syntax error but you'll still need to fix it at some point.
I suspect that particular should should be done only as part of the calculation of the mean, so as to avoid dividing by zero.
I have written this for you. Since, you're a learner, I think that you should be practicing better things like STL functions and not using using namespace std; at top.
You may find some things new, but don't be frightened, just search them on some website like cppreference and see what that entity do and how to effectively use it.
There were many logical errors. #paxdiablo has mentioned them in his answer. I have removed every of them and this code works.
#include <algorithm>
#include <cctype>
#include <iostream>
#include <vector>
int main() {
std::vector<double> numbers;
while (true) {
char input;
std::cout << "Enter a command: ";
std::cin >> input;
switch (std::toupper(input)) {
case 'P':
if (numbers.empty())
std::cerr << "The list is empty!" << std::endl;
else {
for (auto &&i : numbers)
std::cout << i << ' ';
std::cout << std::endl;
}
break;
case 'A': {
int number;
std::cout << "Enter a number: ";
std::cin >> number;
numbers.push_back(number);
break;
}
case 'M':
if (numbers.empty())
std::cerr << "The list is empty! Cannot perform the operation!!";
else {
int sum = 0;
for (auto &&i : numbers)
sum += i;
std::cout << "Mean: " << (sum / numbers.size()) << std::endl;
}
break;
case 'S':
std::cout << "Smallest Number: " << *std::min_element(numbers.begin(), numbers.end()) << std::endl;
break;
case 'L':
std::cout << "Largest Number: " << *std::max_element(numbers.begin(), numbers.end()) << std::endl;
break;
case 'Q':
return 0;
default:
std::cerr << "Unrecognised Command!!" << std::endl;
}
}
return 0;
}

C++ Homework Doesn't Loop

So, I'm super new to C++ and am sharing a book with a friend. I'm creating a simple guessing game, where the user imagines a number, and the computer attempts to guess it. When I debug in Visual Studio, the project does make a guess, and properly prints "how did I do?". At this point, it should get user input for the 'feedback' variable. After the prompt, however, it seems as if it will only repeat everything before the 'while' statement. Does the problem concern the feedback char variable (maybe I should've just used 'cin' and integers?), or am I just missing something really obvious?
//Game that attempts to guess a number from one to twenty.
#include "stdafx.h"
#include <iostream>
using namespace std;
int main()
{
auto lowbound = 1;
auto highbound = 20;
auto guess = 10;
auto gamecont = true;
char feedback[1];
cout << " Pick a number from one to twenty in you head and I'll guess it; no cheating!" << endl << endl;
cout << " If my guess is too low, just say (1). If too high, say (2). Say (3) if I've got it. It's (ENTER) to get going!" << endl << endl;
cout << " Waiting on you..." << endl << " ";
cin.get();
while(gamecont)
{
cout << " I'm thinking your number is " << guess << "." << endl << endl;
cout << " How did I do?" << endl << endl << " ";
cin.get(feedback, 1);
if (feedback[1] == 1) // The guess was too low.
{
if (guess == 10)
{
guess = 15;
}
else if (guess >= 15)
{
guess++;
}
else if (guess < 10)
{
guess++;
}
}
else if (feedback[1] == 2) // The guess was too high.
{
if (guess == 10)
{
guess = 5;
}
else if (guess <= 5)
{
guess--;
}
else if (guess > 10)
{
guess--;
}
}
else if (feedback[1] == 3) // The guess was correct.
{
gamecont = false;
}
}
return 0;
}
Sorry if this question is stupid for whatever reason, and thanks in advance for reading.
a journey of a thousand miles begins with a single step, so here´s some aid for your first step:
using namespace std;
don´t do that. std:: is crowded with identifiers you might use too, problems are guaranteed.
char feedback[1];
You´ll never have input longer than 1, so
char feedback;
is more than appropriate. (besides: arrays are 0 based so it should have been char feedback[0]; instead of char feedback[1];)
cout << " Pick a number from one to twenty in you head and I'll guess it; no cheating!" << endl << endl;
std::endl flushes the buffer, no need to do that twice. Simply use '\n':
std::cout << " Pick a number from one to twenty in you head and I'll guess it; no cheating!" << "\n\n";
you´ll get the character code of the key in feedback. '1' is not equal to 1, so
if (feedback == 1)
should be
if (feedback == '1')
Thats it. There still some work remaining to do for you, e.g. the guessing strategy is poor, but that should be a start.
//Game that attempts to guess a number from one to twenty.
#include <iostream>
int main()
{
auto lowbound = 1;
auto highbound = 20;
auto guess = 10;
auto gamecont = true;
char feedback;
std::cout << " Pick a number from one to twenty in you head and I'll guess it; no cheating!" << "\n\n";
std::cout << " If my guess is too low, just say (1). If too high, say (2). Say (3) if I've got it. It's (ENTER) to get going!" << "\n\n";
std::cout << " Waiting on you..." << "\n\n";
std::cin.get();
while(gamecont)
{
std::cout << " I'm thinking your number is " << guess << "." << "\n\n";
std::cout << " How did I do?" << "\n\n";
std::cin.ignore();
std::cin.get(feedback);
if (feedback == '1') // The guess was too low.
{
if (guess == 10)
{
guess = 15;
}
else if (guess >= 15)
{
guess++;
}
else if (guess < 10)
{
guess++;
}
}
else if (feedback == '2') // The guess was too high.
{
if (guess == 10)
{
guess = 5;
}
else if (guess <= 5)
{
guess--;
}
else if (guess > 10)
{
guess--;
}
}
else if (feedback == '3') // The guess was correct.
{
gamecont = false;
}
}
return 0;
}

Jumping into c++ chapter 5 prob 7

as recommended I've been working through the book 'Jumping into c++'. I'm currently on problem 7 of chapter 5 and although I have produced the code that appears to do what is asked of me I was hoping someone might be able to take a look and tell me if I've implemented any 'bad' practice (Ideally I don't want to be picking up bad habits already).
Secondly, it also says 'try making a bar graph that shows the results properly scaled to fit on your screen no matter how many results were entered'. Again, the code below produces a horizontal bar graph but I'm not convinced that if I had say 10000 entries (I guess I could verify this by adding an additional for loop) that it would scale according. How would one go about applying this? (such that it always properly scales regardless of how many entries).
I should probably point out at this point that I have not covered topics such as arrays, pointers and classes as of yet in case anyone was curious as to why I didn't just create a class called 'vote' or something.
One final thing... I don't have a 'return 0' in my code, is this a problem? I find it slightly confusing as to what exactly the point of having return 0 is. I know that it's to do with making sure your code is running properly but it seems sort of redundant?
Thanks in advance!
#include <iostream>
using namespace std;
int main()
{
int option;
int option_1 = 0;
int option_2 = 0;
int option_3 = 0;
cout << "Which is your favourite sport?" << endl;
cout << "Tennis.. 1" << endl;
cout << "Football.. 2" << endl;
cout << "Cricket.. 3" << endl;
cin >> option;
while(option != 0)
{
if(option == 1)
{
option_1++;
}
else if(option ==2)
{
option_2++;
}
else if(option ==3)
{
option_3++;
}
else if(option > 3 || option < 0)
{
cout << "Not a valid entry, please enter again" << endl;
}
else if(option ==0)
{
break;
}
cout << "Which is your favourite sport?" << endl;
cout << "Tennis.. 1" << endl;
cout << "Football.. 2" << endl;
cout << "Cricket.. 3" << endl;
cin >> option;
}
cout << "Option 1 (" << option_1 << "): ";
for(int i = 0; i < option_1; i++)
{
cout << "*";
}
cout << "" << endl;
cout << "Option 2 (" << option_2 << "): ";
for(int i = 0; i < option_2; i++)
{
cout << "*";
}
cout << "" << endl;
cout << "Option 3 (" << option_3 << "): ";
for(int i = 0; i < option_3; i++)
{
cout << "*";
}
}
About the return 0 in main : it's optional in C++.
About your code:
You have a ton of if / else if blocks, you should replace them with a switch. A switch statement is more compact, readable, and may be a little bit faster at runtime. It's not important at this point, but it's pretty good practice to know where to put a switch and where to use regular if.
You have one big function, it's really bad. You should break your code into small, reusable pieces. That's something called DRY (Don't repeat Yourself): if you are copy-pasting code, you're doing something wrong. For example, your sport list appears 2 times in your code, you should move it in a separate function.
You wrote cout << "" << endl;, I think you don't really understand how std::cout work. std::cout is an object representing the standard output of your program. You can use operator<< to pass values to this standard output. std::endl is one of these values you can pass, strings are, too. So you can just write cout << endl;, no need for an empty string.
Please learn how to use arrays, either raw ones or std::array. This is a pretty good example of a program which can be refactored using arrays.
Here is a more readable, cleaner version of your code:
#include <iostream>
int prompt_option()
{
int option;
while (true)
{
std::cout << "Which is your favourite sport?" << std::endl;
std::cout << "Tennis.. 1" << std::endl;
std::cout << "Football.. 2" << std::endl;
std::cout << "Cricket.. 3" << std::endl;
std::cin >> option;
if (option >= 0 && option <= 3)
return option;
else
std::cout << "Not a valid entry, please enter again" << std::endl;
}
}
void display_option(int number, int value)
{
std::cout << "Option " << number << " (" << value << "): ";
while (value--)
std::cout << '*';
std::cout << std::endl;
}
int main()
{
int option;
int values[3] = {0};
while (true)
{
option = prompt_option();
if (option)
values[option - 1]++;
else
break;
}
for (int i = 0; i < 3; i++)
display_option(i + 1, values[i]);
}
You have too much if else, it messy.
check out the code bellow, muc shorter, cleaner and efficent.
I hope it helps.
#include <iostream>
using namespace std;
int main()
{
int choice;
int soccer=0, NFL=0 ,formula1=0;
while(choice != 0){
cout<<"Please choose one of the following for the poll"<<endl;
cout<<"press 1 for soccer, press 2 for NFL, press 3 for formula 1"<<endl;
cout<<"Press 0 to exit"<<endl;
cin>>choice;
if(choice==1){
soccer++;
}
else if(choice==2){
NFL++;
}
else if(choice == 3){
formula1++;
}
else{
cout<<"Invalid entry, try again"<<endl;
}
cout<<"soccer chosen "<<soccer<<" times.";
for(int i=0; i<soccer; i++){
cout<<"*";
}
cout<<endl;
cout<<"NFL chosen "<<NFL<<" times.";
for(int j=0; j<NFL; j++){
cout<<"*";
}
cout<<endl;
cout<<"formula1 chosen "<<formula1<<" times.";
for(int c=0; c<formula1; c++){
cout<<"*";
}
cout<<endl;
}
return 0;
}