Giter VIP home page Giter VIP logo

pcg-cpp's People

Contributors

adam4130 avatar bhickey avatar crepererum avatar felixonmars avatar imneme avatar ismail avatar merwaaan avatar neumann-a avatar o11c avatar ph4r05 avatar shawnw avatar tido64 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

pcg-cpp's Issues

Cache misses with ccache when pcg-cpp is included, possibly due to __DATE__ and __TIME__

Minimal example:

#include <pcg_random.hpp>

int main() { return 0; }

Compiling twice gives a cache miss the second time:

$ ccache g++ -c -Ipcg-cpp-0.98.1/include pcg-example.cpp 
$ ccache -s
cache directory                     /home/vedranmiletic/.ccache
primary config                      /home/vedranmiletic/.ccache/ccache.conf
secondary config      (readonly)    /etc/ccache.conf
stats updated                       Thu Feb  6 11:39:36 2020
cache hit (direct)                     0
cache hit (preprocessed)               0
cache miss                             1
cache hit rate                      0.00 %
cleanups performed                     0
files in cache                         1
cache size                           4.1 kB
max cache size                       5.0 GB
$ ccache g++ -c -Ipcg-cpp-0.98.1/include pcg-example.cpp 
$ ccache -s
cache directory                     /home/vedranmiletic/.ccache
primary config                      /home/vedranmiletic/.ccache/ccache.conf
secondary config      (readonly)    /etc/ccache.conf
stats updated                       Thu Feb  6 11:39:45 2020
cache hit (direct)                     0
cache hit (preprocessed)               0
cache miss                             2
cache hit rate                      0.00 %
cleanups performed                     0
files in cache                         2
cache size                           8.2 kB
max cache size                       5.0 GB

The debug log file shows a different hash each time:

