64-bit Mersenne Twister for Visual Basic .NET

Home (Get 64-bit Mersenne Twister for Visual Basic 2012, 2010, 2008 and 2005 there.)

Overview

64-bit Mersenne Twister (MT) is a long period, fast, high quality pseudorandom number generator (PRNG). Its period is 219937-1 (approximately 106002). It has equidistribution in 311 dimensions. The Visual Basic .NET class MTRandom64 implementing 64-bit Mersenne Twister (in mt19937-64.vb) produces over 135 million 64-bit pseudorandom integers per second on a 3.60 GHz Intel i7-3820 processor. MT has a sound theoretical basis and has been tested thoroughly. The original MT authors' site has details about the algorithm.

MTRandom64 has functions to produce 32-, 64- and 128-bit integers, as well as 53-bit precision reals. In all, MTRandom64 provides eight equidistribution generator functions and seven initializing methods. Saving a generator's state to a file and loading it later is simple.

MTRandom64 has been successfully tested against the original MT authors' mt19937-64.c code by generating 100 million integers and 100 million reals with both, and comparing the entire outputs.

MTRandom64 passes George Marsalia's Diehard tests.

MTRandom64 implements MT as a VB class. Code is included in a separate file to demonstrate use of the VB class in your program. Test code for the class is also included to duplicate the original authors' mt19937-64.out.txt file.

MTRandom64 will not compile with VB 6 or earlier.

This MTRandom64 (mt19937-64.vb) release is version 1.7, dated 2014-06-18.

VB files in this package

FILE                        CONTENTS
------------------------    ---------------------------------------------------
mt19937-64.vb               The only file necessary to use the PRNGs.  It
                            consists of one Visual Basic .NET PRNG class:
                            MTRandom64; and some exception classes used by
                            MTRandom64.

Main.vb                     The original MT authors' test duplicated in VB .NET;
                            it also calls the following modules:

MakeEntropyTestData64.vb    Makes a file to test with John Walker's 'ent.exe'
                            entropy and chi-squared program available at
                            http://www.fourmilab.ch/random/

MakeDiehardData64.vb        Makes a file to test with George Marsaglia's
                            Diehard tests

Test_init_by_crypto64.vb    Produces a binary file of the initialization values
                            from init_by_crypto64().

Demo64.vb                   Demonstrates how to initialize and use the PRNGs

PerformanceTest64.vb        A performance test

MersenneTwister64.vbproj    VB Project file for Visual Basic 2012.  It likely
                            won't work with Visual Basic 2010 or earlier.  For
                            VB 2005-2010 make an empty console project
                            and add to it the *.vb files named above.

64-bit Mersenne Twister Header Comments

 mt19937-64.vb (for Visual Basic .NET), by Ron Charlton, based on
 C code that is Copyright (c) 2004 by Takuji Nishimura and Makoto
 Matsumoto.  mt19937-64.vb is Copyright (c) 2014 by Ron Charlton.
 The C source code comments below have detailed redistribution
 requirements and disclaimers that apply to mt19937-64.vb.

 This file implements the 64-bit Mersenne Twister (MT), mt19937-64,
 pseudorandom number generator (PRNG) as a Visual Basic .NET (VB)
 class.  Its period is 2^19937-1; approximately 10^6002.
 It is equidistributed in 311 dimensions.

 
 TO USE 64-bit Mersenne Twister in your VB project:

   1) Add only this file, mt19937-64.vb, to your VB project

   2) Check "Remove Integer Overflow Checks" for your project in
      SolutionExplorer-MyProject-Compile-AdvancedCompilerOptions...

   3) mt19937-64.vb has a genrand64_int128SignedInt() function
      that REQUIRES VB 2010 or later for data type BigInteger.
      The function is disabled by default.  If you want to use
      genrand64_int128SignedInt() do the following:
      a) Add a project reference to BigInteger with
         Visual Basic menu item
           [VB 2010] Project/AddReference/.NET/System.Numerics
           [VB 2012] Project/AddReference/Assemblies/Framework/System.Numerics
      b) Set Need128bitInts to True below.

 Set to True if you need genrand64_int128SignedInt() with Visual
 Basic 2010 or later.  Set it to False otherwise (must be False
 for Visual Basic 2008 or earlier).
