Basic Data Types and Calculations - Numerical Functions for Integers (
Page 8 of 14 )
I explain functions in detail in Chapter 8, but that won’t stop us from making use of a few from the standard library before that. Let’s do a quick reprise of what’s going on when you use functions and cover some of the terminology they introduce. A function is a named, self-contained block of code that carries out a specific task. Often, this will involve it performing some operation on data that you supply and then returning the result of that operation to your program. In those circumstances in which a function returns a value that is numeric, the function can participate in an arithmetic expression just like an ordinary variable. In general, a call to a function looks like this:
FunctionName(argument1, argument2, ... )
Depending on the function in question, you can supply zero, one, or more values for it to work with by placing them in parentheses after its name when you call it from your program. The values you pass to the function in this way are called arguments. Like all values in C++, the arguments you pass to a function, and the value it returns to your program, have types that you must take care to conform with in order to use the function.
You can access some numerical functions that you can apply to integers by adding an
#include
directive for the
header at the beginning of your source file. This header has the same contents as the original C library header,
stdlib.h
. You’ll learn how each of these functions works by considering a few sample statements.
The
abs()
function returns the absolute value of the argument, which can be of type
int
or type
long
. The absolute value of a number is just its magnitude, so taking the absolute value of a negative number returns the number with a positive sign, whereas a positive number will be returned unchanged. The value returned by the
abs()
function will be of the same type as the argument, for example:
int value = -20;
int result = std::abs(value); // Result is 20
The <sctdlib>
header also defines the
labs()
function that will also produce the absolute value of an argument of type
long
. This function is there because older C programs may use it, but I suggest you just use the
abs()
function.
The
div()
function takes two arguments, both of type
int
. It returns the result of dividing the first argument by the second as well as the remainder from the operation in the form of a structure of type
div_t
. I go into structures in detail later on, so for the moment you’ll just see how to access the quotient and the remainder from what is returned by the
div()
function through an example:
int value = 93;
int divisor = 17;
div_t results = std::div(value, divisor); // Call the function
std::cout << "nQuotient is " << results.quot; // Quotient is 5
std::cout << "n Remainder is " << results.rem; // Remainder is 8
The first two statements define the variables
value
and
divisor
and give them the initial values 93 and 17, respectively. The next statement calls the
div()
function to divide
value
by
divisor
. You store the resulting structure of type
div_t
that is returned by the function in the variable
results
, which is also of type
div_t
. In the first output statement, you access the quotient from
results
by appending the name
quot
to
results
, separated by a period. The period is called the member access operator, and here you’re using it to access the
quot
member of the
results
structure. Similarly, in the last statement you use the member access operator to output the value of the remain
der, which is available from the
rem
member of the
results
structure. Any structure of type
div_t
will have members with the names
quot
and
rem
, and you always access them by using the member access operator.
Note that you could have used literals directly as arguments to the
div()
function. In this case, the statement calling the function would be
div_t results = std::div(93, 17);
The
ldiv()
function performs the same operation as the
div()
function, but on arguments of type
long
. The result is returned as a structure of type
ldiv_t
, which has members
quot
and
rem
that are of type
long
.
CAUTION The
header is inherited from C, so many implementations will have definitions of the original C functions defined outside of the
std
name-space so the function names can be used without the
std
qualifier. This is to allow C programs to be compiled and executed in the same environment, but you should use the functions with the
std
qualifier because your code is C++.
Generating Random Numbers
Being able to generate random numbers in a program is very useful. You need to be able to build randomness into game programs, for instance; otherwise, they become very boring very quickly. The
header defines a function
rand()
that will generate random integers. To be more precise, it generates pseudo-random integers. Random numbers by definition aren’t predictable, so any sequence of numbers produced by a numerical algorithm can’t be truly random. It just has the appearance of being so. However, now that you understand that, you’ll just refer to the numbers produced by the
rand()
function as random numbers. Note that
rand()
isn’t an outstanding random number generator. For many applications, you’ll probably want to use something that’s rather more sophisticated.
The
rand()
function return a random integer as type
int
. The function doesn’t require any arguments, so you can just use it like this:
int random_value = std::rand(); // A random integer
You store the integer that’s returned by the
rand()
function here in the variable
random_value
, but you could equally well use it in an arithmetic expression, for example:
int even = 2*std::rand();
The value returned by the
rand()
function will be a value that is from 0 to
RAND_MAX
.
RAND_MAX
is a symbol that is defined in
. When you use
RAND_MAX
in your code, the compiler will replace it with an integer value. On my system it represents the value
0x7fff
, but on other systems it may have a different value. It can be up to
0x3fffffff
, which is the maximum integer you can store as type
int
. If this was the case, then you couldn’t multiply the value produced by
rand()
by 2, as you did previously, without running the risk of getting an incorrect result. You’ll see how you can get around this in the next chapter.
Because
RAND_MAX
is defined by a preprocessing macro (you’ll learn what a preprocessing macro is in Chapter 10), it isn’t within the
std
namespace, so you don’t need to qualify the name when you use it. Any symbol that’s defined by a macro won’t be in the
std
namespace because it isn’t a name that refers to something. By the time the compiler gets to compile the code, such a symbol will no longer be present because it will have already been replaced by something else during the preprocessing phase.
Making the Sequence Start at Random
Using
rand()
as you have so far, the sequence of numbers will always be the same. This is because the function uses a default seed value in the algorithm that generates the random numbers. This is fine for testing, but once you have a working game program, you’ll really want different sequences each time the program runs. You can change the seed value that will be used to generate the numbers by passing a new seed value as an integer argument to the
srand()
function that is defined in
, for example:
std::srand(13); // Set seed for rand to 13
The argument to the
srand()
function must be a value of type
unsigned int
. Although the preceding statement will result in
rand()
generating a different sequence from the default, you really need a random seed to get a different sequence from
rand()
each time you execute a program. Fortunately, the clock on your computer provides a ready-made source of random seed values.
The
standard library header defines several functions relating to the data and the time. You’ll just look at the
time()
function here because that’s precisely what you need to obtain a more or less random seed value. The
time()
function returns a value that’s the number of seconds that have elapsed since midnight on January 1, 1970, so if you use that as a seed, you can be certain that a program will use a different seed value each time it executes. The value is returned as type
time_t
, which is a type defined in the standard library to be equivalent to an integer type, usually type
long
. The return type is specified as type
time_t
to allow flexibility in the type of the return value in different C++ implementations. You can use the
time()
function to create the seed for a random number sequence like this:
std::srand((unsigned int)std::time(0));
There are a few things that you’ll have to take on trust for the moment. The argument to the
time()
function here is
0
. There’s another possibility for the argument, but you don’t need it here so you’ll ignore it. The subexpression
(unsigned int)
serves to convert the value returned by the
time()
function to type
unsigned int
, which is the type required for the argument to the
srand()
method. Without this, the statement wouldn’t compile. Type conversion is something else that you’ll look into later.
Let’s put a working example together that makes use of random number generation.
Try It Out: Generating Random Integers
Here’s the code:
// Program 2.5 Using Random Integer
s #include
#include
#include <iostream>
#include <cstdlib>
#include <ctime>
using std::cout;
using std::endl;
using std::rand;
using std::srand;
using std::time;
int main() {
const int limit1 = 500; // Upper limit for on set of random values
const int limit2 = 31; // Upper limit for another set of values
cout << "First we will use the default sequence from rand().n";
cout << "Three random integer from 0 to " << RAND_MAX << ": "
<< rand() << " " << rand() << " " << rand()<< endl;
cout << endl << "Now we will use a new seed for rand().n";
srand((unsigned int)time(0)); // Set a new seed
cout << "Three random integer from 0 to " << RAND_MAX << ": "
<< rand() << " " << rand() << " " << rand()<< endl;
return 0;
}
On my system I get the following output:
First we will use the default sequence from rand().
Three random integer from 0 to 32767: 6334 18467 41
Now we will use a new seed for rand().
Three random integer from 0 to 32767: 4610 32532 28452
HOW IT WORKS
This is a straightforward use of the
rand()
function, first with the default seed to start the sequence:
cout << "A random integer from 0 to " << RAND_MAX << ": "
<< rand() << endl;
Each call to
rand()
returns a value that will be from 0 to
RAND_MAX
, and you call the function three times to get a sequence of three random integers.
Next, you set the seed value as the current value of the system clock with this statement:
srand((unsigned int)time(0)); // Set a new seed
This statement will generally result in a different seed being set each time you execute the program. You then repeat the statement that you executed previous
ly with the default seed set. Thus, each time you run this program, the first set will always produce the same output, whereas with the second set, the output should be different.