[2020-02-06T11:39:35.920164 14858] === CCACHE 3.7.7 STARTED =========================================
[2020-02-06T11:39:35.920164 14858] Config: (default) base_dir = 
[2020-02-06T11:39:35.920164 14858] Config: (default) cache_dir = /home/vedranmiletic/.ccache
[2020-02-06T11:39:35.920164 14858] Config: (default) cache_dir_levels = 2
[2020-02-06T11:39:35.920164 14858] Config: (default) compiler = 
[2020-02-06T11:39:35.920164 14858] Config: (default) compiler_check = mtime
[2020-02-06T11:39:35.920164 14858] Config: (default) compression = false
[2020-02-06T11:39:35.920164 14858] Config: (default) compression_level = 6
[2020-02-06T11:39:35.920164 14858] Config: (default) cpp_extension = 
[2020-02-06T11:39:35.920164 14858] Config: (default) debug = false
[2020-02-06T11:39:35.920164 14858] Config: (default) depend_mode = false
[2020-02-06T11:39:35.920164 14858] Config: (default) direct_mode = true
[2020-02-06T11:39:35.920164 14858] Config: (default) disable = false
[2020-02-06T11:39:35.920164 14858] Config: (default) extra_files_to_hash = 
[2020-02-06T11:39:35.920164 14858] Config: (default) hard_link = false
[2020-02-06T11:39:35.920164 14858] Config: (default) hash_dir = true
[2020-02-06T11:39:35.920164 14858] Config: (default) ignore_headers_in_manifest = 
[2020-02-06T11:39:35.920164 14858] Config: (default) keep_comments_cpp = false
[2020-02-06T11:39:35.920164 14858] Config: (default) limit_multiple = 0.8
[2020-02-06T11:39:35.920164 14858] Config: (environment) log_file = /tmp/cache-minimal.debug
[2020-02-06T11:39:35.920164 14858] Config: (default) max_files = 0
[2020-02-06T11:39:35.920164 14858] Config: (default) max_size = 5.0G
[2020-02-06T11:39:35.920164 14858] Config: (default) path = 
[2020-02-06T11:39:35.920164 14858] Config: (default) pch_external_checksum = false
[2020-02-06T11:39:35.920164 14858] Config: (default) prefix_command = 
[2020-02-06T11:39:35.920164 14858] Config: (default) prefix_command_cpp = 
[2020-02-06T11:39:35.920164 14858] Config: (default) read_only = false
[2020-02-06T11:39:35.920164 14858] Config: (default) read_only_direct = false
[2020-02-06T11:39:35.920164 14858] Config: (default) recache = false
[2020-02-06T11:39:35.920164 14858] Config: (default) run_second_cpp = true
[2020-02-06T11:39:35.920164 14858] Config: (default) sloppiness = 
[2020-02-06T11:39:35.920164 14858] Config: (default) stats = true
[2020-02-06T11:39:35.920164 14858] Config: (default) temporary_dir = 
[2020-02-06T11:39:35.920164 14858] Config: (default) umask = 
[2020-02-06T11:39:35.920372 14858] Command line: ccache g++ -c -Ipcg-cpp-0.98.1/include pcg-example.cpp
[2020-02-06T11:39:35.920397 14858] Hostname: hephaestus
[2020-02-06T11:39:35.920420 14858] Working directory: /home/vedranmiletic
[2020-02-06T11:39:35.920478 14858] Source file: pcg-example.cpp
[2020-02-06T11:39:35.920488 14858] Object file: pcg-example.o
[2020-02-06T11:39:35.920510 14858] Trying direct lookup
[2020-02-06T11:39:35.920559 14858] Looking for object file hash in /home/vedranmiletic/.ccache/0/d/82650d7ebf4afae8251b89938339df-280.manifest
[2020-02-06T11:39:35.920575 14858] No such manifest file
[2020-02-06T11:39:35.920584 14858] Did not find object file hash in manifest
[2020-02-06T11:39:35.921046 14858] Running preprocessor
[2020-02-06T11:39:35.921070 14858] Executing /usr/bin/g++ -Ipcg-cpp-0.98.1/include -E pcg-example.cpp
[2020-02-06T11:39:36.015075 14858] Found __DATE__ in pcg-cpp-0.98.1/include/pcg_extras.hpp
[2020-02-06T11:39:36.015109 14858] Found __TIME__ in pcg-cpp-0.98.1/include/pcg_extras.hpp
[2020-02-06T11:39:36.015115 14858] Disabling direct mode
[2020-02-06T11:39:36.015660 14858] Got object file hash from preprocessor
[2020-02-06T11:39:36.015688 14858] Object file /home/vedranmiletic/.ccache/1/8/f93581b7617650b562067786ae323b-1161376.o not in cache
[2020-02-06T11:39:36.015700 14858] Running real compiler
[2020-02-06T11:39:36.015816 14858] Executing /usr/bin/g++ -Ipcg-cpp-0.98.1/include -c -o pcg-example.o pcg-example.cpp
[2020-02-06T11:39:36.535746 14858] Unlink /home/vedranmiletic/.ccache/1/8/f93581b7617650b562067786ae323b-1161376.o.tmp.stdout.hephaestus.14858.mXEZFI
[2020-02-06T11:39:36.535816 14858] Unlink /home/vedranmiletic/.ccache/1/8/f93581b7617650b562067786ae323b-1161376.o.tmp.stderr.hephaestus.14858.o0IuNH
[2020-02-06T11:39:36.535879 14858] Copying pcg-example.o to /home/vedranmiletic/.ccache/1/8/f93581b7617650b562067786ae323b-1161376.o via /home/vedranmiletic/.ccache/1/8/f93581b7617650b562067786ae323b-1161376.o.hephaestus.14858.DV8O0G (uncompressed)
[2020-02-06T11:39:36.535946 14858] Stored in cache: pcg-example.o -> /home/vedranmiletic/.ccache/1/8/f93581b7617650b562067786ae323b-1161376.o (copied)
[2020-02-06T11:39:36.536325 14858] Result: cache miss
[2020-02-06T11:39:36.536348 14858] Acquired lock /home/vedranmiletic/.ccache/1/stats.lock
[2020-02-06T11:39:36.536397 14858] Releasing lock /home/vedranmiletic/.ccache/1/stats.lock
[2020-02-06T11:39:36.536402 14858] Unlink /home/vedranmiletic/.ccache/1/stats.lock
[2020-02-06T11:39:40.335718 14864] === CCACHE 3.7.7 STARTED =========================================
[2020-02-06T11:39:44.999691 14865] === CCACHE 3.7.7 STARTED =========================================
[2020-02-06T11:39:44.999691 14865] Config: (default) base_dir = 
[2020-02-06T11:39:44.999691 14865] Config: (default) cache_dir = /home/vedranmiletic/.ccache
[2020-02-06T11:39:44.999691 14865] Config: (default) cache_dir_levels = 2
[2020-02-06T11:39:44.999691 14865] Config: (default) compiler = 
[2020-02-06T11:39:44.999691 14865] Config: (default) compiler_check = mtime
[2020-02-06T11:39:44.999691 14865] Config: (default) compression = false
[2020-02-06T11:39:44.999691 14865] Config: (default) compression_level = 6
[2020-02-06T11:39:44.999691 14865] Config: (default) cpp_extension = 
[2020-02-06T11:39:44.999691 14865] Config: (default) debug = false
[2020-02-06T11:39:44.999691 14865] Config: (default) depend_mode = false
[2020-02-06T11:39:44.999691 14865] Config: (default) direct_mode = true
[2020-02-06T11:39:44.999691 14865] Config: (default) disable = false
[2020-02-06T11:39:44.999691 14865] Config: (default) extra_files_to_hash = 
[2020-02-06T11:39:44.999691 14865] Config: (default) hard_link = false
[2020-02-06T11:39:44.999691 14865] Config: (default) hash_dir = true
[2020-02-06T11:39:44.999691 14865] Config: (default) ignore_headers_in_manifest = 
[2020-02-06T11:39:44.999691 14865] Config: (default) keep_comments_cpp = false
[2020-02-06T11:39:44.999691 14865] Config: (default) limit_multiple = 0.8
[2020-02-06T11:39:44.999691 14865] Config: (environment) log_file = /tmp/cache-minimal.debug
[2020-02-06T11:39:44.999691 14865] Config: (default) max_files = 0
[2020-02-06T11:39:44.999691 14865] Config: (/home/vedranmiletic/.ccache/ccache.conf) max_size = 5.0G
[2020-02-06T11:39:44.999691 14865] Config: (default) path = 
[2020-02-06T11:39:44.999691 14865] Config: (default) pch_external_checksum = false
[2020-02-06T11:39:44.999691 14865] Config: (default) prefix_command = 
[2020-02-06T11:39:44.999691 14865] Config: (default) prefix_command_cpp = 
[2020-02-06T11:39:44.999691 14865] Config: (default) read_only = false
[2020-02-06T11:39:44.999691 14865] Config: (default) read_only_direct = false
[2020-02-06T11:39:44.999691 14865] Config: (default) recache = false
[2020-02-06T11:39:44.999691 14865] Config: (default) run_second_cpp = true
[2020-02-06T11:39:44.999691 14865] Config: (default) sloppiness = 
[2020-02-06T11:39:44.999691 14865] Config: (default) stats = true
[2020-02-06T11:39:44.999691 14865] Config: (default) temporary_dir = 
[2020-02-06T11:39:44.999691 14865] Config: (default) umask = 
[2020-02-06T11:39:44.999905 14865] Command line: ccache g++ -c -Ipcg-cpp-0.98.1/include pcg-example.cpp
[2020-02-06T11:39:44.999925 14865] Hostname: hephaestus
[2020-02-06T11:39:44.999947 14865] Working directory: /home/vedranmiletic
[2020-02-06T11:39:44.999995 14865] Source file: pcg-example.cpp
[2020-02-06T11:39:45.000004 14865] Object file: pcg-example.o
[2020-02-06T11:39:45.000023 14865] Trying direct lookup
[2020-02-06T11:39:45.000062 14865] Looking for object file hash in /home/vedranmiletic/.ccache/0/d/82650d7ebf4afae8251b89938339df-280.manifest
[2020-02-06T11:39:45.000082 14865] No such manifest file
[2020-02-06T11:39:45.000090 14865] Did not find object file hash in manifest
[2020-02-06T11:39:45.000210 14865] Running preprocessor
[2020-02-06T11:39:45.000218 14865] Executing /usr/bin/g++ -Ipcg-cpp-0.98.1/include -E pcg-example.cpp
[2020-02-06T11:39:45.097064 14865] Found __DATE__ in pcg-cpp-0.98.1/include/pcg_extras.hpp
[2020-02-06T11:39:45.097099 14865] Found __TIME__ in pcg-cpp-0.98.1/include/pcg_extras.hpp
[2020-02-06T11:39:45.097105 14865] Disabling direct mode
[2020-02-06T11:39:45.097646 14865] Got object file hash from preprocessor
[2020-02-06T11:39:45.097670 14865] Object file /home/vedranmiletic/.ccache/f/1/9c68493f22eafad27987912faa2c81-1161376.o not in cache
[2020-02-06T11:39:45.097682 14865] Running real compiler
[2020-02-06T11:39:45.097803 14865] Executing /usr/bin/g++ -Ipcg-cpp-0.98.1/include -c -o pcg-example.o pcg-example.cpp
[2020-02-06T11:39:45.604277 14865] Unlink /home/vedranmiletic/.ccache/f/1/9c68493f22eafad27987912faa2c81-1161376.o.tmp.stdout.hephaestus.14865.YQFOyc
[2020-02-06T11:39:45.604348 14865] Unlink /home/vedranmiletic/.ccache/f/1/9c68493f22eafad27987912faa2c81-1161376.o.tmp.stderr.hephaestus.14865.la6gad
[2020-02-06T11:39:45.604427 14865] Copying pcg-example.o to /home/vedranmiletic/.ccache/f/1/9c68493f22eafad27987912faa2c81-1161376.o via /home/vedranmiletic/.ccache/f/1/9c68493f22eafad27987912faa2c81-1161376.o.hephaestus.14865.qo8Mbf (uncompressed)
[2020-02-06T11:39:45.604516 14865] Stored in cache: pcg-example.o -> /home/vedranmiletic/.ccache/f/1/9c68493f22eafad27987912faa2c81-1161376.o (copied)
[2020-02-06T11:39:45.605002 14865] Result: cache miss
[2020-02-06T11:39:45.605028 14865] Acquired lock /home/vedranmiletic/.ccache/f/stats.lock
[2020-02-06T11:39:45.605092 14865] Releasing lock /home/vedranmiletic/.ccache/f/stats.lock
[2020-02-06T11:39:45.605099 14865] Unlink /home/vedranmiletic/.ccache/f/stats.lock
[2020-02-06T11:39:46.647536 14871] === CCACHE 3.7.7 STARTED =========================================

Results from separate seed() and set_stream() differ from two-argument seed()

When I seed and set the stream separately I get a different result than if I do that with a single call. Is that expected?

Example code:

#include <iostream>
#include "pcg_random.hpp"

int main(void) {
  pcg64 rng;
  rng.seed(20240409);
  std::cout << rng << std::endl;
  rng.set_stream(90404202);
  std::cout << rng << std::endl;
  rng.seed(20240409, 90404202);
  std::cout << rng << std::endl;
  return 0;
}

