C++/decimals

Advertisement


Question
Hi,

I'm trying to output set precision number of decimal points in my code for the mi/gal.  I am using float, but it currently gives 4.  I'd like 1.  How is the best way to do this?  Here is my code:

// Ch. 2, example 2.16, p. 146

#include <iostream>


using namespace std;

float miles_driven;
float miles;         // totalling
float gallons_used;
float gallons;       // totalling
float x;

int main()
{
  start:
  
  cout << "Enter the number of miles driven (-1 to end): ";
  cin >> miles_driven;

  if (miles_driven >= 0)
  {
     cout << "Enter the number of gallons of gas used in this tank: ";
     cin >> gallons_used;

     x = miles_driven / gallons_used;

     cout << "You went " << x << " mi/gal on this tank." << "\n" << endl;

     miles = miles + miles_driven;  // running count
     gallons = gallons + gallons_used;

     goto start;  // start again
  }

  else if (miles_driven == -1)
  {
     
     x = miles / gallons;
     cout << "You drove an overall average of " << x << " mi/gal.";
  }

  cin.ignore();
  cin.get();
  return 0;

}

Answer
The most obvious way would be to request formatting floating point numbers using fixed point format with a precision of 1 using the std::fixed and std::setprecision manipulators.

I mention the term manipulator as it is the term used for a collection of C++ IOStream types that manipulate stream behaviour - in the case of fixed and setprecision the behaviour with regards to displaying floating point numbers.

The other reason to mention manipulator is in the hope it helps with remembering that some manipulator types - such setprecision - require the header iomanip to be included before they can be used (easily). That and it gives you a term to look up with respect to C++ IO.

Note that if you had tried a search engine site search you would probably have found out about fixed and setprecision for yourself! I tried search for:

   C++ output precision

in Google and the second result lead to:

   http://www.cplusplus.com/reference/iostream/manipulators/setprecision/

You will note from this description that you also need to use fixed or scientific floating point notations (using the fixed or std::scientific manipulators - which should be available if you just include iostream). As in your case fixed point notation would be appropriate we can then look at some blurb on that:

   http://www.cplusplus.com/reference/iostream/manipulators/fixed/

If you do not specify a specific floating point output notation then the value passed to the setprecision manipulator is the maximum number of meaningful digits in the (decimal) floating point value as a whole and not just the number of digits to display after the decimal point.

You will notice that I initially introduce the new manipulator types with the prefix std:: - this is because pretty much all C++ standard library names are in the namespace std and so are fully named with a std:: prefix to indicate this. Your program does not need to use the std:: prefix with such names due to the using namespace std; directive after the #includes.

So. include iomanip for setprecision:

   #include <iostream>
   #include <iomanip>

And in main specify fixed point format with a precision of 1 decimal place for use with cout (these settings are 'sticky' - they remain set until you change them again so placing a line like so as the first line of main should be OK):

       cout << fixed << setprecision(1);

Now a few points on you program:

Firstly what happens if you do not enter valid numbers? (e.g. you press the 'A' key and return)

What happens if you end immediately (meaning your total values are _both_ zero)?

What happens if you enter a negative value other than -1 for miles travelled? And what _should_ happen in this case?

Oh and on a in-practice note be very careful testing for exact floating point values. Such values are approximations and not all values can be accurately represented and often it is necessary to check for a floating point value being within some tolerance value of the required value (often call epsilon). You are probably OK here though.

Next why are you using global variables?

   float miles_driven;
   float miles;         // totalling
   float gallons_used;
   float gallons;       // totalling
   float x;
   
All the above are global to the whole program and not just available to main. OK in this simple example that is not much of a problem but in larger programs it can become one. Do _not_ use global variables unless you _really_ _really_ need to. In fact do not give your variables a greater scope than they require (you can read more on scope in various texts and online e.g.:

   http://en.wikipedia.org/wiki/Scope_(computer_science)
):

Also x is fairly meaningless as a name and is used for two distinct purposes: mile per gallon (mpg) and average mpg. Whilst we are at it miles and gallons could be better named as indicated by the fact you felt the need to add the 'totalling' comments after their definitions.

Finally have you not covered loops yet? This can be the _only_ reason you are using a label and goto to repeat parts of the code. If you have covered loops and are _still_ using goto then please go outside and shoot yourself <grin/> - this is very bad form. There are very few valid uses of goto in code. You could for example use a while loop.

So, putting some of these points together, how about something like this:

// Ch. 2, example 2.16, p. 146

#include <iostream>
#include <iomanip>

using namespace std;

int main()
{
   cout << fixed << setprecision(1);

   float total_miles = 0.0f;
   float total_gallons = 0.0f;

   float miles_driven = 0.0f;
   while ( miles_driven != -1.0f )
   {
       cout << "Enter the number of miles driven (-1 to end): ";
       cin >> miles_driven;

       if (miles_driven >= 0.0f)
       {
         cout << "Enter the number of gallons of gas used in this tank: ";
         float gallons_used;
         cin >> gallons_used;

         float mpg = miles_driven / gallons_used;

         cout << "You went " << mpg << " mi/gal on this tank." << "\n" << endl;

         total_miles = total_miles + miles_driven;  // running count
         total_gallons = total_gallons + gallons_used;
       }
   }

   float average_mpg = total_miles / total_gallons;
   cout << "You drove an overall average of " << average_mpg << " mi/gal.";

   cin.ignore();
   cin.get();
   return 0;

}

Note that it does not behave exactly as you original program did as it _only_ ends if -1 is entered when asked for the number of miles driven, as implied by the prompt text, and ignores other negative values but continues looping.

Oh and I apologise if the code has typos or other problems or if the indentation or other code formatting is a bit messed up - it was nicely formatted when using a 'standard' code fixed pitch font such as Courier but I am never sure if posting through All Experts can have other side-effects.

Hope this both answers your question and gives you food for thought.  

C++

All Answers


Answers by Expert:


Ask Experts

Volunteer


Ralph McArdell

Expertise

I am a software developer with more than 15 years C++ experience and over 25 years experience developing a wide variety of applications for Windows NT/2000/XP, UNIX, Linux and other platforms. I can help with basic to advanced C++, C (although I do not write just-C much if at all these days so maybe ask in the C section about purely C matters), software development and many platform specific and system development problems.

Experience

My career started in the mid 1980s working as a batch process operator for the now defunct Inner London Education Authority, working on Prime mini computers. I then moved into the role of Programmer / Analyst, also on the Primes, then into technical support and finally into the micro computing section, using a variety of 16 and 8 bit machines. Following the demise of the ILEA I worked for a small company, now gone, called Hodos. I worked on a part task train simulator using C and the Intel DVI (Digital Video Interactive) - the hardware based predecessor to Indeo. Other projects included a CGI based train simulator (different goals to the first), and various other projects in C and Visual Basic (er, version 1 that is). When Hodos went into receivership I went freelance and finally managed to start working in C++. I initially had contracts working on train simulators (surprise) and multimedia - I worked on many of the Dorling Kindersley CD-ROM titles and wrote the screensaver games for the Wallace and Gromit Cracking Animator CD. My more recent contracts have been more traditionally IT based, working predominately in C++ on MS Windows NT, 2000. XP, Linux and UN*X. These projects have had wide ranging additional skill sets including system analysis and design, databases and SQL in various guises, C#, client server and remoting, cross porting applications between platforms and various client development processes. I have an interest in the development of the C++ core language and libraries and try to keep up with at least some of the papers on the ISO C++ Standard Committee site at http://www.open-std.org/jtc1/sc22/wg21/.

Education/Credentials

©2016 About.com. All rights reserved.