#Const Need128bitInts = False
 (Also set the #Const in Demo64.vb if you include that file in a
 project.)

 Important information follows in these header comments.  Please
 skim them if you have trouble with MTRandom64.

 To see a list of PRNGs herein, search for "FUNCTIONS:" (no quotes).
 To see instructions for using the PRNGs, search for "USE:" (no quotes).
 To see performance results, search for "PERFORMANCE:" (no quotes).

 Class MTRandom64 was implemented in two steps:

   1)  A C-program for MT19937-64 (2004/9/29 version).  Coded by Takuji
       Nishimura and Makoto Matsumoto.

   2)  Translation from C (mt19937-64.c) to Visual Basic .NET was made
       and tested by me, Ron Charlton (2014-02-18). I also translated
       genrand64_intMax() from C++ code by Richard J. Wagner and Magnus
       Jonsson.

   Ron Charlton
   9002 Balcor Circle
   Knoxville, TN 37923-2301 USA
   Email:      Ron @ RonCharlton.org (remove spaces)
   Home Page:  http://RonCharlton.org/
   Start Date: 2014-02-18

 Bug reports, improvements, corrections, complaints or kudos are welcomed.

 The C version, mt19937-64.c, was obtained via a link at
 http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html on 2014-02-17.

 For cryptographically secure random number generation, search
 Visual Basic .NET Help for "RNGCryptoServiceProvider class". Or
 see http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/efaq.html.

 I compared the Visual Basic .NET Main()'s output file,
 "mt19937-64VBTest.out.txt", to file "mt19937-64.out.txt" from
 the original MT authors' web site. The files are identical.
 (See "USE:" below for details.)

 I also modified the original mt19937-64test.c code and VB Main() to
 produce 100,000,000 random integers and 100,000,000 random reals.
 The C & VB genrand64_int64() outputs were identical.

 The genrand64_real2() VB output was different from the C output for
 7 reals out of 100,000,000.  BUT THE DIFFERENCE IS AN ILLUSION
 caused by VB and C rounding differences when converting to
 a string.

 I compared 100,000,000 genrand64_real2() outputs for C and VB by
 using a VB union to show the VB genrand64_real2() output bit
 patterns in hexadecimal.  The 100,000,000 hexadecimal outputs for
 C and VB genrand64_real2() are identical.

 VB Format() rounds all Double outputs to no more than 15
 places, regardless of the Format() string. The 7 reals out of
 100,000,000 where VB differed are explained by printing them
 to 14 decimal places:

   C: 0.73880033999999  VB: 0.73880034000000
   C: 0.58501159999999  VB: 0.58501160000000
   C: 0.77837456999999  VB: 0.77837457000000
   C: 0.90141489999999  VB: 0.90141490000000
   C: 0.45203357999999  VB: 0.45203358000000
   C: 0.51149137999999  VB: 0.51149138000000
   C: 0.13164961999999  VB: 0.13164962000000

 Note: In Visual Basic 2012, 2010, 2008 and 2005 --
   Data type Integer    has a range of -2^31 inclusive to 2^31-1 inclusive.
   Data type UInteger   has a range of   0   inclusive to 2^32-1 inclusive.
   Data type Long       has a range of -2^63 inclusive to 2^63-1 inclusive.
   Data type ULong      has a range of   0   inclusive to 2^64-1 inclusive.
   Data type BigInteger has an unlimited range and is signed


 Comments (with redistribution requirements and disclaimers) from
 the original MT authors' C source code (mt19337-64.c) follow.
/*
   A C-program for MT19937-64 (2004/9/29 version).
   Coded by Takuji Nishimura and Makoto Matsumoto.

   This is a 64-bit version of Mersenne Twister pseudorandom number
   generator.

   Before using, initialize the state by using init_genrand64(seed)  
   or init_by_array64(init_key, key_length).

   Copyright (C) 2004, Makoto Matsumoto and Takuji Nishimura,
   All rights reserved.                          

   Redistribution and use in source and binary forms, with or without
   modification, are permitted provided that the following conditions
   are met:

     1. Redistributions of source code must retain the above copyright
        notice, this list of conditions and the following disclaimer.

     2. Redistributions in binary form must reproduce the above copyright
        notice, this list of conditions and the following disclaimer in the
        documentation and/or other materials provided with the distribution.

     3. The names of its contributors may not be used to endorse or promote 
        products derived from this software without specific prior written 
        permission.

   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

   References:
   T. Nishimura, ``Tables of 64-bit Mersenne Twisters''
     ACM Transactions on Modeling and 
     Computer Simulation 10. (2000) 348--357.
   M. Matsumoto and T. Nishimura,
     ``Mersenne Twister: a 623-dimensionally equidistributed
       uniform pseudorandom number generator''
     ACM Transactions on Modeling and 
     Computer Simulation 8. (Jan. 1998) 3--30.

   Any feedback is very welcome.
   http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html
   email: m-mat @ math.sci.hiroshima-u.ac.jp (remove spaces)
*/
 [End mt19937-64.c comments]

 The redistribution requirements and the disclaimers above
 apply to this file, mt19937-64.vb, and to its author as
 a contributor.

 It would be nice to CC: rjwagner@writeme.com and Ron @ RonCharlton.org
 when you write to the original authors.