Output:

47026247687942121848144207491837523525 117397592171526113268558934119004209487 232695090976826000214660542883178056279
47026247687942121848144207491837523525 180808405 232695090976826000214660542883178056279
47026247687942121848144207491837523525 180808405 324486960932314774260885781527366674683

I would have expected the second and third line to be identical. While that is true for the stream indicator (second number), this is not the case for the RNG state (third number).

Restore from state

My simulations rely on a great number of random numbers. However, I want to be able uniquely restore a some given point. To this end I think it would be a good idea to store the current state (it would not have to run through the entire sequence starting from some seed). However, it seems that the state was not made public. I can image that that might have been on purpose. So: Am I overlooking something? If not, would you be open to making a public API to read/restore a state?

Typedef Bug

pcg_random seems to have a bug at lines 1703-1704, namely,
these lines

typedef pcg_engines::ext_setseq_xsh_rr_64_32<6,16,true>     pcg32_k2;
typedef pcg_engines::ext_oneseq_xsh_rs_64_32<6,32,true>     pcg32_k2_fast;

should read

typedef pcg_engines::ext_setseq_xsh_rr_64_32<1,16,true>     pcg32_k2;
typedef pcg_engines::ext_oneseq_xsh_rs_64_32<1,32,true>     pcg32_k2_fast;

If the intention was to create a typedef for a 2-dimensionally equidistributed generator.

Inconsistent generator naming

While investigating the source code, I've found several generators with the inconsistent names.

In file pcg_random.hpp on line 1724

typedef pcg_engines::ext_setseq_xsh_rr_64_32<6,16,true>     pcg32_k64;
typedef pcg_engines::ext_mcg_xsh_rs_64_32<6,32,true>        pcg32_k64_oneseq;
typedef pcg_engines::ext_oneseq_xsh_rs_64_32<6,32,true>     pcg32_k64_fast;

pcg32_k64_oneseq is based on the mcg, and pcg32_k64_fast is based on the oneseq generator.

But on line 1732

typedef pcg_engines::ext_setseq_xsl_rr_128_64<5,16,true>    pcg64_k32;
typedef pcg_engines::ext_oneseq_xsl_rr_128_64<5,128,true>   pcg64_k32_oneseq;
typedef pcg_engines::ext_mcg_xsl_rr_128_64<5,128,true>      pcg64_k32_fast;

pcg64_k32_oneseq is based on the oneseq generator, and pcg64_k32_fast is based on the mcg.

After further investigation, I discovered the following.
The base generator are declared as follows (line 1686)

typedef pcg_engines::setseq_xsh_rr_64_32        pcg32;
typedef pcg_engines::oneseq_xsh_rr_64_32        pcg32_oneseq;
typedef pcg_engines::unique_xsh_rr_64_32        pcg32_unique;
typedef pcg_engines::mcg_xsh_rs_64_32           pcg32_fast;

Where pcg32_oneseq is based on oneseq generator and pcg32_fast is based on mcg generator.
But multiple extended fast generators (pcg32_k2_fast, pcg32_k64_fast, pcg32_k1024_fast, pcg32_c1024_fast, pcg64_k1024_fast, pcg64_c1024_fast, pcg32_k16384_fast) are based on oneseq generator while other fast generators (pcg32_c64_fast, pcg64_k32_fast, pcg64_c32_fast) are based on mcg.

Pointer Truncation warnings when using MSVC

When using the _unique versions of pcg_random I get warnings when compiling with MSVC (Visual Studio 2017):

pcg_random.hpp(206): warning C4302: 'reinterpret_cast': truncation from 'const pcg_detail::unique_stream *' to 'unsigned long'

pcg_random.hpp(206): warning C4311: 'reinterpret_cast': pointer truncation from 'const pcg_detail::unique_stream *' to 'unsigned long'

The issue is on line 206 in pcg_random.hpp:

return itype(reinterpret_cast<unsigned long>(this) | 1);

Pointer truncation is probably no issue seeing as how it's used in pcg_random, so to turn off the warnings I'm disabling the warnings before including the pcg_random header:

#pragma warning(push)
#pragma warning(disable:4302)
#pragma warning(disable:4311)
#include <pcg_random.hpp>
#pragma warning(pop)

Perhaps a fix in your header would be better for the future.

Have you considered designing a PCG without the constraint that it has to be "challenging" to predict?

Firstly, you should know that I am not "trolling" you, and that I'm writing this because I appreciate your work designing PRNGs (and a lot of your blog posts and similar have been valuable and enjoyable to me). I understand that trivial predictability seems to be your pet peeve. However, as far as I understand, "challenging" predictability comes at some cost for either statistical quality or speed, and you yourself acknowledge that

Algorithmic-complexity attacks aren't a major risk for our algorithms most of the time

So why not give users who don't need "challenging" predictability the option of using a PRNG that is tailored purely for excellent statistical quality, speed and small state size?

Furthermore, and I hope that writing this is a good idea, but I believe that your reasoning for making "challenging" predictability a goal at all is flawed, and your claims regarding the predictability of PCGs are deceptive.

The problem is that if someone needs to worry about algorithmic complexity attacks, PCG is not the right choice for them anyway, rather something like Randen seems to be a proper choice. The reason is that, as you yourself acknowledge, the PCG family is not cryptographically strong, i.e. the "challenging" predictability can not be relied on. In other words, trivial vs challenging predictability isn't a useful distinction. I'm pretty sure you already know that, unsurprisingly, a relatively efficient attack has already been described. Another thing that should be noted is that in your reasoning about the threat model you suppose that an attacker may only choose the easiest target; while in the real world determined and resourceful attackers with specific targets do exist. Such an attacker may even, for example, implement custom hardware to help with efficiently breaking the PRNG at hand.

To reiterate my point, one either worries about attacks on the PRNG, in which case they can use Randen or a CSPRNG; or they don't and they need good statistical quality and probably also speed, in which case they may use a PCG.

I hope you can appreciate my honesty, are not offended and your desire for making a trivially predictable PCG increases.

Missing "expected" file

Looks like "expected" file containing the correct test results is missing:

[/havana/t/pcg/pcg-cpp]> make test
cd test-high; make
make[1]: Entering directory '/havana/t/pcg/pcg-cpp/test-high'
make[1]: Nothing to be done for 'all'.
make[1]: Leaving directory '/havana/t/pcg/pcg-cpp/test-high'
cd sample; make
make[1]: Entering directory '/havana/t/pcg/pcg-cpp/sample'
make[1]: Nothing to be done for 'all'.
make[1]: Leaving directory '/havana/t/pcg/pcg-cpp/sample'
cd test-high; make test
make[1]: Entering directory '/havana/t/pcg/pcg-cpp/test-high'
sh run-tests.sh
Performing a quick sanity check...
diff: expected: No such file or directory

diff: expected: No such file or directory
ERROR: Some tests failed.
make[1]: Leaving directory '/havana/t/pcg/pcg-cpp/test-high'

pcg64_c32 not usable

When trying to use pgc with a fully updated visual studio 2019 (version 16.7.5) I can
use generators as

	// Make a random number engine 
	pcg64 rng(1234);

