You are here:

C++/random long long in C/C++

Advertisement


Question
Hello,
I am trying to generate a uniformly distributed pseudo-random number of 12 digits. The problem is rand() and random() both only return int/long type (10 digits max).
Is there any function which generate pseudo-random number in long long int type?
Thank you

Answer
If you are asking is there an ISO standard C++ library function to produce such a value then, assuming we are talking about the current 1998 or 2003 bug-fix update of the ISO C++ standard the answer is no. (Note that long long integer types are also not part of the current C++ standard).

In fact although the returned value from rand() is an int (not a long - they are _not_ equivalent on all implementations), the standard only requires values in the range 0 ... 32767, that is RAND_MAX is only required to have a value of at least 32767. Thus even on popular 32-bit compilers where an int can hold values as large as 2147483647 it may be that the range of random numbers produced by rand is restricted to 0 to 32767.

So what can you do?

Well my first thought is that you could build a single value from multiple random numbers:

   const int RandMaxBitLength(15); // assumes RAND_MAX is 32767

   long long r( rand() );
   r <<= RandMaxBitLength;
   r += rand();
   r <<= RandMaxBitLength;
   r += rand();

Where 15 is the number of bits used by 32767. If RAND_MAX were 2147483647 say then the value for RandMaxBitLength would be 31 and only 2 calls to rand would be required. If this approach seems feasible to you I shall leave it to you to tidy things up. The reason I am not sure if such an approach would be acceptable is that I have no idea what the resultant distribution of such composite random values would be compared to that produced by rand - which in fact has no guarantees on uniformity - the C 1999 standard just says the following for rand:

       "The rand function computes a sequence of pseudo-random
        integers in the range 0 to RAND_MAX."

So if you are serious about pseudo random number generation you should be looking outside the standard C/C++ library. I do not have any such 3rd party libraries to hand but I would start by using an Internet search using Google, Yahoo, Msn or similar. One place I know caters for maths and science development needs is the MathTools web site at http://www.mathtools.net/. The C and C++ random number section is at http://www.mathtools.net/C_C__/Random_numbers/index.html.

However the TR1 non-normative library update to the ISO C++ standard includes a new random number generation framework. [note: non-normative means that a C++ implementation does not have to include these features to be standard compliant; however such features will most likely be incorporated into the next full release of the ISO C++ standard].

This is a lot more sophisticated than the simple srand/rand/RAND_MAX facilities inherited from C. It defines a set of pseudo random number generator (PRNG) engine class templates, a set of random distribution class templates and a variate generator class template that uses a specific engine type with a specific distribution type. It also defines a random device type that produces non-deterministic random numbers.

As the TR1 update it is quite new and not widely supported by C++ implementations yet and I have not required industrial strength pseudo random number generation I have not made use of these facilities. I shall try below to give you an overview however. Sorry if it is not as clear or accurate as it could be...I will be working it out as I go along from the TR1 draft document at http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1836.pdf (the random number stuff is in section 5.1).

