Home arrow C++ arrow Page 2 - More on Handling Basic Data Types
C++

More on Handling Basic Data Types


Have you ever wanted to learn how basic types of C++ variables interact in complex situations? Ivor Horton explains this, and also describes some interesting features of C++. This article is from chapter 3 of Ivor Horton's Beginning ANSC C++ The Complete Language (Apress, 2004; ISBN 1590592271).

Author Info:
By: Apress Publishing
Rating: 4 stars4 stars4 stars4 stars4 stars / 10
March 02, 2005
TABLE OF CONTENTS:
  1. · More on Handling Basic Data Types
  2. · Try It Out: Explicit Casting
  3. · Finding Out About Types
  4. · Try It Out: Finding the Sizes of Data Types
  5. · Using the Bitwise AND
  6. · Using the Bitwise Exclusive OR
  7. · Try It Out: Using the Bitwise Operators
  8. · More on Output Manipulators
  9. · Enumerated Data Types
  10. · Try It Out: Enumerated Data Types
  11. · The Lifetime of a Variable
  12. · Try It Out: The Scope Resolution Operator
  13. · Declaring External Variables

print this article
SEARCH DEVARTICLES

More on Handling Basic Data Types - Try It Out: Explicit Casting
(Page 2 of 13 )

Suppose you need to be able to convert a length in yards (as a decimal value) to yards, feet, and inches (as integer values). You can put together a program to do this:

// Program 3.1 Using Explicit Casts
#include <iostream>
using std::cin;
using std::cout;
using std::endl;
int main() {
  const long feet_per_yard = 3;
  const long inches_per_foot = 12;
  double yards = 0.0;           // Length as decimal yards
  long yds = 0;                 // Whole yards
  long ft = 0;                  // Whole feet
  long ins = 0;                 // Whole inches
  cout << "Enter a length in yards as a decimal: ";
  cin >> yards;
  // Get the length as yards, feet, and inches
  yds = static_cast<long>(yards);
  ft = static_cast<long>((yards - yds)
  *feet_per_yard);
  ins = static_cast<long>
           (yards * feet_per_yard *
        inches_per_foot)% inches_per_foot;
 cout << endl
      << yards << " yards converts to "
      << yds   << " yards "
      << ft    << " feet "
      << ins   << " inches.";
 cout << endl;
 return 0;
}

Typical output from this program will be:

==========================================================
 
Enter a length in yards as a decimal: 2.75

2.75 yards converts to 2 yards 2 feet 3inches.

==========================================================

HOW IT WORKS

The first two statements in main() declare a couple of conversion constants that youíll use:

  const long feet_per_yard = 3;
  const long inches_per_foot = 12;

You declare these variables as const to prevent them from being modified accidentally in the program, and you use the type long to be consistent with the other values. Although the type short would have been adequate to store these values, using it may actually increase (rather than decrease) the size of your program in the long run. This is because of additional, implicit conversions that may be necessary when using them in expressions with other integer types.

The next four declarations define the variables youíll use in the calculation:

double yards = 0.0;                 // Length as decimal yards
long yds = 0;                         // Whole yards
long ft = 0;                           // Whole feet
long ins = 0;                         // Whole inches

You prompt for the required input and then read a value from the keyboard with these statements:

  cout << "Enter a length in yards as a decimal: ";
  cin >> yards;

The next statement computes the whole number of yards from the input value with an explicit cast:

  yds = static_cast (yards);

The cast to type long discards the fractional part of the value in yards and stores the integral result in yds. If you omit the explicit cast here, some compilers will compile the program without warning you that theyíve inserted the required conversion, even though thereís clearly a potential loss of data in this conversion operation. You should always write an explicit cast in such cases to indicate that you intend this to happen. If you leave it out, itís not clear that you realized the need for the conversion and the potential loss of data.

You obtain the number of whole feet in the length with the following statement:

 ft = static_cast ((yards Ė yds) * feet_per_yard);

You want the number of whole feet that arenít contained in the whole yards, so you subtract the value in yds from yards. The compiler will arrange for the value in yds to be converted automatically to type double for the subtraction, and the result will be of type double as well. The value of feet_per_yard will then be converted automatically to double to allow the multiplication to take place, and finally your explicit cast will be applied to the result to convert it from type double to type long.

The final part of the calculation is to obtain the residual number of whole inches:

  ins = static_cast<long>
  (yards * feet_per_yard * inches_per_foot) %
    inches_per_foot;

This is done by calculating the total number of inches in the original length, converting this to type long with an explicit cast, and then getting the remainder after dividing by the number of inches in a foot.

Lastly, you output the results with the following statement:

 cout << std::endl
      << yards << " yards converts to "
      << yds   << " yards"
      << ft    << "  feet "
      << ins   << "  inches.";



Old-Style Casts