without any problem, but when trying out pcg64_c32 instead of pcg64 I see compile errors (I am using c++17 language mode but it doesn't matter). It complains about line 1246 in pcg_random.hpp. For some reason the table_mask constexpr seems to not evaluate to a constant.

image

are pcg distributions reproducible

I recently struggled getting the new C++11 random number distributions to work in my algorithm only to find that the distributions generate different sequences when run on different platforms (VS 2015 on windows gcc 5 on ubuntu 16). In my googling for an alternative, I came across PCG, which looks promising. Specifically, I am using std::uniform_int_distribution<unsigned int> with a fixed seed for std::mt19937 . Will using PCG give me a reproducible sequence across ALL (most or even some) implementations?

Thanks,
Phil

Another MSVC compiler problem with pcg32 vs pcg64

Hi there!

I'm trying to use pcg64 in my program (first question: should I? When is pcg32 enough?)
When I do that I get the following compiler error with MSVC 19:

 error C2678: binary '<<': no operator found which takes a left-hand operand of type 'dest_t' (or there is no acceptable conversion) [C:\Users\Eike\Documents\grazer\build\src\Auxillary\Mathfunctions\mathfunctions.vcxproj]

 message : could be 'std::ostream &pcg_extras::operator <<(std::ostream &,uint8_t)' [found using argument-dependent lookup] [C:\Users\Eike\Documents\grazer\build\src\Auxillary\Mathfunctions\mathfunctions.vcxproj]
C:\Users\Eike\Documents\grazer\pcg\include\pcg_uint128.hpp(774,3): message : or       'pcg_extras::uint_x4<uint32_t,uint64_t> pcg_extras::operator <<<uint32_t,uint64_t>(const pcg_extras::uint_x4<uint32_t,uint64_t> &,const pcg_extras::bitcount_t)' [C:\Users\Eike\Documents\grazer\build\src\Auxillary\Mathfunctions\mathfunctions.vcxproj]
C:\Users\Eike\Documents\grazer\pcg\include\pcg_extras.hpp(425,1): message : or       'built-in C++ operator<<(UIntX2, UIntX2)' [C:\Users\Eike\Documents\grazer\build\src\Auxillary\Mathfunctions\mathfunctions.vcxproj]
          with
          [
              UIntX2=uint64_t
          ]

Note that the line numbers are probably wrong, because I clang-formated the sourcecode inadvertedly.

The same compiles without issue with pcg32. I guess I would have to supply an additional overload for << but I don't know how. Can someone help me?

MCG initialisation

I notice that the C++ code forces two bits high:

    engine(itype state = itype(0xcafef00dd15ea5e5ULL))
        : state_(this->is_mcg ? state|state_type(3U)
                              : bump(state + this->increment()))
    {
        // Nothing else to do.
    }

while the C code only forces one bit high:

inline void pcg_mcg_128_srandom_r(struct pcg_state_128* rng, pcg128_t initstate)
{
    rng->state = initstate | 1u;
}

Is there a reason these two are not equivalent?

I also notice that this variant is missing from the C++ test suite (although since it is only ever initialised to 42 in the suite, no one would notice this difference).

Can I store pcg32 as a class member?

I'd like to store my rng as a class member, as I have many methods that require it in my class. Something like:

class MyClass {
  pcg32 rng;
  // ...
  MyClass() : rng(pcg_extras::seed_seq_from<std::random_device>{}) {}
}

leads to segfaults when I use, e.g. std::uniform_real_distribution with rng. I believe this is due to the fact that somewhere it tries to access a reference to the seed sequence, that was built in-place in the constructor! I'm not sure how to go around this... as you know, you can't store an std::random_device, because its copy constructor is deleted. Can you provide a minimal example of how to use pcg "in oo-programming", or at least with classes and not just within main()?

Can't compile under MSVC2017

Hello,

the keyword _forceinline is not recognized by MSVC2017, which I guess is when you disable the Microsoft specific extension to the ISO C++. Have to be replaced with double underscore prefix instead i.e. __forceinline.

#define PCG_ALWAYS_INLINE _forceinline

Best regards.

At least in pcg32 first number of stream is always the same

The apparent reason is that when the engines output_previous template parameter is true, the previous internal state generated with the previous increment is returned first. This is at least unintuitive, and I'd even consider it a bug. Maybe set_stream should bump the internal state when output_previous is true (though I have to admit I don't really see the purpose of outputting the previous state in any case, but I'm sure I'm just missing something?).

Example code:

pcg32 generator1{};
pcg32 generator2(generator1);
generator1.set_stream(0xF00BA8);
generator2.set_stream(0xBAA8F00); 
// Uncomment to "Pump out" the stored internal state and make the assert pass
// generator1();
// generator2();
assert(generator1() != generator2()); // FAILS!

Also, if I use stream numbers 1 and 2, or for example 73, 146 or such simply generated seeds, the first two numbers generated are identical, but I suppose that's what's described shortly in https://www.pcg-random.org/posts/critiquing-pcg-streams.html in the STOP PRESS parentheses statement. I'd be more than happy to read a slightly longer discussion of how to safely initialize a number of streams, initially just given consecutive integers as instance numbers?

Seed securely by default

