Has anyone ported the PCG PRNG to FreeBASIC

General FreeBASIC programming questions.
cbruce
Posts: 163
Joined: Sep 12, 2007 19:13
Location: Dallas, Texas

Has anyone ported the PCG PRNG to FreeBASIC

Post by cbruce »

Has anyone ported the PCG PRNG from C99 to a version for FreeBASIC that they would like to share?

PCG, A Family of Better Random Number Generators
http://www.pcg-random.org/

Not really a C guy ... so wanted to know before I give it a try.

Thanks,
CBruce
MrSwiss
Posts: 3910
Joined: Jun 02, 2013 9:27
Location: Switzerland

Re: Has anyone ported the PCG PRNG to FreeBASIC

Post by MrSwiss »

Hi,

don't know exactly, what you are looking for, but FB has built in random generators.
There is also a thread in Windows: Fast CPRNG
cbruce
Posts: 163
Joined: Sep 12, 2007 19:13
Location: Dallas, Texas

Re: Has anyone ported the PCG PRNG to FreeBASIC

Post by cbruce »

Hi MrSwiss,

Melissa O'Neill has created an amazing family of PRNG's and CPRNG's, written in pure C99 and/or C++ (no ASM), that are faster and have longer periods of non-repeating sequences than any other RNG out there. These include PRNGs that can provide multiple non-collision streams from a single instance.

She has not created an academic exercise or just published a couple of pseudo-code algorithms. These are multiple RNG algorithms that are coded for the real world, have multiple examples, and work as advertised - and it's all very well documented. [grin]

She has a long whitepaper (47 pages) on her site that is a must read ... a lot of incredible information concerning her family of RNGs - as well as analysis, tests and statistics comparing her RNGs against all other ones that are known.