---
_________________________________________________________________________________________
FUNCTIONS:
       Function                      Returns values in the range:
       -------------------------     -------------------------------------------------------
       genrand64_int64()             [0,18446744073709551615]  (0 to 2^64-1)

       genrand64_int63()             [0,9223372036854775807]  (0 to 2^63-1)

       genrand64_real1()             [0.0,1.0]   (both 0.0 and 1.0 included)

       genrand64_real2()             [0.0,1.0)   (0.0 included, 1.0 excluded)

       genrand64_real3()             (0.0,1.0)   (both 0.0 and 1.0 excluded)


       The following three functions were added by Ron Charlton for Visual Basic .NET. 

       genrand64_intMax(upper)         [0,upper] for upper < 2^64
                                               (0 to 18446744073709551615 but <= upper)

       genrand64_intRange(lower,upper) [lower,upper] for 0 <= lower <= upper < 2^64
                                               (0 <= lower <= upper <= 18446744073709551615)

       Optional:
       genrand64_int128SignedInt()     [-2^127,2^127-1]
                                               (-170141183460469231731687303715884105728 to
                                                 170141183460469231731687303715884105727)
_________________________________________________________________________________________
OPERATORS:
       Operator  =(ByVal v As MTRandom64, ByVal w As MTRandom64) As Boolean
       Operator <>(ByVal v As MTRandom64, ByVal w As MTRandom64) As Boolean
_________________________________________________________________________________________
SUBS:
       Sub                       Argument
       ------------------------  ---------------------------------------------------------
       init_genrand64(seed)      any seed included in [0,18446744073709551615]
       init_by_array64(array)    array has elements of type ULong;
                                 the array must have at least one element

       These four Subs were added for the Visual Basic .NET version. 

       init_by_array32(array)    array has elements of type UInteger;
                                 the array must have at least two elements
       init_by_MTRandom64(r)     r is another MTRandom64 instance
       init_by_random64(boolean) True:  reseed VB Random from the system clock,
                                        then reseed MTRandom64 from VB Random
                                 False: use the next two values from VB Random to
                                        reseed MTRandom64
       init_by_crypto64(0.0)     0.0 (cryptographically randomize the
                                 PRNG state; this DOES NOT make mt19937-64
                                 cryptographically secure, it provides the
                                 full range of possible initialized states/
                                 sequences).  Changing the argument value
                                 (not its type) will not affect initialization
       saveState64("fileName")   any valid file name (creates an XML file)
       loadState64("fileName")   name of any file saved earlier with saveState()