If seed (or, for extended generators data - it's fine to omit stream) is omitted for any given constructor/seed call, the sanest default is to seed from /dev/urandom by default. Only allow an insecurely-initialized RNG if some singleton enum is explicitly passed in place of the relevant argument.

This is a breaking change, but appropriate use of macros can let people hide if if they really need to. But chances are if it breaks anything, it was a bug in their code.

Note that the testsuite does rely on selfinit since it never passes data. But I don't like that. (I've replaced TWO_ARG_INIT with ARG_INIT_COUNT which can take any value from 0 to 3 (or conceptually more) and passes exactly that many arguments to RNG's constructor)

computing 53-bits random number

I need to be able to send largest possible integer to a web application. This number will be passed back and forth to server.

template <typename T = pcg64_k1024_fast, typename R = int64_t> R computePCG() {
    static thread_local T rng{pcg_extras::seed_seq_from<std::random_device>()};
    return rng();
}

Using above code of PCG, On server I'm able to generate either 32-bit or 64-bit, However Json using 64 bit IEEE 754 - Only provides 53 bits precision for integer. So my options are:

  1. I can use full 64 bit integer, but this will require code change at client application to be able to handle 64 bit change. Would really like to avoid this approach.

OR

  1. Generate 64 bit number using PCG and right shift 11 bits ( To generate 53 bits), Is this safe approach to generate random numbers. Will this number be random enough atleast upto 53 bits.

OR

  1. Is there a better approach to specify number of byes required for random generation. Similar to javascript crypto function:
    https://nodejs.org/api/crypto.html#crypto_crypto_randombytes_size_callback

Thank you for your time and looking into it.

Error Uploading PCG_cpp on visual studio 2015

Hello,

I have attempted to use the pcg number generator on visual studio but constantly faced with this error in this part of code.

#ifndef PCG_LITTLE_ENDIAN
#if defined(BYTE_ORDER)
#if BYTE_ORDER == ORDER_LITTLE_ENDIAN
#define PCG_LITTLE_ENDIAN 1
#elif BYTE_ORDER == ORDER_BIG_ENDIAN
#define PCG_LITTLE_ENDIAN 0
#else
#error BYTE_ORDER does not match a standard endian, pick a side
#endif
#elif LITTLE_ENDIAN || _LITTLE_ENDIAN
#define PCG_LITTLE_ENDIAN 1
#elif BIG_ENDIAN || _BIG_ENDIAN
#define PCG_LITTLE_ENDIAN 0
#elif __x86_64 || x86_64 || __i386 || i386
#define PCG_LITTLE_ENDIAN 1
#elif powerpc || POWERPC || ppc || PPC
|| m68k || mc68000
#define PCG_LITTLE_ENDIAN 0
#else
#error Unable to determine target endianness // error in this directive
#endif
#endif

The error is shown in this directive comment.

Make engine constexpr under c++14 and higher

Would you be interested in a PR that makes most functions of this library constexpr? I haven't really investigated this yet, but it seems that one could just slab a CONSTEXPR_IN_ CPP14 -style macro in front of most functions.
The only tricky bit would be to make sure that this macro is restrictive enough that it doesn't accidentally add constexpr for a compiler / c++ version combination that nominally supports e.g. c++14 constexpr, but actually has an incomplete implementation which then results in a compilation error even when the function isn't used in a constexpr context.

Question regarding usage

Hi there!

I'm trying to use PCG for some hopefully cross-platform code. As I don't know where my code will be compiled and used, I would like to make sure that random numbers are as random-like as possible.

Therefore I thought, that seeding pcg32 and the like with both a std::random_device and

static_cast<std::random_device::result_type>(
            std::chrono::high_resolution_clock::now()
                .time_since_epoch()
                .count())

but I have no idea how to do that. In addition I didn't gather from https://www.pcg-random.org/ how to seed the generators with deterministic data e.g. in order to make reproducible runs.
Could someone point me in the right direction? Even more appreciated would be some sample code like:

// add time here?
pcg_extras::seed_seq_from<std::random_device> seed_source;

/// add current time here?
pcg64 rng(seed_source);

which uses both std::random_device and the current time in high resolution for entropy or even better with the additional option to provided entropy by the user.

I'm not sure, this is the right place for this, so feel free to send me elsewhere.

Recommended usage with random seeds and streams

First off: apologies if this is the wrong place to ask a usage-related question, I couldn't find any indication of where to ask for help on the PCG website.

The scenario is fairly simple: I am using multiple pcg32 instances (at least 1000, up to a million), each one of which is constructed with a different seed and an incremented stream value (1, 2, 3, etc.). The seeds are different between instances; for the sake of discussion, they can be assumed to be independently and uniformly sampled from the entire range of 64-bit integers.

Upon reviewing my code, someone mentioned that the use of different seeds was unnecessary in the presence of different streams. This sounded reasonable but some reading of the PCG blog made me wonder:

it may be easier than I had thought to make “nearby” streams with correlated initializations like a constant seed and streams of 1,2,3,4

So, the question: is there any advantage or disadvantage to my current PCG32 initialization scheme, over using a constant seed and a different stream for each instance?

New release

Would it be possible to create a new release please? The last one, 0.98.1, is very old (6 years) and broken with Visual Studio (2019 at least).

Mingw64 compiliation Make error

The makefile fails with the following compilation error:

mingw32-make

cd test-high; D:/mingw/winlibs-x86_64-posix-seh-gcc-13.2.0-llvm-17.0.5-mingw-w64ucrt-11.0.1-r3/mingw64/bin/mingw32-make.exe
The filename, directory name, or volume label syntax is incorrect.
mingw32-make: *** [makefile:25: all] Error 1

Dead and untested code

Things I noticed by hand:

  • struct rxs_mixin has its function called output_rxs rather than just plain output, which would prevent it from being used as an output_mixin if it were ever used.
  • may_tock is always false in the testsuite, so those branches aren't tested.
  • A bunch of x ? expr : 0 where x can never be 0. Since the expression is usually a shift, it should probably be a safe_shift function though.
  • operator- on extended generators after a step that can't be represented in a single itype.

Things I noticed missing from my port's coverage report:

  • Half of pcg_engine is ever tested (noticed because all the template-typedefs have to be functions in python)
  • both overloads of extended.advance_table, both methods ininsideout, all unoutput functions, and unxorshift are never tested.
  • unique_stream.stream() and oneseq_stream.stream() Probably should be covered by operator ==.
  • engine.wrapped
  • engine.operator == and extended.operator ==
  • rxs_mixin, rxs_m_mixin, xsh_mixin, xsl_mixin
  • extended.set
  • extended.advance in the forward direction. Probably applies to engine too ... and won't discard malfunction?

Some of these may be used in the samples, but those aren't run as part of the test suite, so can't be demonstrated to work.

pcg64 can't be printed

Here's an example that won't build for pcg_t = ::pcg64 but works for pcg_t = ::pcg32.

#include <random>
#include <sstream>

#include "third_party/pcg_random/include/pcg_random.hpp"

namespace {
  using pcg_t = ::pcg64;
}

int main()
{
  pcg_t rng(std::random_device{}());

  std::stringstream out;
  out << rng;

  return 0;
}

I can verify similar issues in pcg-test.cpp if you add prints to std::cout or reads from std::cin.

What I believe is happening is: you're relying on Koenig lookup to find the definitions of operator<< and operator>> in namespace pcg_extras. But pcg128_t is typically a typedef for __uint128_t; Koenig lookup doesn't work on typedefs (or more precisely, looks at the resolved type's namespace, not the typedef's.)

As I see it there are three possible fixes:

  1. Move the operator definitions to the global namespace -- this is a bad idea, for one thing because anyone could have a conflicting definition.

  2. Add a wrapper class around the typedef. This would solve the namespacing issue neatly; I don't know if we'd incur runtime cost from the compiler choking on the wrapper. Hopefully not but hard to prove.

  3. Replace the operator<< for pcg128_t with similar free functions named (say) Input and Output and use SFINAE in the definitions of the engine operator<< to prefer those if available. A bit clunky, but would work. (Also sort of necessary for the uint8_t stuff, I think.)

I'm hacking together 3) to see how bad it looks, but not done yet.

Compilation fails with both MSVC and GCC

Since all options available in MS Visual Studio 2022, were failing:

image

I decided to try with the GNU C++ compiler (v11 and v12) using the default Makefile, but I am still unable to compile PCG-CPP without errors:

image

Prefer composition over inheritance.

Inheritance is often a code smell. Composition is usually cleaner.

Porting the full code to a language without templates was painfully difficult.

The least concern was that sometimes the names from the template parameters is used, whereas sometimes the typedef/constant in the class was used. To avoid, consider prefixing all template parameters with a _.

The mixins were bad enough (especially since some have extra functions, like unoutput), but inside_out and extended were atrocious. The frequent reliance on mutable references didn't help either.

Questions regarding internal state of PCG rng

I have a situation where I need to seed PCG from a random_device, perform some work and if later on if an investigation is needed to be able to generate the same randomness used for the given unit of work.

The following demo code does that and verifies the numbers generated are identical once the rng is reseeded - all that is good o_r at least seems "ok"_.

What I'm sort of confused with is the following:

  1. The size, in terms of bytes, of the internal seed changes on every iteration (ranges from 115 to 118 bytes)
  2. The first 39 bytes of the internal state are always the same regardless of iteration or if the process is rerun
i: 003157 state_size: 118 state: 0x34373032363234373638373934323132313834383134343230373439313833373532333532352031363633363437363738363637353336363735323933393837333638303333343331333134323120323333373034333838313634363535373131373135383634353733373431343636353934323032
i: 003158 state_size: 118 state: 0x34373032363234373638373934323132313834383134343230373439313833373532333532352031333030333935393939303235363433383336353032303136363737393735363637323235353920313230343430393334323834373531383136383133303336363435383435353632373833393137
i: 003159 state_size: 117 state: 0x343730323632343736383739343231323138343831343432303734393138333735323335323520363531363934333530333130383735333338303632333836383631373832383139313137393920323431303032363031393131313439313637363732303838353935373731303438343833313838
i: 003160 state_size: 117 state: 0x343730323632343736383739343231323138343831343432303734393138333735323335323520393935313338343230363636323432303630343532303532383139333536323536323231383720323332363033393736333335343535383934393736303732343437363538373339353737373333
i: 003161 state_size: 117 state: 0x343730323632343736383739343231323138343831343432303734393138333735323335323520333731363737353233333733363336363131373535313737323330363435323136303432313120333035303036363937303631363032353336303932373132363137353232333335343535383331
i: 003162 state_size: 118 state: 0x34373032363234373638373934323132313834383134343230373439313833373532333532352032323733313635303232313036373235353833383235313036353236393632363539353630393320313136373832343930373834353031343031343535303536383637313633393931383935323338
i: 003163 state_size: 117 state: 0x343730323632343736383739343231323138343831343432303734393138333735323335323520333236323138353338333539303336313134393633393134343832353439313932333534353631203838353632313331373737373230383139393639373631333233323433303635393832303738
i: 003164 state_size: 117 state: 0x343730323632343736383739343231323138343831343432303734393138333735323335323520313332383339363632303030323939323639383130343330323833363831303337313935333120313534343139303531303332323838343234343635333831353735383939353335363236303436
i: 003165 state_size: 117 state: 0x343730323632343736383739343231323138343831343432303734393138333735323335323520313034323438353737333232323436373138343037343833333634383936363533313639313339203337303138343536333937303235313736383835323038363133373433363832363238393034
i: 003166 state_size: 117 state: 0x343730323632343736383739343231323138343831343432303734393138333735323335323520323534303331333630383639343437303636383330353235323532373135383730333535393733203735373231313839343632343835313233383831363237303831383235363636373932313730
i: 003167 state_size: 117 state: 0x343730323632343736383739343231323138343831343432303734393138333735323335323520383231353738303835313334383637383139313637373731373235313635313139303430393320333334313230303333393734303932363836373031343330313939383130373733323739393530
i: 003168 state_size: 117 state: 0x343730323632343736383739343231323138343831343432303734393138333735323335323520343533333634333931343333343336313631313030333432393031323234363037373133343720323136333430323937393735353037323839323433323138333839353230323739373737343439
i: 003169 state_size: 118 state: 0x34373032363234373638373934323132313834383134343230373439313833373532333532352031343133323930303232343239363239393833373739303432393233363437323232373939303120323132393632303531323938303932303131373732303330303834323832313032363432343837
i: 003170 state_size: 118 state: 0x34373032363234373638373934323132313834383134343230373439313833373532333532352032343237323835353830363434383033363832343732323638323731393930333637343134393720313533363436393633333436373636343930383430363736383331313430343639353135393631
i: 003171 state_size: 117 state: 0x343730323632343736383739343231323138343831343432303734393138333735323335323520363834393934373638343332373537323537363739363839303336383233373135393239363120313330373838363933323238313439333338373834393838333739333938343833313934343532
i: 003172 state_size: 118 state: 0x34373032363234373638373934323132313834383134343230373439313833373532333532352031333733373636333631303336343634333437343832353131343038303531303238323535343520313334303531353339313533353539373536323933393433373634333435323332343831373237
i: 003173 state_size: 118 state: 0x34373032363234373638373934323132313834383134343230373439313833373532333532352032383235303038313431313632353637383236343135343031393631383139333331373739373920323834373539323533303533383235383134373939363737333235333033323036353030363830
i: 003174 state_size: 117 state: 0x343730323632343736383739343231323138343831343432303734393138333735323335323520323937373332373030313031383934343031353237323634313330393436393639373936303031203538383233313938323630383430323839323733363135343731323234393931373337303630
i: 003175 state_size: 117 state: 0x343730323632343736383739343231323138343831343432303734393138333735323335323520343039393832343930323034393138303630333633363032393534393732313833353833323120323231353830343932383634313233333330313437313537343935363634373935373639303934
i: 003176 state_size: 117 state: 0x343730323632343736383739343231323138343831343432303734393138333735323335323520353133343735353137353432343537343539333531323030363438383930393139323737303720333037303735353938373035313532343632313130343238333330333535383534363135373034
i: 003177 state_size: 116 state: 0x3437303236323437363837393432313231383438313434323037343931383337353233353235203231383132363332383330303839313736333230303639363033343033323632303631333230392037393333343434393335323837393638373636303731353539363633383830333939353831
i: 003178 state_size: 118 state: 0x34373032363234373638373934323132313834383134343230373439313833373532333532352032363133313632313631333532343338303834383632393638373839313039313130353937343320313532313031343530303337373235383132393035303031393935353531303433313737383333
i: 003179 state_size: 117 state: 0x343730323632343736383739343231323138343831343432303734393138333735323335323520383133393433393235303137303932313434373030353433363837303737373630383136393320313431353536393531303335383533383736333133323238343835323239323333383635333337

Are the above two situations normal or expected behavior?


Example code:

#include <cstdio>
#include <sstream>
#include <string>
#include <random>

#include <pcg/pcg_random.hpp>

std::string str2hex(const std::string& input)
{
    static const char hex_digits[] = "0123456789ABCDEF";
    std::string output;
    output.reserve(input.length() * 2);
    for (const unsigned char c : input)
    {
        output.push_back(hex_digits[c >> 4]);
        output.push_back(hex_digits[c & 15]);
    }
    return output;
}

int main()
{
    pcg_extras::seed_seq_from<std::random_device> seed_source;

    constexpr auto max_num_samples = 10000000;

    for (std::size_t i = 0; i < 1000000000; ++i)
    {
        pcg64 rng(seed_source);

        std::string internal;
        std::stringstream strm;
        strm << rng;
        rng_internal = strm.str();

        printf("i: %06ld state_size: %ld state: 0x%s\n", i, internal.size(), str2hex(internal).c_str());
    }

    return 0;
}

Confusing error when trying to use a different 128 bit library

I rewrote the 128 bit emulation class, but the tests won't compile. What's going on here:

../include/pcg_uint128.hpp:48:25: fatal error: no viable conversion from 'const pcg_extras::seed_seq_from<std::random_device>' to 'uint64_t' (aka 'unsigned long')
            : UPPER(0), LOWER(rhs)
                        ^     ~~~
../include/pcg_random.hpp:1288:21: note: in instantiation of function template specialization
      'pcg_extras::uint128_t::uint128_t<pcg_extras::seed_seq_from<std::random_device> >' requested here
        : baseclass(seedSeq)
                    ^
../include/pcg_random.hpp:1296:20: note: in instantiation of function template specialization 'pcg_detail::extended<'\n', '\x80', pcg_detail::engine<unsigned long,
      pcg_extras::uint128_t, pcg_detail::xsl_rr_mixin<unsigned long, pcg_extras::uint128_t>, false, pcg_detail::oneseq_stream<pcg_extras::uint128_t>,
      pcg_detail::default_multiplier<pcg128_t> >, pcg_detail::engine<unsigned long, unsigned long, pcg_detail::rxs_m_xs_mixin<unsigned long, unsigned long>, true,
      pcg_detail::oneseq_stream<unsigned long>, pcg_detail::default_multiplier<uint64_t> >, false>::extended<pcg_extras::seed_seq_from<std::random_device>, void>'
      requested here
        new (this) extended(std::forward<Args>(args)...);
                   ^
./pcg-test-noadvance.cpp:87:13: note: in instantiation of function template specialization 'pcg_detail::extended<'\n', '\x80', pcg_detail::engine<unsigned long,
      pcg_extras::uint128_t, pcg_detail::xsl_rr_mixin<unsigned long, pcg_extras::uint128_t>, false, pcg_detail::oneseq_stream<pcg_extras::uint128_t>,
      pcg_detail::default_multiplier<pcg128_t> >, pcg_detail::engine<unsigned long, unsigned long, pcg_detail::rxs_m_xs_mixin<unsigned long, unsigned long>, true,
      pcg_detail::oneseq_stream<unsigned long>, pcg_detail::default_multiplier<uint64_t> >, false>::seed<pcg_extras::seed_seq_from<std::random_device> >' requested
      here
        rng.seed(pcg_extras::seed_seq_from<std::random_device>());
            ^

This is Clang++ 4.0.0. I don't understand what pcg_random.hpp:1288 is doing.

Is this being proposed for standardization?

The best pseudo-random number generator in the C++ standard library is probably the Mersenne twister, which has well-known disadvantages such as being pretty memory heavy.

Do you know if anyone has started writing an spec to add this to the C++ standard library?

Switch to CMake

Would you be interested in making a switch to cmake-based installation? For the project I am working on, I have started removing Makefiles and writing CMakeLists.txt files to

  • Get better support in modern IDEs, and,
  • Have modular and relocatable libraries in my project.

To make the sample functions and tests work (enforcing C++11 features in a portable way), I guess you need a CMake version of at least 3.1.3 (dates back to Feb 12, 2015).

Once finished, the build, test, and install processes will be portable among systems that support CMake. Moreover, all the *.cpp files in test-high directory will be removed, as they are simply compile definitions used on pcg-test.cpp and pcg-test-noadvance.cpp.

If you are interested, I can make a PR as soon as I finish writing the CMake scripts.

Two tests failing to compile with MSVC++ 2017.

I've been poking at the test programs on Windows (Including replacing the current test-high/Makefile with a cmake file (which I can make a pull request for if there's interest), after getting tired of compiling random ones manually), and found two programs that fail to compile: check-pcg128_oneseq_once_insecure and check-pcg128_once_insecure. They both fail with the same error:

