First of all, welcome to StackOverflow! I'm sure you'll find it an invaluable resource as you're learning to program. That said, to get the most from the site, it'll be important to observe the site's guidelines. In general, keep in mind that SO's not a forum but rather a Q&A site, and you'll be doing well.
GENERAL ISSUES
There are a few issues with the code you've posted:
A. Whitespace
Using whitespace is very helpful for making your code legible and intelligible both to other programmers and to you yourself. Tabbing to indicate scope (writing
bool condition = ...
if (condition) {
action();
}
rather than
bool condition = ...
if (condition) {
action()
}
which doesn't indicate the scope of action) dramatically increases readability, especially when, as in the code you posted, there are multiple nested scopes. Spacing is important as well.
B. Using cout
1.
Rather than writing cout << "" << endl
, you can simply write cout << endl
.
2.
There are differences between endl
and "\n"
, and it appears from your code that you may be aware of them. While the performance characteristics of using the two are not identical, considering that at this stage would certainly be premature optimization. It's more readable to stick with endl
for this kind of logging. Rather than
cout << "All cycle #1 approximate square are guessed\n" << "using 1 as the approximate." << endl;
it would be better to write
cout << "All cycle #1 approximate square are guessed" << endl << "using 1 as the approximate." << endl;
in this context.
3.
If you're inserting int cout
more than fits comfortably in one line of code (this code,
cout << "This line of code is longer than feels comfortable." << endl << "It would be much more pleasant to break this into several lines so that I don't need to scroll to the right to view the whole thing." << endl;
for example, is too long for one line), rather than, as in your code,
cout << "Anmol's Square Root Calculator!" << endl;
cout << endl;
cout << "This program will compute the square root\n";
cout << "of a number using the Babylonian algorithm!\n";
cout << endl;
cout << "Only positive numbers work with this algorithm!" << endl;
cout << endl;
cout << "All cycle #1 approximate square are guessed\n" << "using 1 as the approximate." << endl;
cout << endl;
cout << endl;
cout << endl;
using the insertion operator on cout
multiple times, you can just write
cout << "Anmol's Square Root Calculator!" << endl
<< endl
<< "This program will compute the square root" << endl
<< "of a number using the Babylonian algorithm!" << endl
<< endl
<< "Only positive numbers work with this algorithm!" << endl
<< endl
<< "All cycle #1 approximate square are guessed" << endl
<< "using 1 as the approximate." << endl
<< endl
<< endl
<< endl;
C. Modularity
All of your code is in main()
. Even with a program of this short length, that still hampers readability. More importantly, it means that you can't reuse the functionality you've created in this program elsewhere.
A good approach is to break up your program into its separate components. In this program, you've got the following setup:
show a greeting
do {
get number from user
compute the squareroot of that number while logging
show the user the squareroot
ask the user if they want to do another computation
} while the user wants the program to keep running
show a farewell
At this point, you can write functions for each step. The functions I'm "writing" here are excerpted from your code with very slightly modifications.
Printing to the screen
The functions for showing a greeting and a farewell to the user are the easiest since they (almost) just require using cout
:
void showGreeting()
{
cout << "Anmol's Square Root Calculator!" << endl
<< endl
<< "This program will compute the square root" << endl
<< "of a number using the Babylonian algorithm!" << endl
<< endl
<< "Only positive numbers work with this algorithm!" << endl
<< endl
<< "All cycle #1 approximate square are guessed" << endl
<< "using 1 as the approximate." << endl
<< endl
<< endl
<< endl;
}
void showFarewell()
{
cout << "Thank you for using a program made by Anmol Sethi!" << endl
<< endl
<< endl
<< endl;
cin.get();
}
Getting user input
Next we need a function to get a number from the user
double getInputNumber()
{
double num = 0.0f;
cout << "Please enter the number you would like to compute the square root of: ";
cin >> num;
cout << endl;
do {
if (num <= 0)
{
cout << endl
<< "Invalid input. Please re-enter a valid number: ";
cin >> num;
cout << endl;
}
} while (num <= 0);
cout << endl
<< endl
<< endl;
return num;
}
In addition, we need to determine whether the user wants the program to run again. From the perspective of the program (the perspective of main
), this is very much a boolean question: we should call some function and it should return true
or false
. Within the function, though, we are interacting with the user, so using 'y'
and 'n'
is ideal (at least for users who speak English);
bool getRunAgain()
{
bool choice = false;
char playAgain = 'n';
do {
cout << endl
<< "Would you like to calculate again? (y/n): ";
cin >> playAgain;
cout << endl;
do {
cout << endl;
if ((playAgain !='y' && playAgain !='n'))
{
cout << "Invalid input. Only y/n: ";
cin >> playAgain;
cout << endl;
}
} while (playAgain !='y' && playAgain !='n');
} while (playAgain !='y' && playAgain !='n');
if (playAgain == 'y') {
choice = true;
} else /*if (playAgain == 'n')*/ {//At this, playAgain is either 'y' or 'n'. So if it's not 'y', it's 'n'.
choice = false;
}
return choice;
}
Thanks to rewriting this code as a function, it's easier to see that more work is being done here than is necessary: Consider the outer do...while
loop. Its condition for repeating is that playAgain !='y' && playAgain !='n'
. At first glance, that seems to make sense: we need to make sure that the user has either entered "yes" or "no". But notice that there's an inner do...while
loop with exactly the same condition. That means that the inner loop will not exit unless playAgain
is equal to either 'y'
or 'n'
. So by the time we leave the inner loop, we can be sure that playAgain
is either 'y'
or 'n'
. So we don't need to check it again. This allows us to rewrite the function like this:
bool getRunAgain()
{
bool choice = false;
char playAgain = 'n';
cout << endl
<< "Would you like to calculate again? (y/n): ";
cin >> playAgain;
cout << endl;
do {
cout << endl;
if ((playAgain !='y' && playAgain !='n'))
{
cout << "Invalid input. Only y/n: ";
cin >> playAgain;
cout << endl;
}
} while (playAgain !='y' && playAgain !='n');
if (playAgain == 'y') {
choice = true;
} else /*if (playAgain == 'n')*/ {
choice = false;
}
return choice;
}
But we have a similar situation within the remaining loop:
do {
cout << endl;
if ((playAgain !='y' && playAgain !='n'))
{
cout << "Invalid input. Only y/n: ";
cin >> playAgain;
cout << endl;
}
} while (playAgain !='y' && playAgain !='n');
Except for the cout << endl
which is not all too important, it looks like we don't want to enter the loop at all unless (playAgain !='y' && playAgain !='n')
. This calls for a while
loop rather than a do...while
loop:
while (playAgain !='y' && playAgain !='n')
{
cout << "Invalid input. Only y/n: ";
cin >> playAgain;
cout << endl;
}
Dropping this into our function, we now have
bool getRunAgain()
{
bool choice = false;
char playAgain = 'n';
cout << endl
<< "Would you like to calculate again? (y/n): ";
cin >> playAgain;
cout << endl;
while (playAgain !='y' && playAgain !='n')
{
cout << "Invalid input. Only y/n: ";
cin >> playAgain;
cout << endl;
}
if (playAgain == 'y') {
choice = true;
} else /*if (playAgain == 'n')*/ {
choice = false;
}
return choice;
}
Computing the square root
Finally, we need a function to compute the square root using the Babylonian algorithm. We just need to take your code
int count(25), cycle(1);
double guess, sqrt, num;
cout << "Please enter the number you would like to compute the square root of: ";
cin >> num;
cout << endl;
for (guess=1; count!=0; count--)
{
guess =(guess + (num/guess))/2;
cout<<""<<endl;
cout<<"Cycle "<<cycle<<" Aproximate: "<<guess<<endl;
sqrt = guess;
cycle++;
}
and put it into a function that takes a double and gives one back:
double computeSquareRootBabylonian(double num)
{
int count(25), cycle(1);
double guess, sqrt;
for (guess = 1; count != 0; count--)
{
guess = (guess + (num/guess))/2;
cout << endl
<< "Cycle " << cycle << " Aproximate: " << guess << endl;
sqrt = guess;
cycle++;
}
return sqrt;
}
We could stop here, but there are a couple of changes that would improve the function.
1.
The initial approximation (the initial guess that you're using, 1
) isn't really part of this function. The code that calls this function should have to specify that starting point:
double computeSquareRootBabylonian
(double num,
double initialApproximation)
{
double approximation, sqrt;
unsigned int count(25), cycle(1);
for (approximation = initialApproximation; count != 0; count--)
{
approximation =(approximation + (num/approximation))/2;
cout << endl
<< "Cycle " << cycle << " Aproximate: " << approximation << endl;
sqrt = approximation;
cycle++;
}
return sqrt;
}
2.
The number of iterations (or cycles, as you're calling them) isn't really a part of the function either. The code that calls this function should have to specify that number:
double computeSquareRootBabylonian
(double num,
double initialApproximation,
unsigned int iterations)
{
double approximation, sqrt;
unsigned int iterationsRemaining = iterations;
unsigned int iteration = 1;
for (approximation = initialApproximation; iterationsRemaining != 0; iterationsRemaining--)
{
approximation =(approximation + (num/approximation))/2;
cout << endl
<< "Cycle " << iteration << " Aproximate: " << approximation << endl;
sqrt = approximation;
iteration++;
}
return sqrt;
}
3.
This for
loop is strange. It's strange because you initialize the variable guess
(which I've renamed approximation
) in the initialization, though it is not the "loop variable". In your second chunk of code, you used
while (count > 0)
{
guess =(guess + (num/guess))/2;
cout << endl;
cout << "Cycle " << cycle << " Aproximate: " << guess << endl;
sqrt = guess;
count-=1;
cycle+=1;
}
instead. The intent of this code is much clearer, but the intent would be clearest using a for
loop the standard way (initializing the same variable in the initialization which the condition of the loop depends on and which is changed at the end of each loop: for (int i = 0; i < 10; i++)
). The variable that's being iterated over here is the count
(what I've termed iterationsRemaining
), and it's being decreased from the number of iterations that the user specifies (the iterations
argument) by 1
as long as it's greater than 0
. This situation calls for the following for loop:
for (unsigned int iterationsRemaining = iterations;
iterationsRemaining > 0;
iterationsRemaining--)
{
//...
}
When substituting this into our function, we need to be sure to still initialize approximation
to initialApproximation
:
double computeSquareRootBabylonian
(double num,
double initialApproximation,
unsigned int iterations)
{
double approximation = initialApproximation;
unsigned int iteration = 1;
double sqrt;
for (unsigned int iterationsRemaining = iterations;
iterationsRemaining > 0;
iterationsRemaining--)
{
approximation =(approximation + (num/approximation))/2;
cout << endl
<< "Cycle " << iteration << " Aproximate: " << approximation << endl;
sqrt = approximation;
iteration++;
}
return sqrt;
}
Aside: More premature optimization
You wrote
In a book I read its more efficient to use a for loops for algorithms so I wanna use the for instead of the while loop.
This is not a good reason to use a for
loop. You don't (within reason) need to make a change to your code to make it faster unless you're sure that it's running too slowly. It's far more important to write code that makes sense when you read it.
4.
What does the variable sqrt
do? It repeatedly has the value of approximation
assigned to it and is returned from the function, but its value when it is returned is the same as the value of approximation
. Removing it for this reason amounts to premature optimization. However, calling the variable sqrt
suggests that it is the true square root rather than an approximation. For this reason, it should be removed, leaving us with
double computeSquareRootBabylonian
(double num,
double initialApproximation,
unsigned int iterations)
{
double approximation = initialApproximation;
unsigned int iteration = 1;
for (unsigned int iterationsRemaining = iterations;
iterationsRemaining > 0;
iterationsRemaining--)
{
approximation =(approximation + (num/approximation))/2;
cout << endl
<< "Cycle " << iteration << " Aproximate: " << approximation << endl;
iteration++;
}
return approximation;
}
5.
Logging the successive approximations on each iteration isn't the kind of thing you would always want a square root function to do. We should add an argument allowing the calling code to specify whether the approximations are logged:
double computeSquareRootBabylonian
(double num,
double initialApproximation,
unsigned int iterations,
bool log)
{
double approximation = initialApproximation;
unsigned int iteration = 1;
for (unsigned int iterationsRemaining = iterations;
iterationsRemaining > 0;
iterationsRemaining--)
{
approximation =(approximation + (num/approximation))/2;
if (log)
{
cout << endl << "Cycle " << iteration << " Aproximate: " << approximation << endl;
}
iteration++;
}
return approximation;
}
Writing the main function
We now have all the component pieces of the program in place. We just need to turn our plan
show a greeting
do {
get number from user
compute the squareroot of that number while logging
show the user the squareroot
ask the user if they want to do another computation
} while the user wants the program to keep running
show a farewell
into a complete program:
int main(int argc, char *argv[])
{
//Do this stuff.
}
To begin with, we know how to begin and end the program. We want to show the greeting and the farewell using our functions showGreeting()
and showFarewell()
:
int main(int argc, char *argv[])
{
showGreeting();
//do {
//get number from user
//compute the squareroot of that number while logging
//show the user the squareroot
//ask the user if they want to do another computation
//} while the user wants the program to keep running
showFarewell();
}
We know that we want to get the user input and compute the square root at least once, and we know that we can get a bool
which represents whether the user wants to compute another square root using our function getRunAgain()
. We should do
the user input and the computation while
getRunAgain()
!
int main(int argc, char *argv[])
{
showGreeting();
do {
//get number from user
//compute the squareroot of that number while logging
//show the user the squareroot
} while(getRunAgain());
showFarewell();
}
We have a function getInputNumber()
which returns a double
representing the number that the user wants to compute the square root of. We need to use this double
twice, once as an argument to the square root function computeSquareRootBabylonian()
and once to output the input and its square root to the user. As a result, we'll need a local variable:
int main(int argc, char *argv[])
{
showGreeting();
do {
double number = getInputNumber();
//compute the squareroot of that number while logging
//show the user the squareroot
} while(getRunAgain());
showFarewell();
}
Now our square root function computeSquareRootBabylonian()
takes four arguments:
- the number of which to compute the square root
- the initial approximation
- the number of iterations
- whether to log each successive approximation
We will pass number
as the first argument. For now, we can hardcode the remaining arguments, using 1
for the initial approximation, 25
for the number of iterations, and true
for whether to log.
Since we only need to use the result of computeSquareRootBabylonian()
once (when logging out the result), we could get away without using a local variable. For clarity, though, let's go ahead and use one:
int main(int argc, char *argv[])
{
showGreeting();
do {
double number = getInputNumber();
double squareRoot = computeSquareRootBabylonian(number, 1.0f, 25, true);
//show the user the squareroot
} while(getRunAgain());
showFarewell();
}
We just need to show the result to the user:
int main(int argc, char *argv[])
{
showGreeting();
do {
double number = getInputNumber();
double squareRoot = computeSquareRootBabylonian(number, 1.0f, 25, true);
cout << endl
<< "The square root of " << num << " is " << sqrt << "!" << endl
<< endl;
} while(getRunAgain());
showFarewell();
}
One thing has been left out of this program: configuring the precision of cout
.
int main(int argc, char *argv[])
{
cout.precision(50);
showGreeting();
do {
double number = getInputNumber();
double squareRoot = computeSquareRootBabylonian(number, 1.0f, 25, true);
cout << endl
<< "The square root of " << num << " is " << sqrt << "!" << endl
<< endl;
} while(getRunAgain());
showFarewell();
}
RESTATING THE QUESTION
You asked a couple of questions about cout
:
In this code [the first main
function] I specifically set the precision of the decimals to 15. However it outputs numbers at 12 decimals. But in this code [the second main
function] it outputs at 15 decimals. [...] Im very confused on why this is happening. I tried cout << fixed << showpoint; but it looks unpleasant when the num outputs 15 zeros for no reason. Can anyone enlighten me on why this is happening and how to fix it?
Why cant I go over the 15 decimals? If I set the precision to 30/40 it does nothing to my output even though in my computer calculator it goes to 30/40. Is there another integer type I should use instead of double?
I'll address these questions in a moment. First, I'll describe how I would have asked them myself in order to get better and quicker responses on StackOverflow.
The main point is to post a short, self-contained, correct (compilable), example. So what exactly is the problem here? It has to do with using inserting (using operator <<
) into std::cout
(into std::ostream
in general). It has to do with formatting double
output using std::ostream::precision
. After reducing the problem to this point, I would start looking at the relevant documentation and, if that did not provide a sufficient explanation, searching on StackOverflow using these keywords. If I could not find the solution to my problem, I would generate an example which illustrates the difficulty I'm having.
Coming up with the first question
The first problem is that when we set the precision of cout to 15, we're only getting 12 decimals. Let's write a program which initializes a double
to a value, sets the precision of cout
to 15
and inserts our double
into cout
:
#include <iostream>
using namespace std;
int main(int argc, char *argv[])
{
double value = 1.1111111111111111111111111f;
cout.precision(15);
cout << value << endl;
return 0;
}
This program prints out
1.11111111111111
This number has only 14 1
's after the decimal point. Though it's not quite what we were hoping for (there are 14 rather than 12 digits after the decimal place), it looks like we're on the right track. It looks like some sort of rounding behavior is going on. Perhaps we should put zeros in the thirteenth and fourteenth decimal places:
#include <iostream>
using namespace std;
int main(int argc, char *argv[])
{
double value = 1.1111111111110011111111111f;
cout.precision(15);
cout << value << endl;
return 0;
}
This program's output
1.111111111111
has only 12 digits, as we were hoping. So we now have a short, self-contained, correct (compilable), example to put in our question.
Stating the first question
I'm using std::cout
to output a double
. I would like to display the first 15 digits after the decimal point, or at least as many of them as are non-zero. But in this code, for example
int main(int argc, char *argv[])
{
double value = 1.1111111111110011111111111f;
cout.precision(15);
cout << value << endl;
return 0;
}
the output is 1.111111111111
rather than 1.111111111111001
as I expected. I was able to address this by using std::fixed
int main(int argc, char *argv[])
{
double value = 1.1111111111110011111111111f;
cout.precision(15);
cout << std::fixed << value << endl;
return 0;
}
which does output 1.111111111111001
as expected. Unfortunately, using std::fixed
results in always printing 15 digits after the decimal even if all those digits are zero. For example the output from
int main(int argc, char *argv[])
{
double value = 1.0f;
cout.precision(15);
cout << std::fixed << value << endl;
return 0;
}
is 1.000000000000000
rather than 1
as I had hoped.
How can I use cout
to output up to 15 decimal digits and fewer when all the remaining digits are zero?
Coming up with the second question
The second problem is that no matter how much higher than 15 we set cout
's precision to be, we only get 15 decimal digits in our output. Let's write a program which initializes a double
to a value, sets the precision of cout
to 30
and inserts our double
into cout
:
int main(int argc, char *argv[])
{
double value = 1.55f;
cout.precision(30);
cout << value << endl;
return 0;
}
This outputs 1.5499999523162841796875
, a number which consists of 22 digits after the decimal place. This suggests that we were somehow getting unlucky to be getting exactly 15 digits of output: the same sort of rounding behavior that we encountered when coming up with the first question evidently is interacting with the output from the value returned from the square root function such that under this rounding behavior, fifteen digits after the decimal place were being printed.
ANSWERING THE QUESTION
You want to insert a double
into cout
such that as many as possible non-zero decimal digits are displayed, up to 15. The string representation of the double
s in cout
should satisfy at least the following tests:
x.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxf ----> "x.xxxxxxxxxxxxxxx"
x.xxxxx0000000000000000000000000f ----> "x.xxxxx"
x.000000000000000000000000000000f ----> "x"
x.00000000000000x000000000000000f ----> "x.00000000000000x"
This cannot be achieved in any obvious way by using std::ostream::precision
. As you pointed out, we can't use std::fixed
since that will certainly fail our third test above. We can't easily use the default either since, as stated at cplusplus.com,
On the default floating-point notation, the precision field specifies the maximum number of meaningful digits to display in total counting both those before and those after the decimal point.
This means that we need to take the number of digits before the decimal place into account. If there are 3 digits before the decimal place, we need to use a precision of 15+3, and so forth.
One way to achieve this is a function which takes a double
and returns a std::string
:
std::string stringFromDouble(double value, unsigned int decimalDigits)
{
int integerComponent = abs((value > 0) ? (int)(floor(value)) : (int)(ceil(value)));
std::ostringstream integerStream;
integerStream << integerComponent;
std::string integerString = integerStream.str();
unsigned int integerLength = integerString.length();
std::ostringstream stream;
stream.precision(decimalDigits + integerLength);
stream << value;
std::string str = stream.str();
return str;
}