Thursday, December 11, 2014

C++ Examples - Data Types

Number Precision

The precision of the numbers you do calculations with must be set when the variable is declared. There are two main types, a float and a double, which are single and double precision storage respectively. In this course we shall only use double precision, which gives around 15-16 digits of accuracy. Now if we are to solve this task, you must first consider what libraries/methods etc you will need. Here we are told that we need the iomanip library to specify outputs, but we also need the cmath lib for calculating inverse tan. You initial program should look like:

// include the input output stream library
// so that you can write to the screen
#include <iostream>
// and the input/output manipulator library
#include <iomanip>
// we will also need the cmath library to
// get access to mathematical functions
#include <cmath>
// use the std namespace
using namespace std;
  
int main()
{
  // do nothing yet
  return 0;
}

Check that the code runs and compiles and does nothing.

Now we want to declare three different versions of pi using float, double and long double.

  // store the variable pi using different data types
  float pi_f;
  double pi_d;
  long double pi_ld;

Next we do the calculation, using the formula in the question. We have to be very careful here to specify what type a number is. Simply writing 1 implies an integer, whilst writing 1. implies a double. To be more specific write 1.f 1.d 1.l for a float, double and long double respectively. You need to specify the correct type for each number in the calculation to avoid conversions in type.

  // call the atan function to calculate pi
  pi_f = 4.f*atan(1.f); // calls atan<float>(float x)
  pi_d = 4.d*atan(1.d); // calls atan<double>(double x)
  pi_ld = 4.l*atan(1.l); // calls atan<long double>(long double x)

Now try to output the numbers,

  cout << pi_f << endl;
  cout << pi_d << endl;
  cout << pi_ld << endl;

and you will see an output like this

3.14159  
3.14159  
3.14159

so obviously we need to see more digits to tell the difference (6 digits is default). Adjust this with the command

   cout.precision(80); 

and you get (depending on your system/compiler)

3.1415927410125732421875  
3.141592653589793115997963468544185161590576171875  
3.14159265358979323851280895940618620443274267017841339111328125

Even though you see around 24 digits for the float, only around 8 of those are actually accurate, the last 16 digits are created in the conversion from binary to decimal. I have run this on gcc 4.8 which means that the long double has a slightly higher precision (around 20 digits) than the double (around 16 digits). Again, any of the digits past where the accurate result for pi ends are created in the conversion from binary to decimal.

The final version of the code is here:

// include the input output stream library
// so that you can write to the screen
#include <iostream>
// and the input/output manipulator library
#include <iomanip>
// we will also need the cmath library to
// get access to mathematical functions
#include <cmath>
// use the std namespace
using namespace std;
  
int main()
{
  // store the variable pi using different data types
  float pi_f;
  double pi_d;
  long double pi_ld;
  
  // call the atan function, the letter f, d or l after a number
  // makes that number a float, double or a long double
  pi_f = 4.f*atan(1.f);
  pi_d = 4.d*atan(1.d);
  pi_ld = 4.l*atan(1.l); 
  // must be consistent using long doubles
  // to maintain accuracy
  
  cout.precision(80); 
  
  cout << pi_f << endl;
  cout << pi_d << endl;
  cout << pi_ld << endl;
  
  return 0;
}

No comments:

Post a Comment