1
#include <iostream>
using namespace std;

int main()
{
    cout.precision(50);
    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 roots are guessed\n"<<"using 1 as the first        approximate."<<endl;
    cout<<""<<endl;
    cout<<""<<endl;
    cout<<""<<endl;



    char playAgain='y';
    while (playAgain !='n') 
    {
        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;

        do {
            if (num <= 0)
            {
                cout<<""<<endl;
                cout<<"Invalid input. Please re-enter a valid number: ";
                cin >> num;
                cout<<""<<endl;
            }
        } while (num <= 0);

        cout<<""<<endl;
        cout<<""<<endl;
        cout<<""<<endl;

        for (guess=1; count!=0; count--)
        { 
            guess =(guess + (num/guess))/2;
            cout<<""<<endl;
            cout<<"Cycle "<<cycle<<" Aproximate: "<<guess<<endl;
            sqrt = guess;

            cycle++;
        }

        cout<<""<<endl;

        cout << "The square root of "<< num << " is " << sqrt<<"!"<<endl;;
        cout <<""<< endl;

        do { 
            cout <<""<<endl;
            cout << "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');

    }

    cout<<"Thank you for using a program made by Anmol Sethi!"<<endl;
    cout<<""<<endl;
    cout<<""<<endl;
    cout<<""<<endl;
    cin.get();
    return 0;
}

For my math class we are learning about square roots. According to my teacher its only possible to find the square root using a calculator or a table which is pretty obviously false as the calcuator needs a method to compute the sqrt. After extensive research I made this code using the Babylonian algorithm. But im facing a problem In this code I specifically set the precision of the decimals to 15. However it outputs numbers at 12 decimals. But in this code it outputs at 15 decimals.

#include <iostream>
using namespace std;

int main()
{
    cout.precision(18);
    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;
    char playAgain='y';
    while (playAgain !='n') 
    {
        int count(25), cycle(1);
        double guess(1), sqrt, x, num; 
        cout << "Please enter the number you would like to know the square root of: ";
        cin >> num;
        cout<<""<<endl;

        do {
            if (num <= 0)
            {
                cout<<""<<endl;
                cout<<"Invalid input. Please re-enter a valid number: ";
                cin >> num;
                cout<<""<<endl;
            }
        } while (num <= 0);

        cout<<""<<endl;
        cout<<""<<endl;
        cout<<""<<endl;

        while (count > 0)
        {
            x = guess =(guess + (num/guess))/2;
            cout<<""<<endl;
            cout<<"Cycle "<<cycle<<" Aproximate: "<<guess<<endl;
            sqrt = guess;

            count-=1;
            cycle+=1;
        }

        cout<<""<<endl;
        cout<<""<<endl;
        cout<<""<<endl;
        cout << "The sqaure root of "<< num << " is " << sqrt<<"!"<<endl;;
        cout <<""<< endl;

        do { 
            cout <<""<<endl;
            cout << "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');

    }

    cout<<"Thank you for using a program made by Anmol Sethi!"<<endl;
    cout<<""<<endl;
    cout<<""<<endl;
    cout<<""<<endl;
    cout<<""<<endl;
    cin.get();
    return 0;

}

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? 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. Also I have a second question. 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?

Sorry if any of it looks like a big wall of text xD.

Im in a rush to type this cause its 12:05am for me atm.

Thanks in advance :D

p.s Im gonna be posting alot on this forum now. I used to use it alot about a year ago but I quit c++ programming for a while because I couldnt understand it further when I was smaller xD. So im reading a book now for it and I hopefully get all the way through the console applications and on to windows. I am using visual studio ultimate 2012 if it matters. xD

Jason C
  • 38,729
  • 14
  • 126
  • 182
Anmol Sethi
  • 21
  • 1
  • 2
  • Please indent properly, it's much easier to read that. `fmt` on linux is good – daniel gratzer Jan 12 '13 at 05:51
  • Or astyle, cident, bcpp, whatnot. Just use vim, emacs, sublime-text, any IDE (eclipse, code::blocks, MSVS Express etc.) and it comes builtin and free of charge. – sehe Jan 13 '13 at 16:20

1 Answers1

7

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 doubles 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;
}
Community
  • 1
  • 1
Nate Chandler
  • 4,533
  • 1
  • 23
  • 32
  • 2
    Wait wat?! You critique the question, saying how it should be clear and legible. Then you bury any remnants of answer under a thick layer of normative ... banter? TL;DR from me – sehe Jan 13 '13 at 16:19
  • 2
    Wow, I'm really impressed by the size of the answer – Andriy Tylychko Jan 13 '13 at 18:10