(ClCompile target) ->
  c:\users\xxx\source\pcg-cpp\include\pcg_extras.hpp(534): error C2440: '<function-style-cast>': cannot
convert from 'pcg_extras::uint_x4<uint32_t,uint64_t>' to 'delta_t' [C:\Users\xxx\Source\pcg-cpp\test-hig
h\check-pcg128_oneseq_once_insecure.vcxproj]

I haven't looked any deeper into it yet, other than to see thatdelta_t is an iterator difference type.

The good news is that all the tests that do compile pass, though since the size of various structures are different, there are some issues when diffing their output against the expected ones.

Problem with oneseq_dxsm_128_64 and uniform int distribution

/usr/include/c++/10/bits/uniform_int_dist.h:249:4: error: ‘typedef long unsigned int pcg_detail::engine<long unsigned int, __int128 unsigned, pcg_detail::dxsm_mixin<long unsigned int, __int128 unsigned>, false, pcg_detail::oneseq_stream<__int128 unsigned>, pcg_detail::default_multiplier<__int128 unsigned> >::result_type’ is inaccessible within this context

Problematic commit: ffd522e

Clang-v12 vs GCC v9 generates different stream [portability-issue]

According to the GCC standard (§8.3.6): "The order of evaluation of function arguments is unspecified."
This causes a problem when PCG is initialized from another generator. GNU GCC evaluates from right (v9.3) while Apple Clang evaluates from left (v12).

