FreeBASIC's PRNG #2

General FreeBASIC programming questions.
Post Reply
deltarho[1859]
Posts: 4292
Joined: Jan 02, 2017 0:34
Location: UK
Contact:

Re: FreeBASIC's PRNG #2

Post by deltarho[1859] »

I have not looked at this before but the '-multithreaded' switch will give your machine a good 'workout'. For the hell of it, I ran two instances of PractRand with that switch and saw my CPU usage averaging 80% on my 8 thread Intel i7. I think that I will just pop down to the shops and get an Intel® Core™ i9-7980XE; that has 36 threads. It may be wise to have a word with my bank manager first though. <smile>
paul doe
Moderator
Posts: 1730
Joined: Jul 25, 2017 17:22
Location: Argentina

Re: FreeBASIC's PRNG #2

Post by paul doe »

deltarho[1859] wrote:Hi Paul. I use a very simple command line for PractRand.

<whatever.exe> | rng_test stdin32 -multithreaded

where <whatever.exe> is the name of the piping program.

On a side note if a test fails at PractRand's first hurdle then try

<whatever.exe> | rng_test stdin32 -tlmin 1KB -multithreaded

This will start PractRand at 1KB. I had to do this for the LCG tests which were failing at 4KB or 8KB.

On my machine the '-multithreaded' switch sees PractRand run about 25% faster.
Thanks, David. The '-multithreaded' option does speed things up, but certainly, I can't expect any miracles here =D

This a simple stub of the code I'm using:

Code: Select all

dim shared as ulongint x = 12, w = 0, s = &h8b5ad4cef9c2703b

function msws() as ulong
  x *= x
  w += s
  x += w
  x = ( x shr 32 ) or ( x shl 32 )
  
  return( x )
end function

/'
  Main code
'/
dim as string cmd = "RNG_test stdin -multithreaded"
dim as long fileHandle = freeFile()

open pipe cmd for binary access write as fileHandle

do
  put #fileHandle, , msws()
loop until( inkey() <> "" )

close( fileHandle )
That way, I don't even have to leave my environment to do quick tests: hit quickrun, and wait for the results =D

It's a pity that FreeBasic doesn't support bi-directional piping directly. You can implement it using the OS features, or another, higher level program that pipes the testing code in one direction, and the PractRand instance in another.
paul doe
Moderator
Posts: 1730
Joined: Jul 25, 2017 17:22
Location: Argentina

Re: FreeBASIC's PRNG #2

Post by paul doe »

deltarho[1859] wrote:I don't know exactly how Bernard Widynski created his seed.h ...
Just to let you know. He uses this C code:

Code: Select all

/**************************************************************************\
*                                                                          *
*   create seed.h include file                                             *
*                                                                          *
*   seed.h contains random and distinct seed values.  These seeds can be   *
*   used for stream initialization. The streams will be different and      *
*   random at the very beginning.                                          *
*                                                                          *
*   The seeds are chosen so that every nibble is different.  This prevents *
*   regularities that occur at the very beginning when the nibbles repeat. *
*   For example, with a seed of all fs, i.e. 0xffffffffffffffff, even      *
*   though this passes BigCrush, the data appears non-random for the first *
*   10 iterations.  A seed of mostly 0s, e.g. 0x0000000100000001, also     *
*   passes BigCrush, but the data also appears non-random for the first    *
*   10 iterations.  Good data at the very beginning can be obtained if the *
*   nibbles are all different.  Seeds of this type are generated by this   *
*   program.                                                               *
*                                                                          *
*   Two arrays are malloced: x and y.  The x array is used to set the upper*
*   32 bits of the seed.  The y array is used to to set the lower 32 bits  *
*   of the seed.  The msws rng is called to generate random data to fill   *
*   these arrays.  Each nibble is checked to be different.  Prior to adding* 
*   an element a 2^32 bit map is used to verify that it has not been added *
*   previously.  This assures distinct data in the x and y arrays.  These  *
*   arrays are printed into seed.h. The seed.h file may be used as follows:*
*                                                                          *
*   uint64_t seed[] = {                                                    *
*   #include "seed.h"                                                      *
*   };                                                                     *
*                                                                          *
*   x = 0; w = 0; s = seed[i];                                             *
*                                                                          *
*   See streams_example for example usage.                                 *
*                                                                          *
\**************************************************************************/