_________________________________________________________________________________________
USE:
 In your Visual Basic .NET application:

   1) Add this file to your Visual Basic .NET project.

   2) Remove Integer Overflow Checks (detailed at the top of this file).

   3) Optional: For genrand64_int128SignedInt() with VB2010 and later, add
      a project reference to BigInteger with menu item
           [VB 2010] Project/AddReference/.NET/System.Numerics
           [VB 2012] Project/AddReference/Assemblies/Framework/System.Numerics
      Set the #Const assignment near the first of this file as appropriate.

   4) Create one or more instances of the MTRandom64 class.  The pseudorandom
      sequence for each instance is initialized based on the arguments.
      Make certain each instance stays in scope for the duration of its use so
      it won't be re-initialized inadvertently.  Seven different methods of
      initialization are:

           a) Dim r As New MTRandom64()
                   Initialize with seed == 5489 (the original MT
                   authors' default seed).

           b) Dim r As New MTRandom64(19456UL)
                   Initialize with seed==19456.  Any unsigned long seed
                   in the range [1,18446744073709551615] is acceptable.

           c) Dim init64() As ULong = {&H12345UL, &H23456UL, &H34567UL, &H45678UL}
              Dim r As New MTRandom64(init64)
                   Initialize with an array of ULong (as in the
                   original MT authors' version).  The array must have
                   at least one element. 312 elements are desirable; more
                   or fewer elements are acceptable.  The element values
                   ideally should be truly random for best results.

           d) Dim r As New MTRandom64(True)
                   Seed VB Random from the system clock, and then
                   seed MTRandom64 with the next two values from VB Random.
                   True is required but ignored.

           e) Dim r As New MTRandom64("filename.ext")
                   Initialize with a generator state saved earlier with
                   MTRandom64.saveState("filename.ext")

           f) Dim r As New MTRandom64(0.0)
                   Initialize with cryptographically random numbers from
                   Visual Basic's RNGCryptoServiceProvider.  The argument
                   0.0 is required but ignored.  Every new MTRandom64 instance
                   that is initialized this way will have any one of
                   approximately 2^19937 different beginning states.
                   THIS DOES NOT MAKE MTRandom64 CRYPTOGRAPHICALLY SECURE.

           g) Dim init32() As UInteger = {&H12345UL, &H23456UL, &H34567UL, &H45678UL}
              Dim r As New MTRandom64(init32)
                   Initialize with an array of UInteger.  The array must have
                   at least two elements.  624 elements are desirable; more
                   or fewer elements are acceptable.  The element values
                   ideally should be truly random for best results.

           h) Dim p As New MTRandom64()
              Dim r As New MTRandom64(p)
                   Initialize PRNG r's state with PRNG p's state.

   5) Call any of the genrand64_X() functions listed above.  You can re-
      initialize an MTRandom64 instance at any point by calling init_genrand64(),
      init_by_array64(), init_by_random64(True), init_by_crypto64(), init_by_MTRandom64()
      or init_by_array32(). You can save or load the PRNG state at any point
      by calling saveState64() or loadState64().

   6) Catch exceptions as desired.  The MTRandom64 exception classes are at the
      end of this file.

 To test genrand64_int64(), genrand64_real2(), init_genrand64() and init_by_array64()
 in the Visual Basic .NET version of 64-bit Mersenne Twister:

   1) Create a Visual Basic .NET console application Project consisting of files
           mt19937-64.vb
           Demo64.vb
           PerformanceTest64.vb
           MakeEntropyTestData64.vb
           MakeDiehardData64.vb
           Main.vb

   2) Follow the instructions at the top of this file.  Then build and run the project.

   3) Compare the file "mt19937-64VBTest.out.txt" with the original MT authors'
      test output file ("mt19937-64.out.txt", found by following
      links at http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt64.html).  
      They should be identical.

_________________________________________________________________________________________
PERFORMANCE:
   On a iBUYPOWER Pro Series P700 computer with 3.60 GHz Intel i7-3820 processor,
   32 GB RAM, Visual Basic .NET (2012) compiler, and generating 100,000,000 random
   numbers with each function (running the Release version at a Cmd.exe prompt)
   on 64-bit Windows:

                                   Seconds     Nanoseconds     Calls Per
   Function                        Run Time    Per Call        Second
   --------------------------      --------    -----------     -----------
   genrand64_int64()                0.741          7.41        135,000,000
   genrand64_int63()                0.787          7.87        127,000,000
   genrand64_real1()                0.866          8.66        109,000,000
   genrand64_real2()                0.881          8.81        106,000,000
   genrand64_real3()                0.881          8.81        106,000,000
   genrand64_intMax(1000UL)         0.790          7.90         83,540,000
   genrand64_intMax(&H5FFFFFFFUL)   1.666         16.66         56,460,000
   genrand64_intRange(10UL, 20UL)   2.953         29.53         46,750,000
   genrand64_int128SignedInt()     31.823        318.23          3,142,000

 NOTE: genrand64_int64() runs about 43 times faster than
 genrand64_int128SignedInt(). Data type BigInteger is SLOW on 32- and 64-bit
 Windows!

Contact

E-mail: Ron Charlton <Ron @ RonCharlton.org> (remove the spaces)
Knoxville, Tennessee   USA

Bug reports, improvements, corrections, complaints or kudos are welcomed.

Document last revised: 2019-09-04