The PCG is thus non-portable as with the same seed it produced different results on various platforms.
Problematic code:

template<typename SeedSeq>
engine(SeedSeq&& seedSeq, typename std::enable_if<
stream_mixin::can_specify_stream
&& !std::is_convertible<SeedSeq, itype>::value
&& !std::is_convertible<SeedSeq, engine>::value,
can_specify_stream_tag>::type = {})
: engine(generate_one<itype,1,2>(seedSeq),
generate_one<itype,0,2>(seedSeq))

Line 520, 521. As we take two draws from the same generator, the order of evaluation matters. Clang thus generates a different stream than gcc.

It seems desirable to have a portable random number generation. (At least my use-case - scientific computation, experiment reproducibility requires it).

More on this:

cross-platform failure to reproduce sequence

I must apologize if this issue reveals a misunderstanding on my side. Nevertheless, I've been banging my head against this for too long, so I'd like to go out public and ask for help.

I am working on a simulation code that is stochastic in nature, so requires drawing from PRNGs repeatedly. In an attempt to move forward in a tested and reproducible way, I discovered a problem with xcode recently, that I have boiled down to some simple example code:

//compile with: c++ -std=c++11 -o stdlib_20 stdlib_20.cpp

#include <iostream>
#include <iomanip>
#include <random>

int main(int argc, char *argv[])
{
    std::mt19937 rng1(121);
    std::mt19937 rng2(100);
    std::normal_distribution<double> norm(5,2);
    std::uniform_int_distribution<> uni(0,50);
    std::cout.precision(8);
    for( int i = 0;i<20;++i){
        std::cout << std::setw(10) << norm(rng1) << " "
                  << std::setw(4) << uni(rng2)
                  << "\n";
    }
    return 0;
}

or using pcg of commit b656278

//compile with: c++ -std=c++11 -o pcg_20 pcg_20.cpp

#include <iostream>
#include <iomanip>
#include <random>
#include "pcg_random.hpp"

int main(int argc, char *argv[])
{
    pcg32 rng1(121);
    pcg32 rng2(100);

    std::normal_distribution<double> norm(5,2);
    std::uniform_int_distribution<> uni(0,50);
    std::cout.precision(8);
    for( int i = 0;i<20;++i){
        std::cout << std::setw(10) << norm(rng1) << " "
                  << std::setw(4) << uni(rng2)
                  << "\n";
    }
    return 0;
}

The interesting observation is, that the above code gives different results with gcc 8.3.1 on fedora 29 and on osx with xcode 9.0.0, Target: x86_64-apple-darwin17.7.0. Here is a diff of the top 10 numbers using pcg:

$ diff -y pcg.txt pcg_osx.txt|head -10
  4.689577   32						      |	 7.1985629   49
 7.1985629   48						      |	  4.689577   30
 4.8603939   35						      |	 5.1719846    6
 5.1719846   46						      |	 4.8603939   14
 1.9203969   12						      |	 6.7887334   39
 6.7887334   10						      |	 1.9203969   10
 4.9383387   10						      |	 7.2118544   14
 7.2118544   32						      |	 4.9383387   45
   4.05167   33						      |	 2.6778881   35
 2.6778881   21						      |	   4.05167   26

And using the stdlib:

$ diff -y stdlib.txt stdlib_osx.txt|head -10
 3.7834751   27						      |	 6.5112185    8
 6.5112185   34						      |	 3.7834751   24
 3.4408029   14						      |	 5.2115202    3
 5.2115202   21						      |	 3.4408029   39
 8.6759752   21						      |	 6.0075102   23
 6.0075102   26						      |	 8.6759752   15
 7.7195293   43						      |	 6.0009774   48
 6.0009774    7						      |	 7.7195293   10
 8.1130049    0						      |	 6.1374016   30
 6.1374016    7						      |	 8.1130049   34

The normal distribution (left column) appears to show consistent numbers but in an arbitrary ordering when comparing linux and osx. About the integer numbers I am quite uncertain what is going on. The question for me now is, is this an expected behavior/feature of PRNGs or is this a bug in xcode/gcc ?

pcg32_k2 is incorrectly defined

Both pcg32_k2 and pcg32_k2_fast are defined with template parameter table_log2 = 6, making them 64-dimensionally equidistributed and requiring substantially more storage than the expected 2-dimensionally equidistributed generators. This is particularly obvious if we note that pcg32_k2 and pcg32_k64 have the same definition, as do pcg32_k2_fast and pcg32_k64_fast.

I'm submitting an issue rather than a PR because I'm not sure how advance_pow2 is chosen.

Rebase seed

I'm working on an algorithm (procedural racetrack generator) whose outcome, in the general case, is solely based on the RNG outputs. But in some specific scenarios, I need to provide to user the ability to bypass some generation steps (e.g. terrain conformation) without affecting the rest of the generation process.

