Skip to the content of the web site.

Other features in the standard library

Here we will just include a few additional useful commands from the standard library.

std::swap

If you want to swap two variables, use std::swap(...) in the utility library:

#include <utility>

unsigned long gcd( unsigned long m, unsigned long n );

unsigned long gcd( unsigned long m, unsigned long n ) {
    if ( m < n ) {
       std::swap( m, n );
    }

    while ( n != 0 ) {
       unsigned long r{m % n};
       m = n;
       n = r;
    }

    return m;
}

std::max and std::min

If you want to calculate the maximum or minimum of any two values (be they int or double or anything else that can be compared, just use the std::max and std::min functions in the algorithm library.

#include <algorithm>

double distance( double x, double y, double z );

double closest( double x, double y, double z ) {
    double dy{std::abs( x - y )};
    double dz[std::abs( x - z )};

    return std::min( dy, dz );
}

std::time

To get the current time in seconds since January 1, 1970, call time( nullptr ).

#include <iostream>
#include <ctime>

int main();

int main() {
    std::cout << std::time( nullptr ) << std::endl;

    return 0;
}

std::rand and std::srand

Unless you have a radioactive source or some other means of generating truly random numbers, the next best bet is to use a mathematical algorithm to generate numbers that appear to be random. What does it mean to appear to be random? If I was giving you a random number between $0$ and $99$ many times, the numbers I give you are random if hearing one number gives you no information about what the next number may be.

Now, if I asked you to give me 1000 random numbers between $0$ and $99$, I can almost guarantee you one thing: no two successive numbers will be the same. You would never say that $42$ was a randomly chosen number and then immediately say again the value $42$, so in a sense, if I ask you for random numbers, if you give me the number $42$, it's almost certain that the next number will not be $42$ and there is probably a very low chance (much less than one in five) that the next number will either start with $4$ or end in $2$. This is because that is what humans understand to be random.

Now, mathematical algorithms will never give you random numbers, but they may give reasonably good approximations, and we call such numbers pseudorandom. One benefit of such algorithms, however, is that they are repeatable:

#include <iostream>
#include <cstdlib>

int main();

int main() {
    std::cout << "Random numbers are generated between 0 and " << RAND_MAX << std::endl;

    for ( int k{0}; k < 10; ++k ) {
        std::cout << (std::rand() % 10) << " ";
    }

    std::cout << std::endl;
 
    return 0;
}

You will notice that if you run this 100 times, you will get the exact same sequence of pseudorandom numbers. This is good, because if you use such numbers to test your code and you find a bug, then you will be able to recreate the circumstances that generated the bug.

Suppose, however, you want to create a different sequence of random numbers. The easiest way to do this is to seed the algorithm with a different starting value. You can do this with the std::srand function where the s stands for seed:

#include <iostream>
#include <cstdlib>

int main();

int main() {
    std::cout << "Random numbers are generated between 0 and " << RAND_MAX << std::endl;

    for ( int s{5}; s <= 15; ++s ) {
        std::srand( s );

        std::cout << "Using seed " << s << ":\t";

        for ( int k{0}; k < 20; ++k ) {
            std::cout << (std::rand() % 100) << " ";
        }

        std::cout << std::endl;
    }

    return 0;
}

The output of this program is

Random numbers are generated between 0 and 2147483647
Using seed 5:	75 65 10 72 76 32 20 49 73 81 26 48 60 98 10 20 20 26 28 86 
Using seed 6:	41 85 12 65 8 85 86 43 2 78 35 23 5 93 42 16 0 92 23 44 
Using seed 7:	77 99 99 71 25 43 86 97 0 53 15 21 31 26 65 20 78 46 70 36 
Using seed 8:	96 44 42 49 11 93 82 21 77 13 47 81 96 47 55 94 0 98 65 97 
Using seed 9:	15 74 65 7 30 53 20 78 42 52 56 63 58 89 37 15 9 40 46 99 
Using seed 10:	95 8 78 25 18 77 75 71 47 7 23 73 28 73 44 81 20 38 71 68 
Using seed 11:	23 94 97 45 3 95 81 81 89 23 0 16 18 34 61 69 81 84 63 18 
Using seed 12:	60 14 94 8 23 55 29 73 97 64 78 69 57 74 68 4 7 67 87 60 
Using seed 13:	90 81 79 91 64 24 32 75 29 51 26 79 62 94 51 3 37 48 8 14 
Using seed 14:	83 52 51 22 73 88 7 0 19 6 78 64 40 50 96 85 96 6 5 41 
Using seed 15:	93 50 97 55 96 65 74 92 43 28 3 92 44 64 90 25 89 7 24 53 

You will notice that out of these 220 random numbers, three times consecutive random numbers were identical (20 20, 99 99 and 81 81).

This function call is useful if you don't need a good random number, but if you're looking for better random numbers, look at the random library.

std::pair and std::make_pair

Sometimes, it is desirable to return two items of information from a function instead of just one. For example, remember that addition and multiplication of integers may cause an overflow. You may want to write a function that checks whether the result is actually valid:

unsigned int add( unsigned int m, unsigned int n );
unsigned int mul( unsigned int m, unsigned int n );

unsigned int add( unsigned int m, unsigned int n ) {
    unsigned int result{ m + n };

    if ( result < m ) {
         // Result is not valid...
    } else {
        return result;  
    }
}

unsigned int mul( unsigned int m, unsigned int n ) {
    unsigned int result{ m*n };

    if ( (n != 0) && (result/n != m) ) {
         // Result is not valid...
    } else {
        return result;  
    }
}

The problem is there is no value we can return that can be used to signal that an error occurred: every possible integer may have been the result of a valid computation. Thus, we need to send back a second flag indicating whether or not the result is actually valid. For this, we can use a pair:

#include <utility>

std::pair<unsigned int, bool>
add( unsigned int m, unsigned int n );

std::pair<unsigned int, bool>
mul( unsigned int m, unsigned int n );

std::pair<unsigned int, bool>
add( unsigned int m, unsigned int n ) {
    unsigned int result{ m + n };

    return std::make_pair( result, result >= m );
}

std::pair<unsigned int, bool>
mul( unsigned int m, unsigned int n ) {
    unsigned int result{ m*n };

    return std::make_pair( result, (n == 0) || (result/n == m) );
}

In each case, the second entry in the pair is true if the result is valid, and false if the result is invalid. You can now use this.

You can see how this works at repl.it, but here is a simple exmaple. If the result is assigned to a variable named res, you can access the first item with res.first (which will be of type unsigned int and the second with res.second (which will be of type bool:

int main() {
    unsigned int m{};
    unsigned int n{};

    std::cout << "Enter a positive number: ";
    std::cin >> m;

    std::cout << "Enter another positive number: ";
    std::cin >> n;

    // Here 'auto' says to determine the type based on
    // the return type of the function being called
    auto res = add( m, n );

    // If the second item is 'true', the result is valid:
    if ( res.second ) {
        std::cout << m << " + " << n << " = " << res.first << std::endl;
    } else {
        std::cout << m << " + " << n << " != " << res.first << std::endl;
    }

    res = mul( m, n );

    // If the second item is 'true', the result is valid:
    if ( res.second ) {
        std::cout << m << "*" << n << " = " << res.first << std::endl;
    } else {
        std::cout << m << "*" << n << " != " << res.first << std::endl;
    }

    return 0
}