#include "msws.h"
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>

#define N 25000 

#define two32 4294967296
#define nbytes two32/8
#define nwords two32/32

int main () {

   FILE *fp;

   uint32_t a, *b, c, i, j, k, m, n, *x, *y;

   /* malloc x and y arrays */

   x = (uint32_t *) malloc(N*4);
   if (x == NULL) {
      printf("malloc error\n");
      return 1;
   }
   y = (uint32_t *) malloc(N*4);
   if (y == NULL) {
      printf("malloc error\n");
      return 1;
   }

   /* malloc bit map array */

   b = (uint32_t *) malloc(nbytes);
   if (b == NULL) {
      printf("malloc error \n");
      return 1;
   }

   /* zero bit map */

   for (i=0;i<nwords;i++) {
       b[i] = 0;
   }

   /* create random x[N] */

   for (n=0;n<N;n++) {
      for (;;) {
         for (m=0,a=0,c=0;m<32;) {
            j = msws();                 /* get 32-bit random word */
            for (i=0;i<32;i+=4) {
               k = (j>>i) & 0xf;        /* get a nibble */
               if ((c & (1<<k)) == 0) { /* verify not used previously */
                  c |= (1<<k);
                  a |= (k<<m);          /* add nibble to output */
                  m += 4;
                  if (m>=32) break;        
               }
            } 
         }

         i = a / 32; j = a % 32;        /* verify distinct data */
         if ((b[i] & (1<<j)) == 0) {
            b[i] |= (1<<j);
            x[n] = a;
            break;
         }
      }
   }

   /* zero bit map */

   for (i=0;i<nwords;i++) {
       b[i] = 0;
   }

   /* create random y[N] */

   for (n=0;n<N;n++) {
      for (;;) {
         for (m=0,a=0,c=0;m<32;) {
            j = msws();                 /* get 32-bit random word */
            for (i=0;i<32;i+=4) {
               k = (j>>i) & 0xf;        /* get a nibble */
               if ((c & (1<<k)) == 0) { /* verify not used previously */
                  c |= (1<<k);
                  a |= (k<<m);          /* add nibble to output */
                  m += 4;
                  if (m>=32) break;
               }
            } 
         }

         a |= 1;                        /* set least significant bit to 1 */

         i = a / 32; j = a % 32;        /* verify distinct data */
         if ((b[i] & (1<<j)) == 0) {
            b[i] |= (1<<j);
            y[n] = a;
            break;
         }
      }
   }

   /* create seed.h include file */

   fp = fopen("seed.h","w");
   if (fp == NULL) {
      printf("unable to open seed.h\n");
      return 1;
   }

   for (i=0;i<N;i++) {
      fprintf(fp,"0x%8.8x%8.8x,\n",x[i],y[i]);
   }

   fclose(fp);
 
   return 0;

}
I can port it if you're interested in studying it =D
deltarho[1859]
Posts: 4292
Joined: Jan 02, 2017 0:34
Location: UK
Contact:

Re: FreeBASIC's PRNG #2

Post by deltarho[1859] »

paul doe wrote:I can port it if you're interested in studying it =D
No thanks, Paul, I'll stick with the 64_bit prime.

BTW, use stdin32 and not stdin which will do a 32-bit analysis as opposed an 8-bit analysis.
deltarho[1859]
Posts: 4292
Joined: Jan 02, 2017 0:34
Location: UK
Contact:

Re: FreeBASIC's PRNG #2

Post by deltarho[1859] »