Prior to the introduction of static_cast<>() (and the other casts, const_cast<>(), dynamic_cast<>(), and reinterpret_cast<>(), which I discuss later in the book) into C++, an explicit cast of the result of an expression to another type was written like this:

(the_type_to_convert_to)expression

The result of expression is cast to the type between the parentheses. For example, the statement to calculate ins in the previous example could be written like this:

ins = (long)(yards * feet_per_yard * inches_per_foot) %
  inches_per_foot;

Essentially, there are four different kinds of casts, and the old-style casting syntax covers them all. Because of this, code using the old-style casts is more prone to erroró it isnít always clear what you intended, and you may not get the result you expected. Although youíll still see old-style casting used extensively (itís still part of the language), I strongly recommend that you stick to using only the new casts in your code.

More on Pseudo-Random Number Generation

Now that you know about casting, you can make sure that you donít run into difficulties with using a value returned by the rand()in an arithmetic expression. I noted in the last chapter that rand()returns values from 0 to RAND_MAX, and RAND_MAX could be defined as any positive int value up to the maximum in the range. Assuming type long has a greater range than type int, you can avoid any possible problems when you want to perform arithmetic with a random integer by casting the value that is returned by the function to type long, for example:

long even = 2*static_cast<long>(std::rand());

With the value from rand() as type long, the multiply operation will be carried out after converting the value 2 to the same type. Thus the result of the multiplication will always be within range. You can produce the same effect by defining the literal as type long:

long even = 2L* std::rand();

Because 2L is of type long, the compiler will arrange to cast the value that is returned by rand() to type long before executing the multiply operation.

You could use rand() to obtain random integers in a more limited range than 0 to RAND_MAX. For instance, suppose you wanted random integers from to 0 to 10 inclusive. You could generate that from the value returned by the rand() function:

const int limit = 11;
int random_value = static_cast<int>(
                          (limit*static_cast<long>
                    (std::rand()))/(RAND_MAX+1L));

What youíre effectively doing here is dividing the range 0 to RAND_MAX into limit segments, in which all the values returned by rand() within a given segment will result in one of the values in the range 0 to limit-1 inclusive. You do this by multiplying limit by the ratio rand()/(RAND_MAX+1L). You divide by RAND_MAX+1L rather than RAND_MAX to deal with the case in which rand() returns a value that is exactly RAND_MAX. If you were to divide by RAND_MAX, the result would be limit in this singular case, instead of limit-1. The constant 1L that you add to RAND_MAX is of type long, so RAND_MAX will be converted to type long too before the addition is carried out. As Iíve already said, RAND_MAX is defined to be the largest possible integer of type int with some implementations of rand(). In this case, you canít add 1 and get a correct result without converting to type long first.

If you want your random values to be between 1 and some upper limit, rather than having a lower limit of 0, this is also very easy to arrange:

const int limit = 100;
int random_value = static_cast<int>(
                     1L+(limit*static_cast<long>(std::rand
                    ()))/(RAND_MAX+1L));

Here you use the same expression as you did previously to produce values from 0 to limit-1 inclusive, and you add 1 to produce values from 1 to limit.

As I said at the beginning, all this assumes that type long has a greater range than type int. If this isnít the case and you need to generate random values outside the range of type int, your only recourse is to cast the value returned by rand() to a floating-point type and store the result of your calculations as floating-point. For example, to produce values in a range from 0 to limit, you could use the following statements:

const double limit = 11.0;
double random_value = limit*std::rand()/(RAND_MAX+1.0);

Because youíve declared limit to be of type double, the compiler will promote the integer thatís returned by rand() to that type so you donít need to insert an explicit cast.

This article is excerpted from Beginning ANSI C++ The Complete Language by Ivor Horton (Apress, 2004; ISBN  1590592271). Check it out at your favorite bookstore today. Buy this book now.


blog comments powered by Disqus
C++ ARTICLES

- Intel Threading Building Blocks
- Threading Building Blocks with C++
- Video Memory Programming in Text Mode
- More Tricks to Gain Speed in Programming Con...
- Easy and Efficient Programming for Contests
- Preparing For Programming Contests
- Programming Contests: Why Bother?
- Polymorphism in C++
- Overview of Virtual Functions
- Inheritance in C++
- Extending the Basic Streams in C++
- Using Stringstreams in C++
- Custom Stream Manipulation in C++
- General Stream Manipulation in C++
- Serialize Your Class into Streams in C++

Watch our Tech Videos 
Dev Articles Forums 
 RSS  Articles
 RSS  Forums
 RSS  All Feeds
Write For Us 
Weekly Newsletter
 
Developer Updates  
Free Website Content 
Contact Us 
Site Map 
Privacy Policy 
Support 

Developer Shed Affiliates

 




© 2003-2017 by Developer Shed. All rights reserved. DS Cluster - Follow our Sitemap
Popular Web Development Topics
All Web Development Tutorials