Note that although TR1 is not yet widely provided with C++ implementations (Microsoft are one of the first and have just released a version for Visual C++ 2008), there is an implementation in the Boost libraries (http://www.boost.org/) specifically see http://www.boost.org/doc/libs/1_35_0/libs/random/index.html. You should also read the usage information for the Boost TR1 implementation at http://www.boost.org/doc/libs/1_35_0/doc/html/boost_tr1/usage.html. Boost is where many of the TR1 features originated by the way, and is free for download and use. Note that many Linux distributions come with pre-build packages for the Boost libraries so see if it is either installed or available as a package if you are using Linux.

In what follows I shall leave off namespace qualifications for clarity. The class template definitions etc. are in fact in the std::tr1 namespace.

Ok let us start with PRNG engines. For example the linear_congruential class template is defined like so:

   template <class UIntType, UIntType a, UIntType c, UIntType m>
   class linear_congruential
   {
   public:
   // types
       typedef UIntType result_type;

   // parameter values
       static const UIntType multiplier = a;
       static const UIntType increment = c;
       static const UIntType modulus = m;

   // constructors and member function
       explicit linear_congruential(unsigned long x0 = 1);
       template<class Gen> linear_congruential(Gen& g);
       void seed(unsigned long x0 = 1);
       template<class Gen> void seed(Gen& g);
       result_type min() const;
       result_type max() const;
       result_type operator()();
   };

In particular notice the UintType template type parameter and the m template parameter of the specified unsigned integer type. Part of the description of this engine reads:

       "The template parameter UIntType shall denote an unsigned
        integral type large enough to store values up to (m-1)."

This is because the m value is, as can be seen from the class template definition, used as a modulus for the generated values. In fact the transform function for the generator is given as:

       "x(i+1) := (a * x(i) + c) mod m"

Note that the a and c template parameters should in general be less than the m template parameter.

The constructor is used to seed objects of these generator types and the call operator ( operator() ) is used to produce pseudo random number values.

There are some predefined types using these generator engine templates, which are useful to show the sort of values involved. Those using the linear_congruential class template are as follows:

   typedef linear_congruential<implementation-defined , 16807, 0, 2147483647> minstd_rand0;
   typedef linear_congruential<implementation-defined , 48271, 0, 2147483647> minstd_rand;

Where implementation-defined would presumably be some integer type capable of holding 2147483647 - i.e. a 32 bit type. However given this you could quite easily come up with a set of parameters based on an unsigned long long or other 64-bit type (on some implementations long or int could be 64-bits in size - those targeting 64-bit operating systems for example):

   typedef linear_congruential<unsigned long long, 16807, 0, 999999999999ULL> rand12digits;

Whether the values of a and c need to be adjusted I cannot say - sorry I am a C++ expert not a pseudo random number expert.

I am unclear if all the provided PRNG engine class templates constitute uniform PRNGs. It is sort of implied but not clearly stated.

However once you have a generator of random numbers there are distribution class templates that can be used to provide a shaping of the distribution of values. One of these is the uniform_int distribution class template, which is parameterised on the type of int required.

   template<class IntType = int>
   class uniform_int
   {
   public:
   // types
       typedef IntType input_type;
       typedef IntType result_type;

   // constructors and member function
       explicit uniform_int(IntType min = 0, IntType max = 9);
       result_type min() const;
       result_type max() const;
       void reset();
       template<class UniformRandomNumberGenerator>
       result_type operator()(UniformRandomNumberGenerator& urng);
       template<class UniformRandomNumberGenerator>
       result_type operator()(UniformRandomNumberGenerator& urng, result_type n);
   };

Thus we could define a uniform distribution type for use with unsigned long long values like so:

   typedef uniform_int<unsigned long long> uniform_ulonglong;
   
You will notice we construct such a distribution from min, max values. The call operator uses an existing uniform PRNG to shape its results.

I presume the use of this distribution type is to modify the range of values from those output from a raw PRNG engine. So if you did not want 0 .... 999999999 but 1234 ... 123456789012 you could use a rand12digits with a suitably constructed uniform_ulonglong instance.

We can combine an engine with a distribution using the variate_generator class template. This takes as template parameters an underlying PRNG type and a distribution type:

   template<class Engine, class Distribution>
   class variate_generator
   {
   public:
       typedef Engine engine_type;
       typedef see below engine_value_type;
       typedef Distribution distribution_type;
       typedef typename Distribution::result_type result_type;

       variate_generator(engine_type eng, distribution_type d);
       result_type operator()();
       template<class T> result_type operator()(T value);
       engine_value_type& engine();
       const engine_value_type& engine() const;
       distribution_type& distribution();
       const distribution_type& distribution() const;
       result_type min() const;
       result_type max() const;
   };

This looks quite like the linear_congruential class template in what is provided - and that is the point. Given a generator engine type and a distribution type it combines then to produce a new generator engine. So I presume we can then use the rand12digits type as the engine and a uniform_int distribution with long long or unsigned long long as the integer type as the distribution type:

   typedef variate_generator<rand12digits, uniform_ulonglong>    uniform_rand12digits;

As far as I can tell we can create a uniform_rand12digits object from a rand12digits object and a uniform_ulonglong object:

   rand12digits engine; // initialised using default value of 1 as seed
   
   uniform_ulonglong distribution(1234, 123456789012ULL); // initialised with min, max values
   
   uniform_rand12digits    prng( engine, distribution);

   unsigned long long value( prng() );  // get pseudo random number from our generator.

As you will note the new random number facilities are a lot more sophisticated than those inherited from C. One point that has to be made is that the state for these generators etc. is kept in the objects and is not static and global as it is for the C rand/srand functions. Hence you can have many different pseudo random number sequences active as you require, not just the single sequence provided by rand/srand.

As I happen to have Boost installed I tried the above suggested code (in fact I added a loop and some output) with Visual C++ 2005:

The full result was as follows:

   #include <boost/tr1/random.hpp>     // For Boost tr1 implementation of <random>
   #include <iostream>          // For std::cout

   using namespace std::tr1;          // As I left off namespace qualifications  

   typedef linear_congruential<unsigned long long, 16807, 0, 999999999999ULL> rand12digits;
   typedef uniform_int<unsigned long long> uniform_ulonglong;
   typedef variate_generator<rand12digits, uniform_ulonglong>    uniform_rand12digits;
   
   int main()
   {
       rand12digits engine; // initialised using default value of 1 as seed

       uniform_ulonglong distribution(1234, 123456789012ULL); // initialised with min, max values

       uniform_rand12digits    prng( engine, distribution);

       for ( int i=0; i <100; ++i)
       {
         unsigned long long value( prng() );  // get pseudo random number from our generator.
         std::cout << std::setw(12) << value << ( !(i%6) ? '\n' : ' ');
       }
       std::cout << std::endl;
   }
   
The output was as follows:

         18040
      282476482   6820784506  19384117468  48022031764  56687428522   4613307439
   103620441178  54828202708  65365228105  99462084154 103553903998 121683597733
    74438582506  89235457795  39577713592  71264115304 118444840537  85051441891
    89035168801 105379946275   9546429121  88473630379  50083334521   9684237286
    22057007962  94670547481  78369889690 113056786549  95811101110  62351343496
    12807691501  11779150636 107966503198  37167167119 112962100471  60017135551
    90613741207  80772621790 113137934950  77113825144   2537571436  93111041413
   114743785111   4712075296  10604194102  39444966643  25568337040  47731760449
   104141552803  60143664415  93727570678 106223169109 119667194371  11710781524
    20339415025  41940276007  87531996079  38968679884  20380364224  38776030666
    91363938655  59711493676  77147535856  62940659137  41050067107   2334225985
    58278912322  61284101131   1866987949   8075373739  43655169778  94976189356
    79490397274   7431961423  44442181174  13674154876  80523138394  43606090918
    85040814814  46149566443  79911124795   4485912838  24345983206   9961330804
    61726216567    126546904   3396305953  19925634058  25913376889  93730078156
    74489272111  76899329812  76408652146  76739109529  75141398227  98793148177
    45892717834  10206543181  47444565559

Obviously you will probably wish to improve on this example - e.g. randomise the seeding of engine, adjust the engine a and c values.

I hope that although this has not been an exhaustive tour of the subject that you will be able to get what you require. I was nicely surprised that the example code I produced while writing this answer actually worked as expected.

Have fun...

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.