She has a simple version that is incredible in itself, but her others versions are beyond compare. I've compiled them and her demo/test applications to see them in operation - but I've never ported C code to BASIC code - (but I'm getting ready to try unless someone else has already done so).

Thanks,
CBruce
srvaldez
Posts: 3373
Joined: Sep 25, 2005 21:54

Re: Has anyone ported the PCG PRNG to FreeBASIC

Post by srvaldez »

hello cbruce
you can use fbfrog to help with the translation there's also a C++ to VB Converter the demo is free though limited.
counting_pine
Site Admin
Posts: 6323
Joined: Jul 05, 2005 17:32
Location: Manchester, Lancs

Re: Has anyone ported the PCG PRNG to FreeBASIC

Post by counting_pine »

I've ported the code at http://www.pcg-random.org/download.html:

Code: Select all

'' *Really* minimal PCG32 code / (c) 2014 M.E. O'Neill / pcg-random.org
'' Licensed under Apache License 2.0 (NO WARRANTY, etc. see website)
'' FreeBASIC translation by Matthew Fearnley 2017-06-04

type pcg32_random_t
  as ulongint state, inc
end type

function pcg32_random_r(byval rng as pcg32_random_t ptr) as ulong
    dim as ulongint oldstate = rng->state
    '' Advance internal state
    rng->state = oldstate * 6364136223846793005ULL + (rng->inc or 1)
    '' Calculate output function (XSH RR), uses old state for max ILP
    dim as ulong xorshifted = ((oldstate shr 18u) xor oldstate) shr 27u
    dim as ulong rot = oldstate shr 59u
    return (xorshifted shr rot) or (xorshifted shl ((-rot) and 31))
end function

'' test

dim rng as pcg32_random_t

for i as integer = 1 to 10
  print pcg32_random_r(@rng)
next i
And here's a complete C program to test against:

Code: Select all

#include <stdint.h>
#include <stdio.h>

// *Really* minimal PCG32 code / (c) 2014 M.E. O'Neill / pcg-random.org
// Licensed under Apache License 2.0 (NO WARRANTY, etc. see website)

typedef struct { uint64_t state;  uint64_t inc; } pcg32_random_t;

uint32_t pcg32_random_r(pcg32_random_t* rng)
{
    uint64_t oldstate = rng->state;
    // Advance internal state
    rng->state = oldstate * 6364136223846793005ULL + (rng->inc|1);
    // Calculate output function (XSH RR), uses old state for max ILP
    uint32_t xorshifted = ((oldstate >> 18u) ^ oldstate) >> 27u;
    uint32_t rot = oldstate >> 59u;
    return (xorshifted >> rot) | (xorshifted << ((-rot) & 31));
}

int main()
{
  pcg32_random_t rng = {0,0};
  int i;
  for (i = 0; i < 10; i++)
  {
    printf("%u\n", pcg32_random_r(&rng));
  }
  return 0;
}
Both should output:

Code: Select all

0
0
3837872008
932996374
1548399547
1612522464
473443212
3522865942
1734871597
2449558126
Evidently if you start with a zeroed out pcg32_random_t instance, it takes a couple of iterations to produce anything random-looking. So the minimal implementation at least needs some seeding first.
counting_pine
Site Admin
Posts: 6323
Joined: Jul 05, 2005 17:32
Location: Manchester, Lancs

Re: Has anyone ported the PCG PRNG to FreeBASIC

Post by counting_pine »

From just looking at the minimal code and reading a couple of pages, I'm amazed.

The principle is ridiculously simple. I would describe it like this:
1. use a simple, well-understood pseudo-random generator (e.g. linear congruential generator as used in the minimal code)
2. return a secure hash of the output
3. there is no step 3!

The periodicity of the random numbers is the same as that of the simple PRNG, but the secure hashing means that without a massive lookup table you can't find out the internal state based on its output.
(In the example code's case, it returns 32 bits of output for a 64-bit state anyway, so it's definitely a one-way hash.)

I don't really understand the hashing method, although it's clearly pretty simple. But from the Party Tricks page it evidently has the property of being able to calculate the input needed to contrive any output. This itself isn't particularly useful when generating random numbers, but it means that all outputs are possible, which is a good property for a random number generator.
cbruce
Posts: 163
Joined: Sep 12, 2007 19:13
Location: Dallas, Texas

Re: Has anyone ported the PCG PRNG to FreeBASIC

Post by cbruce »

THANKS for converting the basic version counting_pine!!!
I should be able to convert the full version by referencing this one.
Now I get to go play!!!

CBruce

FYI counting_pine .... From her whitepaper, the simple description of the Ms. O'Neill's algorithm:
The key idea is to pass the output of a fast well-understood “medium quality” random number generator to an efficient permutation function (a.k.a. hash function), built from composable primitives, that enhances the quality of the output. The algorithm can be applied at variety of bit sizes, including 64 and 128 bits (which provide 32- and 64-bit outputs, with periods of 2 64 and 2 128). Optionally, we can provide each b -bit generator with a b - 1 bit stream-selection constant, thereby providing 2 b - 1 random streams, which are full period and entirely distinct. An extension adds up to 2 b -dimensional equidistribution for a total period of 2 b 2 b . The construction of the permutation function and the period-extension technique are both founded on the idea of permutation functions on tuples.

In its standard variants, b -bit generators use a 2 b /2 -to-1 function to produce b /2 bits of output. These functions can be designed to make it difficult for an adversary to discover the generator’s internal state by examining its output, and thus make it challenging to predict. This property, coupled with the ability to easily switch between random streams, provides many of the benefits provided by cryptographically secure generators without the overheads usually associated with those generators.
Last edited by cbruce on Jun 04, 2017 16:56, edited 1 time in total.
counting_pine
Site Admin
Posts: 6323
Joined: Jul 05, 2005 17:32
Location: Manchester, Lancs

Re: Has anyone ported the PCG PRNG to FreeBASIC

Post by counting_pine »

I'll add the caveat that after further reading (particularly http://www.pcg-random.org/predictability.html), it is obvious that she doesn't guarantee the numbers generated by the algorithm are unpredictable.
It is only clear that with a linear congruential generator, hashing the output or even just discarding some of the state when outputting it, makes it much more "challenging" to predict.
But obviously we can hope that it is secure, and particularly hope that it can be proven to be secure, and she is keen to invite the mathematical community to put it to the test.
deltarho[1859]
Posts: 4292
Joined: Jan 02, 2017 0:34
Location: UK
Contact:

Re: Has anyone ported the PCG PRNG to FreeBASIC

Post by deltarho[1859] »

I don't impress easily.

I am impressed.<smile>

I have added a few lines to counting_pine's code to determine the average single in [0,1) and an estimate of the speed of single generation.

I get:

Code: Select all

Average [0,1) : 0.500004
Million singles per second: 188.582
That 0.500004 does not prove randomness. Had we got 0.3, say, then that would prove non-randomness. The speed is very good and about 80% faster than FB's option 2 (MWC) and over twice as fast as FB's option 3 (Mersenne Twister). What is more impressive is the small amount of state space used, admittedly this is the minimal version, and the code size.

Ms O'Neill would do well to include PractRand in the tests. The author of PractRand considered 120 PRNGs and his suite found bias in 78. TestU01(Big Crush) found bias in 50. Dieharder found bias in 25. Dieharder has had its day.

So, I presented the above to PractRand. There was only a couple of anomalies in a one terabyte test, on par with my CryptoRndII which uses cryptographic random nhumbers. I would have posted before now but PractRand cannot be hurried. It should be noted that PractRand does not prove randomness either. What it tells us is whether there is any evidence of non-randomness or not.

I would go futher than counting_pine and say that under no circumstance should this code be used in cryptograhic applications until the paper has been reviewed but, more importantly, examined by the world's crypanalysts who may have some suggestions - they will have some suggestions.<smile>

I shall involve myself no further - this is CBruce's baby.
I should be able to convert the full version by referencing this one.
Now I get to go play!!!
I look forward to the full version as others will, I am sure.

Call here to see Ms O'Neill in action. Pull up your easy chair - it is 74 minutes long. She is a Professor of Computer Science at Harvey Mudd.

Code: Select all

'' *Really* minimal PCG32 code / (c) 2014 M.E. O'Neill / pcg-random.org
'' Licensed under Apache License 2.0 (NO WARRANTY, etc. see website)
'' FreeBASIC translation by Matthew Fearnley 2017-06-04
 
Type pcg32_random_t
  As Ulongint state, inc
End Type
 
Function pcg32_random_r(Byval rng As pcg32_random_t Ptr) As Ulong
    Dim As Ulongint oldstate = rng->state
    '' Advance internal state
    rng->state = oldstate * 6364136223846793005ULL + (rng->inc Or 1)
    '' Calculate output function (XSH RR), uses old state for max ILP
    Dim As Ulong xorshifted = ((oldstate Shr 18u) xor oldstate) Shr 27u
    Dim As Ulong rot = oldstate Shr 59u
    Return (xorshifted Shr rot) Or (xorshifted Shl ((-rot) And 31))
End Function
 
'' test
 
Dim rng As pcg32_random_t
' Warm up - probably don't need 100 - about 0.5 micro-seconds
' but worth it - trust me <smile>
Randomize , 5
rng.state = Rnd*(2^64-1) ' using a cryptographically random Ulongint seed
For i As Integer = 1 To 100
  pcg32_random_r(@rng)
Next i
 
Dim As Ulong I, N
Dim T As Double
Dim As Ulong TempVar
Dim Result As Single
Dim Tot As Double
 
N = 10^8 ' 100 x million
T = Timer
For I = 1 To N
  TempVar = pcg32_random_r(@rng)
  ' Single precision
  Asm
    mov eax, dword Ptr [TempVar]
    movd xmm0, eax
    psrlq xmm0, 9
    mov eax, 1
    cvtsi2ss xmm1, eax
    por xmm0, xmm1
    subss xmm0, xmm1
    movd [Result], xmm0
  End Asm
  Tot += Result
Next
T = Timer - T
Print "Average [0,1) : ";Using "#.######";tot/n
Print "Million singles per second: ";Using "###.###";n/(t*1000000)
 
Sleep
cbruce
Posts: 163
Joined: Sep 12, 2007 19:13
Location: Dallas, Texas

Re: Has anyone ported the PCG PRNG to FreeBASIC

Post by cbruce »

Thanks, David. The fact that you are impressed, tells me I might be headed down the right road.

I'll be working on this next week in my evenings. and I'll keep you updated.

By the way, if you have time, take a look at her whitepaper ... It is actually the best read I have ever seen on RNGs.

BEH
deltarho[1859]
Posts: 4292
Joined: Jan 02, 2017 0:34
Location: UK
Contact:

Re: Has anyone ported the PCG PRNG to FreeBASIC

Post by deltarho[1859] »

The fact that you are impressed, tells me I might be headed down the right road.
Thank you. The cheque is in the post.
take a look at her whitepaper
I will.
srvaldez
Posts: 3373
Joined: Sep 25, 2005 21:54

Re: Has anyone ported the PCG PRNG to FreeBASIC

Post by srvaldez »

hello cbruce
using fbfrog and a bit of editing here's the pcg_prng

pcg_variants.bi

Code: Select all

/'
 * PCG Random Number Generation for C.
 *
 * Copyright 2014 Melissa O'Neill <oneill@pcg-random.org>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * For additional information about the PCG random number generation scheme,
 * including its license and other licensing options, visit
 *
 *     http://www.pcg-random.org
 '/

/'
 * This code is derived from the canonical C++ PCG implementation, which
 * has many additional features and is preferable if you can use C++ in
 * your project.
 *
 * Much of the derivation was performed mechanically.  In particular, the
 * output functions were generated by compiling the C++ output functions
 * into LLVM bitcode and then transforming that using the LLVM C backend
 * (from https://github.com/draperlaboratory/llvm-cbe), and then
 * postprocessing and hand editing the output.
 *
 * Much of the remaining code was generated by C-preprocessor metaprogramming.
 '/
 
 'translated using fbfrog https://github.com/dkl/fbfrog
 
#pragma once

'' #include once "inttypes.bi"

extern "C"

const PCG_VARIANTS_H_INCLUDED = 1

function pcg_rotr_8(byval value as ubyte, byval rot as ulong) as ubyte
	return (value shr rot) or (value shl ((-rot) and 7))
end function

function pcg_rotr_16(byval value as ushort, byval rot as ulong) as ushort
	return (value shr rot) or (value shl ((-rot) and 15))
end function

function pcg_rotr_32(byval value as ulong, byval rot as ulong) as ulong
	return (value shr rot) or (value shl ((-rot) and 31))
end function

function pcg_rotr_64(byval value as ulongint, byval rot as ulong) as ulongint
	return (value shr rot) or (value shl ((-rot) and 63))
end function

function pcg_output_xsh_rs_16_8(byval state as ushort) as ubyte
	return cubyte(((state shr 7u) xor state) shr ((state shr 14u) + 3u))
end function

function pcg_output_xsh_rs_32_16(byval state as ulong) as ushort
	return cushort(((state shr 11u) xor state) shr ((state shr 30u) + 11u))
end function

function pcg_output_xsh_rs_64_32(byval state as ulongint) as ulong
	return culng(((state shr 22u) xor state) shr ((state shr 61u) + 22u))
end function

function pcg_output_xsh_rr_16_8(byval state as ushort) as ubyte
	return pcg_rotr_8(((state shr 5u) xor state) shr 5u, state shr 13u)
end function

function pcg_output_xsh_rr_32_16(byval state as ulong) as ushort
	return pcg_rotr_16(((state shr 10u) xor state) shr 12u, state shr 28u)
end function

function pcg_output_xsh_rr_64_32(byval state as ulongint) as ulong
	return pcg_rotr_32(((state shr 18u) xor state) shr 27u, state shr 59u)
end function

function pcg_output_rxs_m_xs_8_8(byval state as ubyte) as ubyte
	dim word as ubyte = ((state shr ((state shr 6u) + 2u)) xor state) * 217u
	return (word shr 6u) xor word
end function

function pcg_output_rxs_m_xs_16_16(byval state as ushort) as ushort
	dim word as ushort = ((state shr ((state shr 13u) + 3u)) xor state) * 62169u
	return (word shr 11u) xor word
end function

function pcg_output_rxs_m_xs_32_32(byval state as ulong) as ulong
	dim word as ulong = ((state shr ((state shr 28u) + 4u)) xor state) * 277803737u
	return (word shr 22u) xor word
end function

function pcg_output_rxs_m_xs_64_64(byval state as ulongint) as ulongint
	dim word as ulongint = ((state shr ((state shr 59u) + 5u)) xor state) * 12605985483714917081ull
	return (word shr 43u) xor word
end function

function pcg_output_xsl_rr_64_32(byval state as ulongint) as ulong
	return pcg_rotr_32(culng(culng(state shr 32u) xor culng(state)), state shr 59u)
end function

function pcg_output_xsl_rr_rr_64_64(byval state as ulongint) as ulongint
	dim rot1 as ulong = culng(state shr 59u)
	dim high as ulong = culng(state shr 32u)
	dim low as ulong = culng(state)
	dim xored as ulong = high xor low
	dim newlow as ulong = pcg_rotr_32(xored, rot1)
	dim newhigh as ulong = pcg_rotr_32(high, newlow and 31u)
	return (culngint(newhigh) shl 32u) or newlow
end function

const PCG_DEFAULT_MULTIPLIER_8 = 141u
const PCG_DEFAULT_MULTIPLIER_16 = 12829u
const PCG_DEFAULT_MULTIPLIER_32 = 747796405u
const PCG_DEFAULT_MULTIPLIER_64 = 6364136223846793005ull
const PCG_DEFAULT_INCREMENT_8 = 77u
const PCG_DEFAULT_INCREMENT_16 = 47989u
const PCG_DEFAULT_INCREMENT_32 = 2891336453u
const PCG_DEFAULT_INCREMENT_64 = 1442695040888963407ull

type pcg_state_8
	state as ubyte
end type

type pcg_state_16
	state as ushort
end type

type pcg_state_32
	state as ulong
end type

type pcg_state_64
	state as ulongint
end type

type pcg_state_setseq_8
	state as ubyte
	inc as ubyte
end type

type pcg_state_setseq_16
	state as ushort
	inc as ushort
end type

type pcg_state_setseq_32
	state as ulong
	inc as ulong
end type

type pcg_state_setseq_64
	state as ulongint
	inc as ulongint
end type

declare function pcg_advance_lcg_8(byval state as ubyte, byval delta as ubyte, byval cur_mult as ubyte, byval cur_plus as ubyte) as ubyte
declare function pcg_advance_lcg_16(byval state as ushort, byval delta as ushort, byval cur_mult as ushort, byval cur_plus as ushort) as ushort
declare function pcg_advance_lcg_32(byval state as ulong, byval delta as ulong, byval cur_mult as ulong, byval cur_plus as ulong) as ulong
declare function pcg_advance_lcg_64(byval state as ulongint, byval delta as ulongint, byval cur_mult as ulongint, byval cur_plus as ulongint) as ulongint

sub pcg_oneseq_8_step_r(byval rng as pcg_state_8 ptr)
	rng->state = (rng->state * 141u) + 77u
end sub

sub pcg_oneseq_8_advance_r(byval rng as pcg_state_8 ptr, byval delta as ubyte)
	rng->state = pcg_advance_lcg_8(rng->state, delta, 141u, 77u)
end sub

sub pcg_mcg_8_step_r(byval rng as pcg_state_8 ptr)
	rng->state = rng->state * 141u
end sub

sub pcg_mcg_8_advance_r(byval rng as pcg_state_8 ptr, byval delta as ubyte)
	rng->state = pcg_advance_lcg_8(rng->state, delta, 141u, 0u)
end sub

sub pcg_unique_8_step_r(byval rng as pcg_state_8 ptr)
	rng->state = (rng->state * 141u) + cubyte(cint(rng) or 1u)
end sub

sub pcg_unique_8_advance_r(byval rng as pcg_state_8 ptr, byval delta as ubyte)
	rng->state = pcg_advance_lcg_8(rng->state, delta, 141u, cubyte(cint(rng) or 1u))
end sub

sub pcg_setseq_8_step_r(byval rng as pcg_state_setseq_8 ptr)
	rng->state = (rng->state * 141u) + rng->inc
end sub

sub pcg_setseq_8_advance_r(byval rng as pcg_state_setseq_8 ptr, byval delta as ubyte)
	rng->state = pcg_advance_lcg_8(rng->state, delta, 141u, rng->inc)
end sub

sub pcg_oneseq_16_step_r(byval rng as pcg_state_16 ptr)
	rng->state = (rng->state * 12829u) + 47989u
end sub

sub pcg_oneseq_16_advance_r(byval rng as pcg_state_16 ptr, byval delta as ushort)
	rng->state = pcg_advance_lcg_16(rng->state, delta, 12829u, 47989u)
end sub

sub pcg_mcg_16_step_r(byval rng as pcg_state_16 ptr)
	rng->state = rng->state * 12829u
end sub

sub pcg_mcg_16_advance_r(byval rng as pcg_state_16 ptr, byval delta as ushort)
	rng->state = pcg_advance_lcg_16(rng->state, delta, 12829u, 0u)
end sub

sub pcg_unique_16_step_r(byval rng as pcg_state_16 ptr)
	rng->state = (rng->state * 12829u) + cushort(cint(rng) or 1u)
end sub

sub pcg_unique_16_advance_r(byval rng as pcg_state_16 ptr, byval delta as ushort)
	rng->state = pcg_advance_lcg_16(rng->state, delta, 12829u, cushort(cint(rng) or 1u))
end sub

sub pcg_setseq_16_step_r(byval rng as pcg_state_setseq_16 ptr)
	rng->state = (rng->state * 12829u) + rng->inc
end sub

sub pcg_setseq_16_advance_r(byval rng as pcg_state_setseq_16 ptr, byval delta as ushort)
	rng->state = pcg_advance_lcg_16(rng->state, delta, 12829u, rng->inc)
end sub

sub pcg_oneseq_32_step_r(byval rng as pcg_state_32 ptr)
	rng->state = (rng->state * 747796405u) + 2891336453u
end sub

sub pcg_oneseq_32_advance_r(byval rng as pcg_state_32 ptr, byval delta as ulong)
	rng->state = pcg_advance_lcg_32(rng->state, delta, 747796405u, 2891336453u)
end sub

sub pcg_mcg_32_step_r(byval rng as pcg_state_32 ptr)
	rng->state = rng->state * 747796405u
end sub

sub pcg_mcg_32_advance_r(byval rng as pcg_state_32 ptr, byval delta as ulong)
	rng->state = pcg_advance_lcg_32(rng->state, delta, 747796405u, 0u)
end sub

sub pcg_unique_32_step_r(byval rng as pcg_state_32 ptr)
	rng->state = (rng->state * 747796405u) + culng(cint(rng) or 1u)
end sub

sub pcg_unique_32_advance_r(byval rng as pcg_state_32 ptr, byval delta as ulong)
	rng->state = pcg_advance_lcg_32(rng->state, delta, 747796405u, culng(cint(rng) or 1u))
end sub

sub pcg_setseq_32_step_r(byval rng as pcg_state_setseq_32 ptr)
	rng->state = (rng->state * 747796405u) + rng->inc
end sub

sub pcg_setseq_32_advance_r(byval rng as pcg_state_setseq_32 ptr, byval delta as ulong)
	rng->state = pcg_advance_lcg_32(rng->state, delta, 747796405u, rng->inc)
end sub

sub pcg_oneseq_64_step_r(byval rng as pcg_state_64 ptr)
	rng->state = (rng->state * 6364136223846793005ull) + 1442695040888963407ull
end sub

sub pcg_oneseq_64_advance_r(byval rng as pcg_state_64 ptr, byval delta as ulongint)
	rng->state = pcg_advance_lcg_64(rng->state, delta, 6364136223846793005ull, 1442695040888963407ull)
end sub

sub pcg_mcg_64_step_r(byval rng as pcg_state_64 ptr)
	rng->state = rng->state * 6364136223846793005ull
end sub

sub pcg_mcg_64_advance_r(byval rng as pcg_state_64 ptr, byval delta as ulongint)
	rng->state = pcg_advance_lcg_64(rng->state, delta, 6364136223846793005ull, 0u)
end sub

sub pcg_unique_64_step_r(byval rng as pcg_state_64 ptr)
	rng->state = (rng->state * 6364136223846793005ull) + culngint(cint(rng) or 1u)
end sub

sub pcg_unique_64_advance_r(byval rng as pcg_state_64 ptr, byval delta as ulongint)
	rng->state = pcg_advance_lcg_64(rng->state, delta, 6364136223846793005ull, culngint(cint(rng) or 1u))
end sub

sub pcg_setseq_64_step_r(byval rng as pcg_state_setseq_64 ptr)
	rng->state = (rng->state * 6364136223846793005ull) + rng->inc
end sub

sub pcg_setseq_64_advance_r(byval rng as pcg_state_setseq_64 ptr, byval delta as ulongint)
	rng->state = pcg_advance_lcg_64(rng->state, delta, 6364136223846793005ull, rng->inc)
end sub

sub pcg_oneseq_8_srandom_r(byval rng as pcg_state_8 ptr, byval initstate as ubyte)
	rng->state = 0u
	pcg_oneseq_8_step_r(rng)
	rng->state += initstate
	pcg_oneseq_8_step_r(rng)
end sub

sub pcg_mcg_8_srandom_r(byval rng as pcg_state_8 ptr, byval initstate as ubyte)
	rng->state = initstate or 1u
end sub

sub pcg_unique_8_srandom_r(byval rng as pcg_state_8 ptr, byval initstate as ubyte)
	rng->state = 0u
	pcg_unique_8_step_r(rng)
	rng->state += initstate
	pcg_unique_8_step_r(rng)
end sub

sub pcg_setseq_8_srandom_r(byval rng as pcg_state_setseq_8 ptr, byval initstate as ubyte, byval initseq as ubyte)
	rng->state = 0u
	rng->inc = (initseq shl 1u) or 1u
	pcg_setseq_8_step_r(rng)
	rng->state += initstate
	pcg_setseq_8_step_r(rng)
end sub

sub pcg_oneseq_16_srandom_r(byval rng as pcg_state_16 ptr, byval initstate as ushort)
	rng->state = 0u
	pcg_oneseq_16_step_r(rng)
	rng->state += initstate
	pcg_oneseq_16_step_r(rng)
end sub

sub pcg_mcg_16_srandom_r(byval rng as pcg_state_16 ptr, byval initstate as ushort)
	rng->state = initstate or 1u
end sub

sub pcg_unique_16_srandom_r(byval rng as pcg_state_16 ptr, byval initstate as ushort)
	rng->state = 0u
	pcg_unique_16_step_r(rng)
	rng->state += initstate
	pcg_unique_16_step_r(rng)
end sub

sub pcg_setseq_16_srandom_r(byval rng as pcg_state_setseq_16 ptr, byval initstate as ushort, byval initseq as ushort)
	rng->state = 0u
	rng->inc = (initseq shl 1u) or 1u
	pcg_setseq_16_step_r(rng)
	rng->state += initstate
	pcg_setseq_16_step_r(rng)
end sub

sub pcg_oneseq_32_srandom_r(byval rng as pcg_state_32 ptr, byval initstate as ulong)
	rng->state = 0u
	pcg_oneseq_32_step_r(rng)
	rng->state += initstate
	pcg_oneseq_32_step_r(rng)
end sub

sub pcg_mcg_32_srandom_r(byval rng as pcg_state_32 ptr, byval initstate as ulong)
	rng->state = initstate or 1u
end sub

sub pcg_unique_32_srandom_r(byval rng as pcg_state_32 ptr, byval initstate as ulong)
	rng->state = 0u
	pcg_unique_32_step_r(rng)
	rng->state += initstate
	pcg_unique_32_step_r(rng)
end sub

sub pcg_setseq_32_srandom_r(byval rng as pcg_state_setseq_32 ptr, byval initstate as ulong, byval initseq as ulong)
	rng->state = 0u
	rng->inc = (initseq shl 1u) or 1u
	pcg_setseq_32_step_r(rng)
	rng->state += initstate
	pcg_setseq_32_step_r(rng)
end sub

sub pcg_oneseq_64_srandom_r(byval rng as pcg_state_64 ptr, byval initstate as ulongint)
	rng->state = 0u
	pcg_oneseq_64_step_r(rng)
	rng->state += initstate
	pcg_oneseq_64_step_r(rng)
end sub

sub pcg_mcg_64_srandom_r(byval rng as pcg_state_64 ptr, byval initstate as ulongint)
	rng->state = initstate or 1u
end sub

sub pcg_unique_64_srandom_r(byval rng as pcg_state_64 ptr, byval initstate as ulongint)
	rng->state = 0u
	pcg_unique_64_step_r(rng)
	rng->state += initstate
	pcg_unique_64_step_r(rng)
end sub

sub pcg_setseq_64_srandom_r(byval rng as pcg_state_setseq_64 ptr, byval initstate as ulongint, byval initseq as ulongint)
	rng->state = 0u
	rng->inc = (initseq shl 1u) or 1u
	pcg_setseq_64_step_r(rng)
	rng->state += initstate
	pcg_setseq_64_step_r(rng)
end sub

function pcg_oneseq_16_xsh_rs_8_random_r(byval rng as pcg_state_16 ptr) as ubyte
	dim oldstate as ushort = rng->state
	pcg_oneseq_16_step_r(rng)
	return pcg_output_xsh_rs_16_8(oldstate)
end function

function pcg_oneseq_16_xsh_rs_8_boundedrand_r(byval rng as pcg_state_16 ptr, byval bound as ubyte) as ubyte
	dim threshold as ubyte = cubyte(-bound) mod bound
	do
		dim as ubyte r = pcg_oneseq_16_xsh_rs_8_random_r(rng)
		if (r >= threshold) then return r mod bound
	loop
end function

function pcg_oneseq_32_xsh_rs_16_random_r(byval rng as pcg_state_32 ptr) as ushort
	dim oldstate as ulong = rng->state
	pcg_oneseq_32_step_r(rng)
	return pcg_output_xsh_rs_32_16(oldstate)
end function

function pcg_oneseq_32_xsh_rs_16_boundedrand_r(byval rng as pcg_state_32 ptr, byval bound as ushort) as ushort
	dim threshold as ushort = cushort(-bound) mod bound
	do
		dim as ushort r = pcg_oneseq_32_xsh_rs_16_random_r(rng)
		if (r >= threshold) then return r mod bound
	loop
end function

function pcg_oneseq_64_xsh_rs_32_random_r(byval rng as pcg_state_64 ptr) as ulong
	dim oldstate as ulongint = rng->state
	pcg_oneseq_64_step_r(rng)
	return pcg_output_xsh_rs_64_32(oldstate)
end function

function pcg_oneseq_64_xsh_rs_32_boundedrand_r(byval rng as pcg_state_64 ptr, byval bound as ulong) as ulong
	dim threshold as ulong = (-bound) mod bound
	do
		dim as ulong r = pcg_oneseq_64_xsh_rs_32_random_r(rng)
		if (r >= threshold) then return r mod bound
	loop
end function

function pcg_unique_16_xsh_rs_8_random_r(byval rng as pcg_state_16 ptr) as ubyte
	dim oldstate as ushort = rng->state
	pcg_unique_16_step_r(rng)
	return pcg_output_xsh_rs_16_8(oldstate)
end function

function pcg_unique_16_xsh_rs_8_boundedrand_r(byval rng as pcg_state_16 ptr, byval bound as ubyte) as ubyte
	dim threshold as ubyte = cubyte(-bound) mod bound
	do
		dim as ubyte r = pcg_unique_16_xsh_rs_8_random_r(rng)
		if (r >= threshold) then return r mod bound
	loop
end function

function pcg_unique_32_xsh_rs_16_random_r(byval rng as pcg_state_32 ptr) as ushort
	dim oldstate as ulong = rng->state
	pcg_unique_32_step_r(rng)
	return pcg_output_xsh_rs_32_16(oldstate)
end function

function pcg_unique_32_xsh_rs_16_boundedrand_r(byval rng as pcg_state_32 ptr, byval bound as ushort) as ushort
	dim threshold as ushort = cushort(-bound) mod bound
	do
		dim as ushort r = pcg_unique_32_xsh_rs_16_random_r(rng)
		if (r >= threshold) then return r mod bound
	loop
end function

function pcg_unique_64_xsh_rs_32_random_r(byval rng as pcg_state_64 ptr) as ulong
	dim oldstate as ulongint = rng->state
	pcg_unique_64_step_r(rng)
	return pcg_output_xsh_rs_64_32(oldstate)
end function

function pcg_unique_64_xsh_rs_32_boundedrand_r(byval rng as pcg_state_64 ptr, byval bound as ulong) as ulong
	dim threshold as ulong = (-bound) mod bound
	do
		dim as ulong r = pcg_unique_64_xsh_rs_32_random_r(rng)
		if (r >= threshold) then return r mod bound
	loop
end function

function pcg_setseq_16_xsh_rs_8_random_r(byval rng as pcg_state_setseq_16 ptr) as ubyte
	dim oldstate as ushort = rng->state
	pcg_setseq_16_step_r(rng)
	return pcg_output_xsh_rs_16_8(oldstate)
end function

function pcg_setseq_16_xsh_rs_8_boundedrand_r(byval rng as pcg_state_setseq_16 ptr, byval bound as ubyte) as ubyte
	dim threshold as ubyte = cubyte(-bound) mod bound
	do
		dim as ubyte r = pcg_setseq_16_xsh_rs_8_random_r(rng)
		if (r >= threshold) then return r mod bound
	loop
end function

function pcg_setseq_32_xsh_rs_16_random_r(byval rng as pcg_state_setseq_32 ptr) as ushort
	dim oldstate as ulong = rng->state
	pcg_setseq_32_step_r(rng)
	return pcg_output_xsh_rs_32_16(oldstate)
end function

function pcg_setseq_32_xsh_rs_16_boundedrand_r(byval rng as pcg_state_setseq_32 ptr, byval bound as ushort) as ushort
	dim threshold as ushort = cushort(-bound) mod bound
	do
		dim as ushort r = pcg_setseq_32_xsh_rs_16_random_r(rng)
		if (r >= threshold) then return r mod bound
	loop
end function

function pcg_setseq_64_xsh_rs_32_random_r(byval rng as pcg_state_setseq_64 ptr) as ulong
	dim oldstate as ulongint = rng->state
	pcg_setseq_64_step_r(rng)
	return pcg_output_xsh_rs_64_32(oldstate)
end function

function pcg_setseq_64_xsh_rs_32_boundedrand_r(byval rng as pcg_state_setseq_64 ptr, byval bound as ulong) as ulong
	dim threshold as ulong = (-bound) mod bound
	do
		dim as ulong r = pcg_setseq_64_xsh_rs_32_random_r(rng)
		if (r >= threshold) then return r mod bound
	loop
end function

function pcg_mcg_16_xsh_rs_8_random_r(byval rng as pcg_state_16 ptr) as ubyte
	dim oldstate as ushort = rng->state
	pcg_mcg_16_step_r(rng)
	return pcg_output_xsh_rs_16_8(oldstate)
end function

function pcg_mcg_16_xsh_rs_8_boundedrand_r(byval rng as pcg_state_16 ptr, byval bound as ubyte) as ubyte
	dim threshold as ubyte = cubyte(-bound) mod bound
	do
		dim as ubyte r = pcg_mcg_16_xsh_rs_8_random_r(rng)
		if (r >= threshold) then return r mod bound
	loop
end function

function pcg_mcg_32_xsh_rs_16_random_r(byval rng as pcg_state_32 ptr) as ushort
	dim oldstate as ulong = rng->state
	pcg_mcg_32_step_r(rng)
	return pcg_output_xsh_rs_32_16(oldstate)
end function

function pcg_mcg_32_xsh_rs_16_boundedrand_r(byval rng as pcg_state_32 ptr, byval bound as ushort) as ushort
	dim threshold as ushort = cushort(-bound) mod bound
	do
		dim as ushort r = pcg_mcg_32_xsh_rs_16_random_r(rng)
		if (r >= threshold) then return r mod bound
	loop
end function

function pcg_mcg_64_xsh_rs_32_random_r(byval rng as pcg_state_64 ptr) as ulong
	dim oldstate as ulongint = rng->state
	pcg_mcg_64_step_r(rng)
	return pcg_output_xsh_rs_64_32(oldstate)
end function

function pcg_mcg_64_xsh_rs_32_boundedrand_r(byval rng as pcg_state_64 ptr, byval bound as ulong) as ulong
	dim threshold as ulong = (-bound) mod bound
	do
		dim as ulong r = pcg_mcg_64_xsh_rs_32_random_r(rng)
		if (r >= threshold) then return r mod bound
	loop
end function

function pcg_oneseq_16_xsh_rr_8_random_r(byval rng as pcg_state_16 ptr) as ubyte
	dim oldstate as ushort = rng->state
	pcg_oneseq_16_step_r(rng)
	return pcg_output_xsh_rr_16_8(oldstate)
end function

function pcg_oneseq_16_xsh_rr_8_boundedrand_r(byval rng as pcg_state_16 ptr, byval bound as ubyte) as ubyte
	dim threshold as ubyte = cubyte(-bound) mod bound
	do
		dim as ubyte r = pcg_oneseq_16_xsh_rr_8_random_r(rng)
		if (r >= threshold) then return r mod bound
	loop
end function

function pcg_oneseq_32_xsh_rr_16_random_r(byval rng as pcg_state_32 ptr) as ushort
	dim oldstate as ulong = rng->state
	pcg_oneseq_32_step_r(rng)
	return pcg_output_xsh_rr_32_16(oldstate)
end function

function pcg_oneseq_32_xsh_rr_16_boundedrand_r(byval rng as pcg_state_32 ptr, byval bound as ushort) as ushort
	dim threshold as ushort = cushort(-bound) mod bound
	do
		dim as ushort r = pcg_oneseq_32_xsh_rr_16_random_r(rng)
		if (r >= threshold) then return r mod bound
	loop
end function

function pcg_oneseq_64_xsh_rr_32_random_r(byval rng as pcg_state_64 ptr) as ulong
	dim oldstate as ulongint = rng->state
	pcg_oneseq_64_step_r(rng)
	return pcg_output_xsh_rr_64_32(oldstate)
end function

function pcg_oneseq_64_xsh_rr_32_boundedrand_r(byval rng as pcg_state_64 ptr, byval bound as ulong) as ulong
	dim threshold as ulong = (-bound) mod bound
	do
		dim as ulong r = pcg_oneseq_64_xsh_rr_32_random_r(rng)
		if (r >= threshold) then return r mod bound
	loop
end function

function pcg_unique_16_xsh_rr_8_random_r(byval rng as pcg_state_16 ptr) as ubyte
	dim oldstate as ushort = rng->state
	pcg_unique_16_step_r(rng)
	return pcg_output_xsh_rr_16_8(oldstate)
end function

function pcg_unique_16_xsh_rr_8_boundedrand_r(byval rng as pcg_state_16 ptr, byval bound as ubyte) as ubyte
	dim threshold as ubyte = cubyte(-bound) mod bound
	do
		dim as ubyte r = pcg_unique_16_xsh_rr_8_random_r(rng)
		if (r >= threshold) then return r mod bound
	loop
end function

function pcg_unique_32_xsh_rr_16_random_r(byval rng as pcg_state_32 ptr) as ushort
	dim oldstate as ulong = rng->state
	pcg_unique_32_step_r(rng)
	return pcg_output_xsh_rr_32_16(oldstate)
end function

function pcg_unique_32_xsh_rr_16_boundedrand_r(byval rng as pcg_state_32 ptr, byval bound as ushort) as ushort
	dim threshold as ushort = cushort(-bound) mod bound
	do
		dim as ushort r = pcg_unique_32_xsh_rr_16_random_r(rng)
		if (r >= threshold) then return r mod bound
	loop
end function

function pcg_unique_64_xsh_rr_32_random_r(byval rng as pcg_state_64 ptr) as ulong
	dim oldstate as ulongint = rng->state
	pcg_unique_64_step_r(rng)
	return pcg_output_xsh_rr_64_32(oldstate)
end function

function pcg_unique_64_xsh_rr_32_boundedrand_r(byval rng as pcg_state_64 ptr, byval bound as ulong) as ulong
	dim threshold as ulong = (-bound) mod bound
	do
		dim as ulong r = pcg_unique_64_xsh_rr_32_random_r(rng)
		if (r >= threshold) then return r mod bound
	loop
end function

function pcg_setseq_16_xsh_rr_8_random_r(byval rng as pcg_state_setseq_16 ptr) as ubyte
	dim oldstate as ushort = rng->state
	pcg_setseq_16_step_r(rng)
	return pcg_output_xsh_rr_16_8(oldstate)
end function

function pcg_setseq_16_xsh_rr_8_boundedrand_r(byval rng as pcg_state_setseq_16 ptr, byval bound as ubyte) as ubyte
	dim threshold as ubyte = cubyte(-bound) mod bound
	do
		dim as ubyte r = pcg_setseq_16_xsh_rr_8_random_r(rng)
		if (r >= threshold) then return r mod bound
	loop
end function

function pcg_setseq_32_xsh_rr_16_random_r(byval rng as pcg_state_setseq_32 ptr) as ushort
	dim oldstate as ulong = rng->state
	pcg_setseq_32_step_r(rng)
	return pcg_output_xsh_rr_32_16(oldstate)
end function

function pcg_setseq_32_xsh_rr_16_boundedrand_r(byval rng as pcg_state_setseq_32 ptr, byval bound as ushort) as ushort
	dim threshold as ushort = cushort(-bound) mod bound
	do
		dim as ushort r = pcg_setseq_32_xsh_rr_16_random_r(rng)
		if (r >= threshold) then return r mod bound
	loop
end function

function pcg_setseq_64_xsh_rr_32_random_r(byval rng as pcg_state_setseq_64 ptr) as ulong
	dim oldstate as ulongint = rng->state
	pcg_setseq_64_step_r(rng)
	return pcg_output_xsh_rr_64_32(oldstate)
end function

function pcg_setseq_64_xsh_rr_32_boundedrand_r(byval rng as pcg_state_setseq_64 ptr, byval bound as ulong) as ulong
	dim threshold as ulong = (-bound) mod bound
	do
		dim as ulong r = pcg_setseq_64_xsh_rr_32_random_r(rng)
		if (r >= threshold) then return r mod bound
	loop
end function

function pcg_mcg_16_xsh_rr_8_random_r(byval rng as pcg_state_16 ptr) as ubyte
	dim oldstate as ushort = rng->state
	pcg_mcg_16_step_r(rng)
	return pcg_output_xsh_rr_16_8(oldstate)
end function

function pcg_mcg_16_xsh_rr_8_boundedrand_r(byval rng as pcg_state_16 ptr, byval bound as ubyte) as ubyte
	dim threshold as ubyte = cubyte(-bound) mod bound
	do
		dim as ubyte r = pcg_mcg_16_xsh_rr_8_random_r(rng)
		if (r >= threshold) then return r mod bound
	loop
end function

function pcg_mcg_32_xsh_rr_16_random_r(byval rng as pcg_state_32 ptr) as ushort
	dim oldstate as ulong = rng->state
	pcg_mcg_32_step_r(rng)
	return pcg_output_xsh_rr_32_16(oldstate)
end function

function pcg_mcg_32_xsh_rr_16_boundedrand_r(byval rng as pcg_state_32 ptr, byval bound as ushort) as ushort
	dim threshold as ushort = cushort(-bound) mod bound
	do
		dim as ushort r = pcg_mcg_32_xsh_rr_16_random_r(rng)
		if (r >= threshold) then return r mod bound
	loop
end function

function pcg_mcg_64_xsh_rr_32_random_r(byval rng as pcg_state_64 ptr) as ulong
	dim oldstate as ulongint = rng->state
	pcg_mcg_64_step_r(rng)
	return pcg_output_xsh_rr_64_32(oldstate)
end function

function pcg_mcg_64_xsh_rr_32_boundedrand_r(byval rng as pcg_state_64 ptr, byval bound as ulong) as ulong
	dim threshold as ulong = (-bound) mod bound
	do
		dim as ulong r = pcg_mcg_64_xsh_rr_32_random_r(rng)
		if (r >= threshold) then return r mod bound
	loop
end function

function pcg_oneseq_8_rxs_m_xs_8_random_r(byval rng as pcg_state_8 ptr) as ubyte
	dim oldstate as ubyte = rng->state
	pcg_oneseq_8_step_r(rng)
	return pcg_output_rxs_m_xs_8_8(oldstate)
end function

function pcg_oneseq_8_rxs_m_xs_8_boundedrand_r(byval rng as pcg_state_8 ptr, byval bound as ubyte) as ubyte
	dim threshold as ubyte = cubyte(-bound) mod bound
	do
		dim as ubyte r = pcg_oneseq_8_rxs_m_xs_8_random_r(rng)
		if (r >= threshold) then return r mod bound
	loop
end function

function pcg_oneseq_16_rxs_m_xs_16_random_r(byval rng as pcg_state_16 ptr) as ushort
	dim oldstate as ushort = rng->state
	pcg_oneseq_16_step_r(rng)
	return pcg_output_rxs_m_xs_16_16(oldstate)
end function

function pcg_oneseq_16_rxs_m_xs_16_boundedrand_r(byval rng as pcg_state_16 ptr, byval bound as ushort) as ushort
	dim threshold as ushort = cushort(-bound) mod bound
	do
		dim as ushort r = pcg_oneseq_16_rxs_m_xs_16_random_r(rng)
		if (r >= threshold) then return r mod bound
	loop
end function

function pcg_oneseq_32_rxs_m_xs_32_random_r(byval rng as pcg_state_32 ptr) as ulong
	dim oldstate as ulong = rng->state
	pcg_oneseq_32_step_r(rng)
	return pcg_output_rxs_m_xs_32_32(oldstate)
end function

function pcg_oneseq_32_rxs_m_xs_32_boundedrand_r(byval rng as pcg_state_32 ptr, byval bound as ulong) as ulong
	dim threshold as ulong = (-bound) mod bound
	do
		dim as ulong r = pcg_oneseq_32_rxs_m_xs_32_random_r(rng)
		if (r >= threshold) then return r mod bound
	loop
end function

function pcg_oneseq_64_rxs_m_xs_64_random_r(byval rng as pcg_state_64 ptr) as ulongint
	dim oldstate as ulongint = rng->state
	pcg_oneseq_64_step_r(rng)
	return pcg_output_rxs_m_xs_64_64(oldstate)
end function

function pcg_oneseq_64_rxs_m_xs_64_boundedrand_r(byval rng as pcg_state_64 ptr, byval bound as ulongint) as ulongint
	dim threshold as ulongint = (-bound) mod bound
	do
		dim as ulongint r = pcg_oneseq_64_rxs_m_xs_64_random_r(rng)
		if (r >= threshold) then return r mod bound
	loop
end function

function pcg_unique_16_rxs_m_xs_16_random_r(byval rng as pcg_state_16 ptr) as ushort
	dim oldstate as ushort = rng->state
	pcg_unique_16_step_r(rng)
	return pcg_output_rxs_m_xs_16_16(oldstate)
end function

function pcg_unique_16_rxs_m_xs_16_boundedrand_r(byval rng as pcg_state_16 ptr, byval bound as ushort) as ushort
	dim threshold as ushort = cushort(-bound) mod bound
	do
		dim as ushort r = pcg_unique_16_rxs_m_xs_16_random_r(rng)
		if (r >= threshold) then return r mod bound
	loop
end function

function pcg_unique_32_rxs_m_xs_32_random_r(byval rng as pcg_state_32 ptr) as ulong
	dim oldstate as ulong = rng->state
	pcg_unique_32_step_r(rng)
	return pcg_output_rxs_m_xs_32_32(oldstate)
end function

function pcg_unique_32_rxs_m_xs_32_boundedrand_r(byval rng as pcg_state_32 ptr, byval bound as ulong) as ulong
	dim threshold as ulong = (-bound) mod bound
	do
		dim as ulong r = pcg_unique_32_rxs_m_xs_32_random_r(rng)
		if (r >= threshold) then return r mod bound
	loop
end function

function pcg_unique_64_rxs_m_xs_64_random_r(byval rng as pcg_state_64 ptr) as ulongint
	dim oldstate as ulongint = rng->state
	pcg_unique_64_step_r(rng)
	return pcg_output_rxs_m_xs_64_64(oldstate)
end function

function pcg_unique_64_rxs_m_xs_64_boundedrand_r(byval rng as pcg_state_64 ptr, byval bound as ulongint) as ulongint
	dim threshold as ulongint = (-bound) mod bound
	do
		dim as ulongint r = pcg_unique_64_rxs_m_xs_64_random_r(rng)
		if (r >= threshold) then return r mod bound
	loop
end function

function pcg_setseq_8_rxs_m_xs_8_random_r(byval rng as pcg_state_setseq_8 ptr) as ubyte
	dim oldstate as ubyte = rng->state
	pcg_setseq_8_step_r(rng)
	return pcg_output_rxs_m_xs_8_8(oldstate)
end function

function pcg_setseq_8_rxs_m_xs_8_boundedrand_r(byval rng as pcg_state_setseq_8 ptr, byval bound as ubyte) as ubyte
	dim threshold as ubyte = cubyte(-bound) mod bound
	do
		dim as ubyte r = pcg_setseq_8_rxs_m_xs_8_random_r(rng)
		if (r >= threshold) then return r mod bound
	loop
end function

function pcg_setseq_16_rxs_m_xs_16_random_r(byval rng as pcg_state_setseq_16 ptr) as ushort
	dim oldstate as ushort = rng->state
	pcg_setseq_16_step_r(rng)
	return pcg_output_rxs_m_xs_16_16(oldstate)
end function

function pcg_setseq_16_rxs_m_xs_16_boundedrand_r(byval rng as pcg_state_setseq_16 ptr, byval bound as ushort) as ushort
	dim threshold as ushort = cushort(-bound) mod bound
	do
		dim as ushort r = pcg_setseq_16_rxs_m_xs_16_random_r(rng)
		if (r >= threshold) then return r mod bound
	loop
end function

function pcg_setseq_32_rxs_m_xs_32_random_r(byval rng as pcg_state_setseq_32 ptr) as ulong
	dim oldstate as ulong = rng->state
	pcg_setseq_32_step_r(rng)
	return pcg_output_rxs_m_xs_32_32(oldstate)
end function

function pcg_setseq_32_rxs_m_xs_32_boundedrand_r(byval rng as pcg_state_setseq_32 ptr, byval bound as ulong) as ulong
	dim threshold as ulong = (-bound) mod bound
	do
		dim as ulong r = pcg_setseq_32_rxs_m_xs_32_random_r(rng)
		if (r >= threshold) then return r mod bound
	loop
end function

function pcg_setseq_64_rxs_m_xs_64_random_r(byval rng as pcg_state_setseq_64 ptr) as ulongint
	dim oldstate as ulongint = rng->state
	pcg_setseq_64_step_r(rng)
	return pcg_output_rxs_m_xs_64_64(oldstate)
end function

function pcg_setseq_64_rxs_m_xs_64_boundedrand_r(byval rng as pcg_state_setseq_64 ptr, byval bound as ulongint) as ulongint
	dim threshold as ulongint = (-bound) mod bound
	do
		dim as ulongint r = pcg_setseq_64_rxs_m_xs_64_random_r(rng)
		if (r >= threshold) then return r mod bound
	loop
end function

function pcg_oneseq_64_xsl_rr_32_random_r(byval rng as pcg_state_64 ptr) as ulong
	dim oldstate as ulongint = rng->state
	pcg_oneseq_64_step_r(rng)
	return pcg_output_xsl_rr_64_32(oldstate)
end function

function pcg_oneseq_64_xsl_rr_32_boundedrand_r(byval rng as pcg_state_64 ptr, byval bound as ulong) as ulong
	dim threshold as ulong = (-bound) mod bound
	do
		dim as ulong r = pcg_oneseq_64_xsl_rr_32_random_r(rng)
		if (r >= threshold) then return r mod bound
	loop
end function

function pcg_unique_64_xsl_rr_32_random_r(byval rng as pcg_state_64 ptr) as ulong
	dim oldstate as ulongint = rng->state
	pcg_unique_64_step_r(rng)
	return pcg_output_xsl_rr_64_32(oldstate)
end function

function pcg_unique_64_xsl_rr_32_boundedrand_r(byval rng as pcg_state_64 ptr, byval bound as ulong) as ulong
	dim threshold as ulong = (-bound) mod bound
	do
		dim as ulong r = pcg_unique_64_xsl_rr_32_random_r(rng)
		if (r >= threshold) then return r mod bound
	loop
end function

function pcg_setseq_64_xsl_rr_32_random_r(byval rng as pcg_state_setseq_64 ptr) as ulong
	dim oldstate as ulongint = rng->state
	pcg_setseq_64_step_r(rng)
	return pcg_output_xsl_rr_64_32(oldstate)
end function

function pcg_setseq_64_xsl_rr_32_boundedrand_r(byval rng as pcg_state_setseq_64 ptr, byval bound as ulong) as ulong
	dim threshold as ulong = (-bound) mod bound
	do
		dim as ulong r = pcg_setseq_64_xsl_rr_32_random_r(rng)
		if (r >= threshold) then return r mod bound
	loop
end function

function pcg_mcg_64_xsl_rr_32_random_r(byval rng as pcg_state_64 ptr) as ulong
	dim oldstate as ulongint = rng->state
	pcg_mcg_64_step_r(rng)
	return pcg_output_xsl_rr_64_32(oldstate)
end function

function pcg_mcg_64_xsl_rr_32_boundedrand_r(byval rng as pcg_state_64 ptr, byval bound as ulong) as ulong
	dim threshold as ulong = (-bound) mod bound
	do
		dim as ulong r = pcg_mcg_64_xsl_rr_32_random_r(rng)
		if (r >= threshold) then return r mod bound
	loop
end function

function pcg_oneseq_64_xsl_rr_rr_64_random_r(byval rng as pcg_state_64 ptr) as ulongint
	dim oldstate as ulongint = rng->state
	pcg_oneseq_64_step_r(rng)
	return pcg_output_xsl_rr_rr_64_64(oldstate)
end function

function pcg_oneseq_64_xsl_rr_rr_64_boundedrand_r(byval rng as pcg_state_64 ptr, byval bound as ulongint) as ulongint
	dim threshold as ulongint = (-bound) mod bound
	do
		dim as ulongint r = pcg_oneseq_64_xsl_rr_rr_64_random_r(rng)
		if (r >= threshold) then return r mod bound
	loop
end function

function pcg_unique_64_xsl_rr_rr_64_random_r(byval rng as pcg_state_64 ptr) as ulongint
	dim oldstate as ulongint = rng->state
	pcg_unique_64_step_r(rng)
	return pcg_output_xsl_rr_rr_64_64(oldstate)
end function

function pcg_unique_64_xsl_rr_rr_64_boundedrand_r(byval rng as pcg_state_64 ptr, byval bound as ulongint) as ulongint
	dim threshold as ulongint = (-bound) mod bound
	do
		dim as ulongint r = pcg_unique_64_xsl_rr_rr_64_random_r(rng)
		if (r >= threshold) then return r mod bound
	loop
end function

function pcg_setseq_64_xsl_rr_rr_64_random_r(byval rng as pcg_state_setseq_64 ptr) as ulongint
	dim oldstate as ulongint = rng->state
	pcg_setseq_64_step_r(rng)
	return pcg_output_xsl_rr_rr_64_64(oldstate)
end function

function pcg_setseq_64_xsl_rr_rr_64_boundedrand_r(byval rng as pcg_state_setseq_64 ptr, byval bound as ulongint) as ulongint
	dim threshold as ulongint = (-bound) mod bound
	do
		dim as ulongint r = pcg_setseq_64_xsl_rr_rr_64_random_r(rng)
		if (r >= threshold) then return r mod bound
	loop
end function

type pcg32_random_t as pcg_state_setseq_64
type pcg32s_random_t as pcg_state_64
type pcg32u_random_t as pcg_state_64
type pcg32f_random_t as pcg_state_64

declare function pcg32_random_r alias "pcg_setseq_64_xsh_rr_32_random_r"(byval rng as pcg_state_setseq_64 ptr) as ulong
declare function pcg32s_random_r alias "pcg_oneseq_64_xsh_rr_32_random_r"(byval rng as pcg_state_64 ptr) as ulong
declare function pcg32u_random_r alias "pcg_unique_64_xsh_rr_32_random_r"(byval rng as pcg_state_64 ptr) as ulong
declare function pcg32f_random_r alias "pcg_mcg_64_xsh_rs_32_random_r"(byval rng as pcg_state_64 ptr) as ulong
declare function pcg32_boundedrand_r alias "pcg_setseq_64_xsh_rr_32_boundedrand_r"(byval rng as pcg_state_setseq_64 ptr, byval bound as ulong) as ulong
declare function pcg32s_boundedrand_r alias "pcg_oneseq_64_xsh_rr_32_boundedrand_r"(byval rng as pcg_state_64 ptr, byval bound as ulong) as ulong
declare function pcg32u_boundedrand_r alias "pcg_unique_64_xsh_rr_32_boundedrand_r"(byval rng as pcg_state_64 ptr, byval bound as ulong) as ulong
declare function pcg32f_boundedrand_r alias "pcg_mcg_64_xsh_rs_32_boundedrand_r"(byval rng as pcg_state_64 ptr, byval bound as ulong) as ulong
declare sub pcg32_srandom_r alias "pcg_setseq_64_srandom_r"(byval rng as pcg_state_setseq_64 ptr, byval initstate as ulongint, byval initseq as ulongint)
declare sub pcg32s_srandom_r alias "pcg_oneseq_64_srandom_r"(byval rng as pcg_state_64 ptr, byval initstate as ulongint)
declare sub pcg32u_srandom_r alias "pcg_unique_64_srandom_r"(byval rng as pcg_state_64 ptr, byval initstate as ulongint)
declare sub pcg32f_srandom_r alias "pcg_mcg_64_srandom_r"(byval rng as pcg_state_64 ptr, byval initstate as ulongint)
declare sub pcg32_advance_r alias "pcg_setseq_64_advance_r"(byval rng as pcg_state_setseq_64 ptr, byval delta as ulongint)
declare sub pcg32s_advance_r alias "pcg_oneseq_64_advance_r"(byval rng as pcg_state_64 ptr, byval delta as ulongint)
declare sub pcg32u_advance_r alias "pcg_unique_64_advance_r"(byval rng as pcg_state_64 ptr, byval delta as ulongint)
declare sub pcg32f_advance_r alias "pcg_mcg_64_advance_r"(byval rng as pcg_state_64 ptr, byval delta as ulongint)

type pcg8si_random_t as pcg_state_8
type pcg16si_random_t as pcg_state_16
type pcg32si_random_t as pcg_state_32
type pcg64si_random_t as pcg_state_64

declare function pcg8si_random_r alias "pcg_oneseq_8_rxs_m_xs_8_random_r"(byval rng as pcg_state_8 ptr) as ubyte
declare function pcg16si_random_r alias "pcg_oneseq_16_rxs_m_xs_16_random_r"(byval rng as pcg_state_16 ptr) as ushort
declare function pcg32si_random_r alias "pcg_oneseq_32_rxs_m_xs_32_random_r"(byval rng as pcg_state_32 ptr) as ulong
declare function pcg64si_random_r alias "pcg_oneseq_64_rxs_m_xs_64_random_r"(byval rng as pcg_state_64 ptr) as ulongint
declare function pcg8si_boundedrand_r alias "pcg_oneseq_8_rxs_m_xs_8_boundedrand_r"(byval rng as pcg_state_8 ptr, byval bound as ubyte) as ubyte
declare function pcg16si_boundedrand_r alias "pcg_oneseq_16_rxs_m_xs_16_boundedrand_r"(byval rng as pcg_state_16 ptr, byval bound as ushort) as ushort
declare function pcg32si_boundedrand_r alias "pcg_oneseq_32_rxs_m_xs_32_boundedrand_r"(byval rng as pcg_state_32 ptr, byval bound as ulong) as ulong
declare function pcg64si_boundedrand_r alias "pcg_oneseq_64_rxs_m_xs_64_boundedrand_r"(byval rng as pcg_state_64 ptr, byval bound as ulongint) as ulongint
declare sub pcg8si_srandom_r alias "pcg_oneseq_8_srandom_r"(byval rng as pcg_state_8 ptr, byval initstate as ubyte)
declare sub pcg16si_srandom_r alias "pcg_oneseq_16_srandom_r"(byval rng as pcg_state_16 ptr, byval initstate as ushort)
declare sub pcg32si_srandom_r alias "pcg_oneseq_32_srandom_r"(byval rng as pcg_state_32 ptr, byval initstate as ulong)
declare sub pcg64si_srandom_r alias "pcg_oneseq_64_srandom_r"(byval rng as pcg_state_64 ptr, byval initstate as ulongint)
declare sub pcg8si_advance_r alias "pcg_oneseq_8_advance_r"(byval rng as pcg_state_8 ptr, byval delta as ubyte)
declare sub pcg16si_advance_r alias "pcg_oneseq_16_advance_r"(byval rng as pcg_state_16 ptr, byval delta as ushort)
declare sub pcg32si_advance_r alias "pcg_oneseq_32_advance_r"(byval rng as pcg_state_32 ptr, byval delta as ulong)
declare sub pcg64si_advance_r alias "pcg_oneseq_64_advance_r"(byval rng as pcg_state_64 ptr, byval delta as ulongint)

type pcg8i_random_t as pcg_state_setseq_8
type pcg16i_random_t as pcg_state_setseq_16
type pcg32i_random_t as pcg_state_setseq_32
type pcg64i_random_t as pcg_state_setseq_64

declare function pcg8i_random_r alias "pcg_setseq_8_rxs_m_xs_8_random_r"(byval rng as pcg_state_setseq_8 ptr) as ubyte
declare function pcg16i_random_r alias "pcg_setseq_16_rxs_m_xs_16_random_r"(byval rng as pcg_state_setseq_16 ptr) as ushort
declare function pcg32i_random_r alias "pcg_setseq_32_rxs_m_xs_32_random_r"(byval rng as pcg_state_setseq_32 ptr) as ulong
declare function pcg64i_random_r alias "pcg_setseq_64_rxs_m_xs_64_random_r"(byval rng as pcg_state_setseq_64 ptr) as ulongint
declare function pcg8i_boundedrand_r alias "pcg_setseq_8_rxs_m_xs_8_boundedrand_r"(byval rng as pcg_state_setseq_8 ptr, byval bound as ubyte) as ubyte
declare function pcg16i_boundedrand_r alias "pcg_setseq_16_rxs_m_xs_16_boundedrand_r"(byval rng as pcg_state_setseq_16 ptr, byval bound as ushort) as ushort
declare function pcg32i_boundedrand_r alias "pcg_setseq_32_rxs_m_xs_32_boundedrand_r"(byval rng as pcg_state_setseq_32 ptr, byval bound as ulong) as ulong
declare function pcg64i_boundedrand_r alias "pcg_setseq_64_rxs_m_xs_64_boundedrand_r"(byval rng as pcg_state_setseq_64 ptr, byval bound as ulongint) as ulongint
declare sub pcg8i_srandom_r alias "pcg_setseq_8_srandom_r"(byval rng as pcg_state_setseq_8 ptr, byval initstate as ubyte, byval initseq as ubyte)
declare sub pcg16i_srandom_r alias "pcg_setseq_16_srandom_r"(byval rng as pcg_state_setseq_16 ptr, byval initstate as ushort, byval initseq as ushort)
declare sub pcg32i_srandom_r alias "pcg_setseq_32_srandom_r"(byval rng as pcg_state_setseq_32 ptr, byval initstate as ulong, byval initseq as ulong)
declare sub pcg64i_srandom_r alias "pcg_setseq_64_srandom_r"(byval rng as pcg_state_setseq_64 ptr, byval initstate as ulongint, byval initseq as ulongint)
declare sub pcg8i_advance_r alias "pcg_setseq_8_advance_r"(byval rng as pcg_state_setseq_8 ptr, byval delta as ubyte)
declare sub pcg16i_advance_r alias "pcg_setseq_16_advance_r"(byval rng as pcg_state_setseq_16 ptr, byval delta as ushort)
declare sub pcg32i_advance_r alias "pcg_setseq_32_advance_r"(byval rng as pcg_state_setseq_32 ptr, byval delta as ulong)
declare sub pcg64i_advance_r alias "pcg_setseq_64_advance_r"(byval rng as pcg_state_setseq_64 ptr, byval delta as ulongint)
declare function pcg32_random() as ulong
declare function pcg32_boundedrand(byval bound as ulong) as ulong
declare sub pcg32_srandom(byval seed as ulongint, byval seq as ulongint)
declare sub pcg32_advance(byval delta as ulongint)

#define PCG_STATE_SETSEQ_8_INITIALIZER (&h9bu, &hdbu)
#define PCG_STATE_SETSEQ_16_INITIALIZER (&he39bu, &h5bdbu)
#define PCG_STATE_SETSEQ_32_INITIALIZER (&hec02d89bu, &h94b95bdbu)
#define PCG_STATE_SETSEQ_64_INITIALIZER (&h853c49e6748fea9bull, &hda3e39cb94b95bdbull)

#define PCG32_INITIALIZER PCG_STATE_SETSEQ_64_INITIALIZER
#define PCG32U_INITIALIZER PCG_STATE_UNIQUE_64_INITIALIZER
#define PCG32S_INITIALIZER PCG_STATE_ONESEQ_64_INITIALIZER
#define PCG32F_INITIALIZER PCG_STATE_MCG_64_INITIALIZER

end extern
pcg_advance.bas

Code: Select all

/'
 * PCG Random Number Generation for C.
 *
 * Copyright 2014 Melissa O'Neill <oneill@pcg-random.org>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * For additional information about the PCG random number generation scheme,
 * including its license and other licensing options, visit
 *
 *       http://www.pcg-random.org
 '/

/'
 * This code is derived from the canonical C++ PCG implementation, which
 * has many additional features and is preferable if you can use C++ in
 * your project.
 *
 * Repetative C code is derived using C preprocessor metaprogramming
 * techniques.
 '/

 'translated to FreeBASIC using fbfrog https://github.com/dkl/fbfrog
 
#pragma once

#include once "pcg_variants.bi"

/' Multi-step advance functions (jump-ahead, jump-back)
 *
 * The method used here is based on Brown, "Random Number Generation
 * with Arbitrary Stride,", Transactions of the American Nuclear
 * Society (Nov. 1994).  The algorithm is very similar to fast
 * exponentiation.
 *
 * Even though delta is an unsigned integer, we can pass a
 * signed integer to go backwards, it just goes "the long way round".
 '/

extern "C"

function pcg_advance_lcg_8(byval state as ubyte, byval delta as ubyte, byval cur_mult as ubyte, byval cur_plus as ubyte) as ubyte
	dim acc_mult as ubyte = 1u
	dim acc_plus as ubyte = 0u
	while delta > 0
		if delta and 1 then
			acc_mult *= cur_mult
			acc_plus = (acc_plus * cur_mult) + cur_plus
		end if
		cur_plus = (cur_mult + 1) * cur_plus
		cur_mult *= cur_mult
		delta /= 2
	wend
	return (acc_mult * state) + acc_plus
end function

function pcg_advance_lcg_16(byval state as ushort, byval delta as ushort, byval cur_mult as ushort, byval cur_plus as ushort) as ushort
	dim acc_mult as ushort = 1u
	dim acc_plus as ushort = 0u
	while delta > 0
		if delta and 1 then
			acc_mult *= cur_mult
			acc_plus = (acc_plus * cur_mult) + cur_plus
		end if
		cur_plus = (cur_mult + 1) * cur_plus
		cur_mult *= cur_mult
		delta /= 2
	wend
	return (acc_mult * state) + acc_plus
end function

function pcg_advance_lcg_32(byval state as ulong, byval delta as ulong, byval cur_mult as ulong, byval cur_plus as ulong) as ulong
	dim acc_mult as ulong = 1u
	dim acc_plus as ulong = 0u
	while delta > 0
		if delta and 1 then
			acc_mult *= cur_mult
			acc_plus = (acc_plus * cur_mult) + cur_plus
		end if
		cur_plus = (cur_mult + 1) * cur_plus
		cur_mult *= cur_mult
		delta /= 2
	wend
	return (acc_mult * state) + acc_plus
end function

function pcg_advance_lcg_64(byval state as ulongint, byval delta as ulongint, byval cur_mult as ulongint, byval cur_plus as ulongint) as ulongint
	dim acc_mult as ulongint = 1u
	dim acc_plus as ulongint = 0u
	while delta > 0
		if delta and 1 then
			acc_mult *= cur_mult
			acc_plus = (acc_plus * cur_mult) + cur_plus
		end if
		cur_plus = (cur_mult + 1) * cur_plus
		cur_mult *= cur_mult
		delta /= 2
	wend
	return (acc_mult * state) + acc_plus
end function

end extern
srvaldez
Posts: 3373
Joined: Sep 25, 2005 21:54

Re: Has anyone ported the PCG PRNG to FreeBASIC

Post by srvaldez »

small test
note that the function pcg32_advance_r does not work as in the C version, the function is declared as

Code: Select all

declare sub pcg32_advance_r alias "pcg_setseq_64_advance_r"(byval rng as pcg_state_setseq_64 ptr, byval delta as ulongint)
but in the example a negative value is passed to delta which works in C but not in FB
<edit> in case you did't know, the "print Again:" code is supposed to print the same numbers as the previous output just above"

Code: Select all


#include once "pcg-advance.bas"

dim rounds as long = 5
dim as pcg32_random_t rng

pcg_setseq_64_srandom_r(@rng, 42u, 54u)

print "pcg32_random_r:"
print "      -  result:      32-bit unsigned int (uint32_t)"
print "      -  period:      2^64   (* 2^63 streams)"
print "      -  state type:  pcg32_random_t (";sizeof(pcg32_random_t);" bytes)"
print "      -  output func: XSH-RR"
print

For round As Integer = 1 To rounds
	print "Round "; round
	print "  32bit: ";
	For i As Integer = 0 To 5
		print "0x";hex(pcg32_random_r(@rng),8);" ";
	next
	print
	'pcg32_advance_r(@rng, -6) does not work, replace #if 0 with #if 1 to test
	#if 0
		print "  Again: ";
		pcg32_advance_r(@rng, -6)
		For i As Integer = 0 To 5
			print "0x";hex(pcg32_random_r(@rng),8);" ";
		next
		print
	#endif
	print "  Coins: ";
	For i As Integer = 0 To 64
		print iif(pcg32_boundedrand_r(@rng, 2) ,"H" , "T");
	next
	print
	print"  Rolls:";
	For i As Integer = 0 To 32
		print cast(long,pcg32_boundedrand_r(@rng, 6) + 1);
	next
	print
next
Last edited by srvaldez on Jun 06, 2017 14:41, edited 2 times in total.
cbruce
Posts: 163
Joined: Sep 12, 2007 19:13
Location: Dallas, Texas

Re: Has anyone ported the PCG PRNG to FreeBASIC

Post by cbruce »

Wow! Thanks, srvaldez!

I'll look at it tonight.

CBruce
deltarho[1859]
Posts: 4292
Joined: Jan 02, 2017 0:34
Location: UK
Contact:

Re: Has anyone ported the PCG PRNG to FreeBASIC

Post by deltarho[1859] »

@srvaldez

Hi, when you created pcg_variants.bi did you edit out all the 128 bits stuff? I couldn't find any 128 bit functions and also noticed that pcg_variants.h has about twice as many lines as pcg_variants.bi.

Cheers
Post Reply