Let me make a simple practical example:

## Procedural racetrack ##
                                                         *
           | Track shape generation | Terrain generation | Surfaces generation | Assets picking |
RNG stream | 1 2 3                  | 4 5 6 7            | 8 9                 | 0              |
## User-overridden racetrack ##
                                                         *
           | Track shape generation | Terrain generation | Surfaces generation | Assets picking |
RNG stream | 1 2 3                  | provided by user   | 4 5                 | 6              |

As you can see, in the User-overridden racetrack case, the fact that the Terrain generation step is bypassed (and so no RNG output is consumed) alters all the subsequent generation steps.

What I'm looking for is some sort of RNG synchronization operation (probably not the most corrected term to use...) to put in between the Terrain generation step and the Surfaces generation step to have the same RNG stream from the * onwards, regardless if the terrain is provided by user or not. I thought about something like:

uint64_t seed = // initialized with racetrack ID
pcg32 rng(seed);

// Do Track shape generation step
// Do Terrain generation generation step

seed = seed + k; // where k is some constant
rng.seed(seed);

// Do Surfaces generation step
// Do Assets picking step

But I don't know if seed = seed + k; is a valid reseeding approach (or there's something better) and if some value is better than others for k.

[EDIT]
Forgot to state it, but the number of RNG outputs required for every generation step in not constant among different racetracks generation (and it isn't even predeterminable in advance).

Support Case Study for C++03?

As currently written, it seems impossible to use the library in a compiler in C++03 mode, this despite the library being otherwise a great addition to a C++ codebase as it should work similarly to the already available <random> utilities in C++03's TR1. This also given that for example I was made aware of this library in a blog entry recommending better random utilities for C++ yet in these circumstances the better clear winner against this is a competing C solution that compiles and can be used generically without issues.

Upon initial inspection of an attempted compile with GCC 5 without -std=c++11 switch, the problems that prevent the library from being compiled in C++03 mode can be categorized in three types:

  • Usage of auto to declare variables of types whose types are known or already named explicitly (eg.: in pcg_extras.hpp's operator<< for stuff like char (in a call to narrow) or fmtflags (in a call to member flags).
  • Usage of C++11 features that abbreviate or conditionate code, that can be easily backported such as static_assert or integral_constant; backporting to C++03 would probably require changing calling sites using them (such as the static assert in pcg_random line 692, which can be made into a macro if the test expression is moved into an enum). In some cases such as nullptr which even have an official backport this should be easily doable as most of these features are library-level solutions.
  • Usage of C++11 features that have no equivalent in a C++03 compiler, such as constexpr. These would probably require writing ad-hoc code to simulate the desired behaviour (some variables declared constexpr could be converted to enums, for example), or providing a more limited alternative.

It would be interesting to see a more involved case study of what backporting to C++03 would require; in particular, while I don't have problems trying to edit the headers myself to seek out a better compile, I am not qualified for and wouldn't venture into ensuring that the statistical properties of the utilities are preserved.

(Disclainer: am the author of cxxomfort, a general backports library for C++, and am using the backports myself for the compile tests, so my experience might not reflect an attempted backport "from scratch")

Does it make sense to expand this to 256-bit instructions?

The talk on youtube shows that the 64-bit version has twice the throughput of the 32-bit version (for processors that support 64-bit integers on hardware), which is pretty exciting. I wonder if PCG is suitable for extension to higher-throughput vectorized hardware instructions (ie. AVX/AVX2)?

Four consecutive seeds give the same RNG when using pcg64_fast or pcg32_fast

Four consecutive seeds give identical random numbers for the pcg64_fast or pcg32_fast generators. For example pcg64_fast(0), pcg64_fast(1), pcg64_fast(2), and pcg64_fast(3) return identical states and thus identical random numbers.

See output of my test script (example.zip):

checking seed 0 to 9 using pcg32_fast..
	0	0	3614609610	1032979711
	1	0	3614609610	1032979711
	2	0	3614609610	1032979711
	3	0	3614609610	1032979711
	4	0	517360375	2849173575
	5	0	517360375	2849173575
	6	0	517360375	2849173575
	7	0	517360375	2849173575
	8	0	3092770245	231179071
	9	0	3092770245	231179071
checking seed 0 to 9 using pcg64_fast..
	0	972365100324636832	3152476261539479119	4963323010661987954
	1	972365100324636832	3152476261539479119	4963323010661987954
	2	972365100324636832	3152476261539479119	4963323010661987954
	3	972365100324636832	3152476261539479119	4963323010661987954
	4	8681540523656324337	8610569632533855969	15689244027466136655
	5	8681540523656324337	8610569632533855969	15689244027466136655
	6	8681540523656324337	8610569632533855969	15689244027466136655
	7	8681540523656324337	8610569632533855969	15689244027466136655
	8	4621899917499390773	4965021727069323010	11849989275254633783
	9	4621899917499390773	4965021727069323010	11849989275254633783
checking seed 0 to 9 using pcg32..
	0	3894649422	2055130073	2315086854
	1	1412771199	1791099446	124312908
	2	3461116586	2338043315	3191287740
	3	3053290573	2880989984	3620796526
	4	78042152	3239916909	598054463
	5	338748765	3035781544	893179696
	6	2079632860	1396738611	3112634576
	7	1273465047	4201302492	1760530922
	8	1658943282	3425254359	1380307894
	9	3396683593	298473608	3727095581
checking seed 0 to 9 using pcg64..
	0	74029666500212977	8088122161323000979	16521829690994476282
	1	16246141021062200314	13888980485107364105	1444523129010881979
	2	15283991013767829887	16012073048563605758	18041754508879526868
	3	4571984878009979848	4956887517419763765	10963035626649002760
	4	8213965343793293256	14634166037439189285	7351202335824653137
	5	12828375142235852897	3043909115430366615	12212956655512261919
	6	14744360861768679421	7731410906820487750	9990277316766610057
	7	2314236103276969522	16242248372244286679	9455988229017472731
	8	6146847088143149122	105960750376085417	8469200379157136437
	9	4176210987077628350	5147113462634521278	7929888373037025941
It appears that that seed = 4*n+i for i in {0,1,2,3} gives identical results for a fixed n for the two fast variants. Additionally, the 32 bit fast variant seems to start at zero.
Checking whether the problem remains for higher seeds:
pcg64_fast: All checked generators are memory identical for fixed seed // 4
pcg32_fast: All checked generators are memory identical for fixed seed // 4

Solaris build failure

I have incorporated the PCG family into an R package. On submission to CRAN I have been informed about a compilation error on Solaris:

In file included from dqrng.cpp:22:0:
../inst/include/pcg_random.hpp:1639:18: error: reference to ‘extended’ is ambiguous
using ext_std8 = extended<table_pow2, advance_pow2, BaseRNG,
^
In file included from /usr/include/math.h:382:0,
from /opt/csw/include/c++/5.2.0/cmath:44,
from /home/ripley/R/Lib32/Rcpp/include/Rcpp/platform/compiler.h:100,
from /home/ripley/R/Lib32/Rcpp/include/Rcpp/r/headers.h:48,
from /home/ripley/R/Lib32/Rcpp/include/RcppCommon.h:38,
from /home/ripley/R/Lib32/Rcpp/include/Rcpp.h:27,
from dqrng.cpp:18:
/usr/include/floatingpoint.h:71:18: note: candidates are: typedef unsigned int extended [3]
typedef unsigned extended[3];
^

I was able to circumvent this with a simple patch to use fully qualified names. Are you interested in a PR based on this patch?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.