I have no idea if this would make any difference but I use the following. It pipes a 1MB string.

Code: Select all

Dim Shared S As String * 1048576
Dim As Ulong Ptr SPtr, BasePtr
Dim As Long j

SPtr = Cptr(Ulong Ptr, StrPtr( S ))
BasePtr = SPtr

Do
  For j = 1 to 262144
    *SPtr = randomNumber.one()
    SPtr += 1
  Next
  Print S;
  SPtr = BasePtr
Loop
paul doe
Moderator
Posts: 1730
Joined: Jul 25, 2017 17:22
Location: Argentina

Re: FreeBASIC's PRNG #2

Post by paul doe »

deltarho[1859] wrote:BTW, use stdin32 and not stdin which will do a 32-bit analysis as opposed an 8-bit analysis.
Oooh good to know, thanks =D
deltarho[1859] wrote:I have no idea if this would make any difference...
From a functionality standpoint, no. However, opening a pipe with 'open pipe' offers you the advantage of simply invoking PractRand from inside your code, so you can quickly test several algorithms in a row ie. you don't need to compile your code and go to the command line to invoke PractRand.

You could create code that, say, pipes PCG32, MSWS and any/all other algorithm of your choice, pass them to the ChiSquared test, ENT, BigCrush and PractRand in succession, and gather all the results in a single report when finished. All this simply by hitting 'QuickRun' in the IDE of your choice =D
deltarho[1859]
Posts: 4292
Joined: Jan 02, 2017 0:34
Location: UK
Contact:

Re: FreeBASIC's PRNG #2

Post by deltarho[1859] »

I like your 'open pipe cmd ...' approach.
paul doe wrote:From a functionality standpoint, no.
Actually it makes a world of difference.

This is your piping program start:

Code: Select all

rng=RNG_stdin, seed=unknown
length= 1 megabyte (2^20 bytes), time= 3.4 seconds
  no anomalies in 94 test result(s)
 
rng=RNG_stdin, seed=unknown
length= 2 megabytes (2^21 bytes), time= 7.2 seconds
  no anomalies in 109 test result(s)
 
rng=RNG_stdin, seed=unknown
length= 4 megabytes (2^22 bytes), time= 14.7 seconds
  no anomalies in 124 test result(s)
This is my 1MB string start:

Code: Select all

rng=RNG_stdin32, seed=unknown
length= 256 megabytes (2^28 bytes), time= 2.5 seconds
  no anomalies in 165 test result(s)
 
rng=RNG_stdin32, seed=unknown
length= 512 megabytes (2^29 bytes), time= 5.0 seconds
  no anomalies in 178 test result(s)
 
rng=RNG_stdin32, seed=unknown
length= 1 gigabyte (2^30 bytes), time= 9.5 seconds
  no anomalies in 192 test result(s)
Try this:

Code: Select all

Dim Shared As Ulongint x = 12, w = 0
Dim As String cmd = "RNG_test stdin32 -multithreaded"
Dim As Long fileHandle = Freefile()
Dim Shared S As String * 1048576
Dim As Ulong Ptr SPtr, BasePtr
Dim As Long j
 
Function msws() As Ulong
  x *= x
  w += &h8b5ad4cef9c2703b
  x += w
  x = ( x Shr 32 ) Or ( x Shl 32 )
 
  Return( x )
End Function
 
SPtr = Cptr(Ulong Ptr, Strptr( S ))
BasePtr = SPtr

Open pipe cmd For Binary Access Write As fileHandle 
Do
  For j = 1 To 262144
    *SPtr = msws
    SPtr += 1
  Next
  Print #fileHandle, S;
  SPtr = BasePtr
Loop 
Close( fileHandle )
paul doe
Moderator
Posts: 1730
Joined: Jul 25, 2017 17:22
Location: Argentina

Re: FreeBASIC's PRNG #2

Post by paul doe »

deltarho[1859] wrote:I like your 'open pipe cmd ...' approach
...
Try this:
Ah, I see. I was piping 1 32-bit number at a time hahaha! Sorry, told you I'm quite noob in these matters =D

Thanks for the suggestion! Things should work much more smoothly now =D
dodicat
Posts: 7976
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: FreeBASIC's PRNG #2

Post by dodicat »

My second attempt (bar the string one)
The string one run to 2gb shows no anomalies, but it is too slow and I got fed up waiting.
Here is my second attempt.
This is pipe.bas

Code: Select all

'pipe.exe
Type Random
    Private:
	As Ulongint a,b,c,d
    Public:
    Declare Function Valu() As Ulongint
    Declare Function Valf() As double
    Declare Sub seed(As Ulongint)
End Type

Function Random.Valu() As Ulongint
	Dim As Ulongint e = a - ((b Shl 7) Or (b Shr (57)))
	a = b xor ((c Shl 13) Or (c Shr (51)))
	b = c + ((d Shl 37) Or (d Shr (27)))
	c = d + e
	d = e + a
	Return d
End Function

function Random.valf() as double
    return Valu/18446744073709551615
    end function

Sub Random.seed(Byval z As Ulongint)
    This=Type(4058668781,z,z,z)
    For i As Ulongint=1 To 20
        Valu
    Next
End Sub

dim as random p
p.seed(100)

Dim Shared S As String * 1048576
Dim As Ulong Ptr SPtr, BasePtr
Dim As Long j

SPtr = Cptr(Ulong Ptr, StrPtr( S ))
BasePtr = SPtr
 
Do
  For j = 1 to 262144
    *SPtr = p.valu
    SPtr += 1
  Next
  print S;
  SPtr = BasePtr
Loop
   
And the results up to 64 Gb

Code: Select all

 
Microsoft Windows [Version 10.0.17134.285]
(c) 2018 Microsoft Corporation. All rights reserved.

C:\Users\User\Desktop\bin\random\PractRand_0.94\PractRand_094\bin\msvc12_64bit>pipe3.exe | rng_test stdin32 -multithread
ed
RNG_test using PractRand version 0.94
RNG = RNG_stdin32, seed = unknown
test set = core, folding = standard (32 bit)

rng=RNG_stdin32, seed=unknown
length= 256 megabytes (2^28 bytes), time= 3.3 seconds
  no anomalies in 165 test result(s)

rng=RNG_stdin32, seed=unknown
length= 512 megabytes (2^29 bytes), time= 6.8 seconds
  no anomalies in 178 test result(s)

rng=RNG_stdin32, seed=unknown
length= 1 gigabyte (2^30 bytes), time= 14.1 seconds
  no anomalies in 192 test result(s)

rng=RNG_stdin32, seed=unknown
length= 2 gigabytes (2^31 bytes), time= 27.9 seconds
  no anomalies in 204 test result(s)

rng=RNG_stdin32, seed=unknown
length= 4 gigabytes (2^32 bytes), time= 57.4 seconds
  no anomalies in 216 test result(s)

rng=RNG_stdin32, seed=unknown
length= 8 gigabytes (2^33 bytes), time= 120 seconds
  no anomalies in 229 test result(s)

rng=RNG_stdin32, seed=unknown
length= 16 gigabytes (2^34 bytes), time= 255 seconds
  no anomalies in 240 test result(s)

rng=RNG_stdin32, seed=unknown
length= 32 gigabytes (2^35 bytes), time= 530 seconds
  no anomalies in 251 test result(s)

rng=RNG_stdin32, seed=unknown
length= 64 gigabytes (2^36 bytes), time= 1110 seconds
  Test Name                         Raw       Processed     Evaluation
  [Low1/32]Gap-16:B                 R=  +4.4  p =  1.0e-3   unusual
  ...and 262 test result(s) without anomalies

  
The first hiccup at 64 Gb.
My computer is not very fast.(Ebay bargain.)
deltarho[1859]
Posts: 4292
Joined: Jan 02, 2017 0:34
Location: UK
Contact:

Re: FreeBASIC's PRNG #2

Post by deltarho[1859] »

@dodicat

There is a lot of shifting going on there but it still comes in at 243MHz.

I think that this thread is showing that FB's suite of generators is in dire need of a serious overhaul.
badidea
Posts: 2586
Joined: May 24, 2007 22:10
Location: The Netherlands

Re: FreeBASIC's PRNG #2

Post by badidea »

deltarho[1859] wrote:I think that I will just pop down to the shops and get an Intel® Core™ i9-7980XE; that has 36 threads. It may be wise to have a word with my bank manager first though. <smile>
A TPD of 165 Watt! I would need to plug in 3 power supplies in my laptop for that. Not that it would fit with all the cooling requirements :-)
dafhi
Posts: 1640
Joined: Jun 04, 2005 9:51

Re: FreeBASIC's PRNG #2

Post by dafhi »

@dodicat - interesting algorithm. rho seems to indicate that it's one of FB's
dodicat
Posts: 7976
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: FreeBASIC's PRNG #2

Post by dodicat »

Observation:
On my old Dell, double cpu xeon (Two of 'em, not cores) Win XP runs hotter than Scientific Linux.
deltarho[1859]
Posts: 4292
Joined: Jan 02, 2017 0:34
Location: UK
Contact:

Re: FreeBASIC's PRNG #2

Post by deltarho[1859] »

I have mentioned on a few occasions that a tight loop for measuring MHz is not particularly informative.

Here are runs of my 'real life' test where each generator is given 20 seconds to do the same task.

gcc 8.1 FB 1.06

Code: Select all

32-bit
 
5            1.50
1            425.79
3            440.59
CMWC4096     463.84
4            474.16
CryptoRndII  475.04
2            486.63
RndMT        606.92
xoshiro256   721.62
MsWs         777.78
PCG32II      878.54
Knuth64      883.05
 
64-bit
 
5            1.59
1            532.52
RndMT        725.48
CMWC4096     809.45
3            840.66
CryptoRndII  970.62
4            981.61
2            1061.21
xoshiro256   1254.99
MsWs         1307.09
PCG32II      1382.72
Knuth64      1383.80
With Knuth64 being a LCG it should leave everyone standing but that is not the case. With Knuth64 failing PractRand in the KB domain and both PCG32II and MsWs passing in the TB domain then we can write off Knuth64.

PCG32II is still holding it's own but paul doe's MsWs find is not far behind.

I will remove xoshiro256 from the test. It is fast but it has nothing else going for it.
paul doe
Moderator
Posts: 1730
Joined: Jul 25, 2017 17:22
Location: Argentina

Re: FreeBASIC's PRNG #2

Post by paul doe »

deltarho[1859] wrote:I will remove xoshiro256 from the test. It is fast but it has nothing else going for it.
Speaking of fast: you don't really need to use strings to pass binary data to PractRand:

Code: Select all

dim shared as ulongint x = 12, w = 0, s = &h8b5ad4cef9c2703b

function msws() as ulong
  x *= x
  w += s
  x += w
  x = ( x shr 32 ) or ( x shl 32 )
  
  return( x )
end function

dim as string cmd = "RNG_test stdin32 -multithreaded"
dim as long fileHandle = freeFile()

dim as ulongint numbers = 262144 '' how many numbers to pass to PractRand
dim as ulong ptr mem = new ulong[ numbers ]
dim as ulong ptr address = mem

open pipe cmd for binary access write as fileHandle

do
  for i as integer = 1 To numbers
    *address = msws()
    address += 1
  next
  
  put #fileHandle, , *cptr( ubyte ptr, mem ), numbers * sizeOf( ulong )
  address = mem
  
  sleep( 1, 1 )
loop until( inkey() <> "" )

close( fileHandle )

delete[] mem
This makes the task much more amenable to me. Thanks for the tip ;)
Post Reply