Is it incorrect to use 0 (zero) to seed srand()?
int seed = (argc >= 2 && strlen(argv[1]) == 9)
? atoi(argv[1])
: (int)(time(NULL) % 900000000 + 100000000);
srand(seed);
On 2025-12-22 03:48, Michael Sanders wrote:
Is it incorrect to use 0 (zero) to seed srand()?
int seed = (argc >= 2 && strlen(argv[1]) == 9)
? atoi(argv[1])
: (int)(time(NULL) % 900000000 + 100000000);
srand(seed);
No, why whould you think so?
On 2025-12-22 12:44, James Kuyper wrote:
On 2025-12-22 03:48, Michael Sanders wrote:
Is it incorrect to use 0 (zero) to seed srand()?
int seed = (argc >= 2 && strlen(argv[1]) == 9)
? atoi(argv[1])
: (int)(time(NULL) % 900000000 + 100000000);
srand(seed);
No, why whould you think so?
There's number sequence generators that produce 0 sequences if seeded
with 0. ...
... And maybe the comment in 'man 3 rand', "If no seed value is
provided, the rand() function is automatically seeded with a value
of 1.", may have fostered his doubt.
On 2025-12-22 07:18, Janis Papanagnou wrote:
On 2025-12-22 12:44, James Kuyper wrote:
On 2025-12-22 03:48, Michael Sanders wrote:
Is it incorrect to use 0 (zero) to seed srand()?
int seed = (argc >= 2 && strlen(argv[1]) == 9)
? atoi(argv[1])
: (int)(time(NULL) % 900000000 + 100000000);
srand(seed);
No, why whould you think so?
There's number sequence generators that produce 0 sequences if seeded
with 0. ...
The details of how the seed affects the random number sequence are unspecified by the standard. I personally would consider a pseudo-random number generator to be quite defective if there were any seed that
produced a constant output.
[...]
On 2025-12-22 18:13, James Kuyper wrote:
On 2025-12-22 07:18, Janis Papanagnou wrote:
On 2025-12-22 12:44, James Kuyper wrote:
On 2025-12-22 03:48, Michael Sanders wrote:
Is it incorrect to use 0 (zero) to seed srand()?
int seed = (argc >= 2 && strlen(argv[1]) == 9)
? atoi(argv[1])
: (int)(time(NULL) % 900000000 + 100000000);
srand(seed);
No, why whould you think so?
There's number sequence generators that produce 0 sequences if
seeded with 0. ...
The details of how the seed affects the random number sequence are unspecified by the standard. I personally would consider a
pseudo-random number generator to be quite defective if there were
any seed that produced a constant output.
I wouldn't have mentioned that if there weren't a whole class of
such functions that expose exactly that behavior by design. Have
a look for PN-(Pseudo Noise-)generators and LFSR (Linear Feedback
Shift Registers). These have been defined to produce random noise
(bit pattern with good statistical distribution). With sophisticated generator polynomials they produce also sequences of maximum period;
say, for N=31 a non-repeating sequence of length 2^N - 1. The one
element that is missing from the sequence is the 0 (that reproduces
itself).
Technically you pick some bit-values from fixed positions (depending
on the generator polynomial) of the register and xor the bits to shift
the result into the register. Here's ad hoc an example...
#include <stdio.h>
#include <stdint.h>
int main ()
{
uint32_t init = 0x00000038;
uint32_t reg = init;
uint32_t new_bit;
int count = 0;
do {
new_bit = ((reg >> 2) + (reg >> 4) + (reg >> 6) + (reg >>
30)) & 0x1;
reg <<= 1;
reg |= new_bit;
reg &= 0x7fffffff;
count++;
} while (reg != init);
printf ("period: %d\n", count);
}
Janis
[...]
On 2025-12-22 18:13, James Kuyper wrote:
On 2025-12-22 07:18, Janis Papanagnou wrote:
On 2025-12-22 12:44, James Kuyper wrote:
On 2025-12-22 03:48, Michael Sanders wrote:
Is it incorrect to use 0 (zero) to seed srand()?
int seed = (argc >= 2 && strlen(argv[1]) == 9)
? atoi(argv[1])
: (int)(time(NULL) % 900000000 + 100000000);
srand(seed);
No, why whould you think so?
There's number sequence generators that produce 0 sequences if seeded
with 0. ...
The details of how the seed affects the random number sequence are
unspecified by the standard. I personally would consider a pseudo-random
number generator to be quite defective if there were any seed that
produced a constant output.
I wouldn't have mentioned that if there weren't a whole class of
such functions that expose exactly that behavior by design. Have
a look for PN-(Pseudo Noise-)generators and LFSR (Linear Feedback
Shift Registers).
#include <stdint.h>
int main ()
{
uint32_t init = 0x00000038;
uint32_t reg = init;
uint32_t new_bit;
int count = 0;
do {
new_bit = ((reg >> 2) + (reg >> 4) + (reg >> 6) + (reg >> 30))
& 0x1;
reg <<= 1;
reg |= new_bit;
... (not POSIX imbecile rand_r() ) ...
[...]
In practice, using LFSR for rand() is not particularly bright idea for different reason: LFSR is a reasonably good PRNG for a single bit, but
not when you want to generate a group of 31 pseudo-random bits. [...]
There's number sequence generators that produce 0 sequences if seededIs it incorrect to use 0 (zero) to seed srand()?No, why whould you think so?
On 2025-12-22, Janis Papanagnou <janis_papanagnou+ng@hotmail.com> wrote:
I don't recall having paid attention to this exact material in the
past so it is a "TIL" for me.
#include <stdint.h>
int main ()
{
uint32_t init = 0x00000038;
uint32_t reg = init;
uint32_t new_bit;
int count = 0;
do {
new_bit = ((reg >> 2) + (reg >> 4) + (reg >> 6) + (reg >> 30))
& 0x1;
These could of course be XOR, without it making a difference; the least significant bit in a binary addition is the XOR of the LSB's of the
inputs.
[...]
[...] LFSR is a reasonably good PRNG for a single bit, but
not when you want to generate a group of 31 pseudo-random bits. In
order to get 31 new bits, without predictable repetitions from the
previous value, you would have to do 31 steps. That's slow! The process
can be accelerate by generation of several bits at time via look up
tables, but in order to get decent speed the table has to be rater big
and using big tables in standard library is bad sportsmanship.
It seems that overwhelming majority C RTLs use Linear Congruential Generators, probably because for Stanadard library compactness of both
code and data is considered more important than very high speed (not
that on modern HW LCGs are slow) or superior random properties of
Mersenne Twisters.
[...]
Is it incorrect to use 0 (zero) to seed srand()?
int seed = (argc >= 2 && strlen(argv[1]) == 9)
? atoi(argv[1])
: (int)(time(NULL) % 900000000 + 100000000);
srand(seed);
I like to just read /dev/urandom when I need a random number. Seem
easier and more portable across Linux & the *BSDs.
Michael Sanders <porkchop@invalid.foo> wrote:
Is it incorrect to use 0 (zero) to seed srand()?
int seed = (argc >= 2 && strlen(argv[1]) == 9)
? atoi(argv[1])
: (int)(time(NULL) % 900000000 + 100000000);
srand(seed);
I like to just read /dev/urandom when I need a random
number. Seem easier and more portable across Linux &
the *BSDs.
int s;
read(fd, &s, sizeof(int));
On 2025-12-22 03:48, Michael Sanders wrote:
Is it incorrect to use 0 (zero) to seed srand()?
int seed = (argc >= 2 && strlen(argv[1]) == 9)
? atoi(argv[1])
: (int)(time(NULL) % 900000000 + 100000000);
srand(seed);
No, why whould you think so?
There's number sequence generators that produce 0 sequences if seeded
with 0. And maybe the comment in 'man 3 rand', "If no seed value is
provided, the rand() function is automatically seeded with a value
of 1.", may have fostered his doubt.
I like to just read /dev/urandom when I need a random
number. Seem easier and more portable across Linux &
the *BSDs.
int s;
read(fd, &s, sizeof(int));
On Mon, 22 Dec 2025 06:44:42 -0500, James Kuyper wrote:
On 2025-12-22 03:48, Michael Sanders wrote:
Is it incorrect to use 0 (zero) to seed srand()?
int seed = (argc >= 2 && strlen(argv[1]) == 9)
? atoi(argv[1])
: (int)(time(NULL) % 900000000 + 100000000);
srand(seed);
No, why whould you think so?
Excuse my delayed reply James (net provider was down most of today).
Well, I guess I did not expect such large differences between
gcc & musl somehow (cant test with clang just yet). I understand the
sequence is deterministic & likely still some differences with musl,
yet I wrongly assumed it seems, the sequences would be the same...
#include <stdio.h>
#include <stdlib.h>
int main(void) {
srand(0);
printf("%d\n", rand());
return 0;
}
/*
$ gcc -O2 -o rnd rnd.c && ./rnd
1804289383
$ musl-gcc -static -O2 -o rnd rnd.c && ./rnd
2049033599
*/
On Mon, 22 Dec 2025 13:18:19 +0100, Janis Papanagnou wrote:
There's number sequence generators that produce 0 sequences if seeded
with 0. And maybe the comment in 'man 3 rand', "If no seed value is
provided, the rand() function is automatically seeded with a value
of 1.", may have fostered his doubt.
Janis - naive question for you...
How do I bring up *posix only* man pages using 3?
I see no difference when invoking any of:
man 3 srand
or: man 3 posix srand
or: man posix 3 srand
What I'm doing wrong here?
On 2025-12-22 19:45, Michael S wrote:
[...] LFSR is a reasonably good PRNG for a single bit, but
not when you want to generate a group of 31 pseudo-random bits. In
order to get 31 new bits, without predictable repetitions from the
previous value, you would have to do 31 steps. That's slow! The
process can be accelerate by generation of several bits at time via
look up tables, but in order to get decent speed the table has to
be rater big and using big tables in standard library is bad
sportsmanship.
Yes. But mind that the speed is also depending on what quality you
need. For example; I used the PN-generator to create bit-sequences
(as you also suggest). For another application both, PN-LFSR and
LCG (that you mention below), were inacceptable; we used a cipher
to create the random data. (If you compare the speed of creating
the cipher to a bit-shift-register the latter looks really fast.)
It seems that overwhelming majority C RTLs use Linear Congruential Generators, probably because for Stanadard library compactness of
both code and data is considered more important than very high
speed (not that on modern HW LCGs are slow) or superior random
properties of Mersenne Twisters.
For "standard applications" I always used the simple LCGs; simple
and fast. Or whatever the tools or library provided; which were
mostly anyway LCGs.
Janis
[...]
When I need PRNG then I am typically not deeply concerned about size of
its internal state. On the other hand, I don't want to care about
potentially insufficient randomness of the output (not in crypto
sense). On the 3rd hand, vectors that I generate with PRNG tend to be
big and I don't like to wait, so I do care somewhat about speed.
Those 3 factors together plus availability long ago made MT19937-64
into my personal default PRNG of choice.
MT19937-64 is available out of the box(*) in C++. But not in C, unfortunately.
At higher theoretical level MT is a generalization of LFSR, but it is
not obvious when one looks at implementation.
Is it incorrect to use 0 (zero) to seed srand()?
int seed = (argc >= 2 && strlen(argv[1]) == 9)
? atoi(argv[1])
: (int)(time(NULL) % 900000000 + 100000000);
srand(seed);
On 2025-12-23 08:24, Michael Sanders wrote:
[...]
How do I bring up *posix only* man pages using 3?
Sorry, can't help you here. Maybe someone else can.
On Mon, 22 Dec 2025 13:18:19 +0100, Janis Papanagnou wrote:
There's number sequence generators that produce 0 sequences if seeded
with 0. And maybe the comment in 'man 3 rand', "If no seed value is
provided, the rand() function is automatically seeded with a value
of 1.", may have fostered his doubt.
Janis - naive question for you...
How do I bring up *posix only* man pages using 3?
I see no difference when invoking any of:
man 3 srand
or: man 3 posix srand
or: man posix 3 srand
What I'm doing wrong here?
On 2025-12-23 10:18, Michael S wrote:
When I need PRNG then I am typically not deeply concerned about
size of its internal state. On the other hand, I don't want to care
about potentially insufficient randomness of the output (not in
crypto sense). On the 3rd hand, vectors that I generate with PRNG
tend to be big and I don't like to wait, so I do care somewhat
about speed. Those 3 factors together plus availability long ago
made MT19937-64 into my personal default PRNG of choice.
I've never intensified my knowledge in direction of MT algorithms.
MT19937-64 is available out of the box(*) in C++. But not in C, unfortunately.
This is really strange given that the name ("Mersenne Twister") is
that prominent.
Looking that up I find at least "C" code for MT19937 in Wikipedia https://de.wikipedia.org/wiki/Mersenne-Twister
It's based on 32 bit logic it seems; interpreting your "MT19937-64"
I assume you're looking for a 64 bit based version?
At higher theoretical level MT is a generalization of LFSR, but it
is not obvious when one looks at implementation.
Well, at least there's the 'mod' operations all based on powers of 2
along with all the binary op's which suggests some (non-arithmetic) bit-register type of algorithm, but the multiplication with 0x9908b0df
(5 * 513496723) - which I'd suppose be hard to realize as/with LFSR -
may suggest some other generator type.
Janis
It is not the compilers that are different, it is the C standard
libraries that are different. gcc is a compiler, not a library, but you
are probably using glibc with it by default. musl is a library, not a compiler. There is no reason to suppose that different C standard
libraries use the same implementation of rand()and srand(), so no reason
to suppose they would give the same sequences - though each on their own will give a deterministic pseudo-random sequence based on their seeds.
If you swap gcc with clang you will get the same results - it will
depend on whether you are linking with glibc, musl, or another C library.
On Debian, Ubuntu, and similar systems, you can install the
"manpages-posix" (section 1) and "manpages-posix-dev" (sections 3
and 7) packages. You can then view the POSIX man page for srand
by typing any of:
man 3posix srand
man -s 3posix srand
man srand.3posix
I'd expect similar packages to be available on (some) other systems.
Manual pages are for the implementation of the operating system.
The current standard version can be viewed here: <https://pubs.opengroup.org/onlinepubs/9799919799/functions/srand.html>
This is the older standard version, still containing rand_r(): <https://pubs.opengroup.org/onlinepubs/9699919799/functions/srand.html>
On Tue, 23 Dec 2025 00:39:49 -0000 (UTC), John McCue wrote:
I like to just read /dev/urandom when I need a random number. Seem
easier and more portable across Linux & the *BSDs.
Not to mention a lot stronger, cryptographically.
On Mon, 22 Dec 2025 13:18:19 +0100, Janis Papanagnou wrote:
There's number sequence generators that produce 0 sequences if seeded
with 0. And maybe the comment in 'man 3 rand', "If no seed value is
provided, the rand() function is automatically seeded with a value
of 1.", may have fostered his doubt.
Janis - naive question for you...
How do I bring up *posix only* man pages using 3?
I see no difference when invoking any of:
man 3 srand
or: man 3 posix srand
or: man posix 3 srand
What I'm doing wrong here?
On 2025-12-23 08:24, Michael Sanders wrote:
On Mon, 22 Dec 2025 13:18:19 +0100, Janis Papanagnou wrote:
There's number sequence generators that produce 0 sequences if seeded
with 0. And maybe the comment in 'man 3 rand', "If no seed value is
provided, the rand() function is automatically seeded with a value
of 1.", may have fostered his doubt.
Janis - naive question for you...
How do I bring up *posix only* man pages using 3?
Sorry, can't help you here. Maybe someone else can.
Myself I only access the Unix man pages as they come,
i.e. using either 'man entry' or 'man section entry'.
The POSIX information is usually textually integrated
in the man pages.
I see no difference when invoking any of:
man 3 srand
That's what I'm doing, and I see, for example,
...
HISTORY
rand()
srand()
SVr4, 4.3BSD, C89, POSIX.1-2001.
On Mon, 22 Dec 2025 18:41:10 +0100
Janis Papanagnou <janis_papanagnou+ng@hotmail.com> wrote:
On 2025-12-22 18:13, James Kuyper wrote:
On 2025-12-22 07:18, Janis Papanagnou wrote:
On 2025-12-22 12:44, James Kuyper wrote:
On 2025-12-22 03:48, Michael Sanders wrote:
Is it incorrect to use 0 (zero) to seed srand()?
int seed = (argc >= 2 && strlen(argv[1]) == 9)
? atoi(argv[1])
: (int)(time(NULL) % 900000000 + 100000000);
srand(seed);
No, why whould you think so?
There's number sequence generators that produce 0 sequences if
seeded with 0. ...
The details of how the seed affects the random number sequence are
unspecified by the standard. I personally would consider a
pseudo-random number generator to be quite defective if there were
any seed that produced a constant output.
I wouldn't have mentioned that if there weren't a whole class of
such functions that expose exactly that behavior by design. Have
a look for PN-(Pseudo Noise-)generators and LFSR (Linear Feedback
Shift Registers). These have been defined to produce random noise
(bit pattern with good statistical distribution). With sophisticated
generator polynomials they produce also sequences of maximum period;
say, for N=31 a non-repeating sequence of length 2^N - 1. The one
element that is missing from the sequence is the 0 (that reproduces
itself).
Technically you pick some bit-values from fixed positions (depending
on the generator polynomial) of the register and xor the bits to shift
the result into the register. Here's ad hoc an example...
#include <stdio.h>
#include <stdint.h>
int main ()
{
uint32_t init = 0x00000038;
uint32_t reg = init;
uint32_t new_bit;
int count = 0;
do {
new_bit = ((reg >> 2) + (reg >> 4) + (reg >> 6) + (reg >>
30)) & 0x1;
reg <<= 1;
reg |= new_bit;
reg &= 0x7fffffff;
count++;
} while (reg != init);
printf ("period: %d\n", count);
}
Janis
[...]
Pay attention that C Standard only requires for the same seed to always produces the same sequence. There is no requirement that different
seeds have to produce different sequences.
So, for generator in your example, implementation like below would be
fully legal. Personally, I wouldn't even consider it as particularly
poor quality:
void srand(unsigned seed ) { init = seed | 1;}
[O.T.]
In practice, using LFSR for rand() is not particularly bright idea for different reason: LFSR is a reasonably good PRNG for a single bit, but
not when you want to generate a group of 31 pseudo-random bits. In
order to get 31 new bits, without predictable repetitions from the
previous value, you would have to do 31 steps. That's slow! The process
can be accelerate by generation of several bits at time via look up
tables, but in order to get decent speed the table has to be rater big
and using big tables in standard library is bad sportsmanship.
It seems that overwhelming majority C RTLs use Linear Congruential Generators, probably because for Stanadard library compactness of both
code and data is considered more important than very high speed (not
that on modern HW LCGs are slow) or superior random properties of
Mersenne Twisters.
On Tue, 23 Dec 2025 08:25:59 +0100, David Brown wrote:
It is not the compilers that are different, it is the C standard
libraries that are different. gcc is a compiler, not a library, but you
are probably using glibc with it by default. musl is a library, not a
compiler. There is no reason to suppose that different C standard
libraries use the same implementation of rand()and srand(), so no reason
to suppose they would give the same sequences - though each on their own
will give a deterministic pseudo-random sequence based on their seeds.
If you swap gcc with clang you will get the same results - it will
depend on whether you are linking with glibc, musl, or another C library.
Sure enough & thank you David - I appreciate your explanation.
I see where my thinking was off now. You're 100% correct
(I'm still learning as you noticed).
HISTORY
rand()
srand()
SVr4, 4.3BSD, C89, POSIX.1-2001.
Those interfaces were originally documented in the SVID
(System V Interface Definition).
The third edition (1989) states:
"The function rand() uses a multiplicative congruential random-number
generator with a period 2^32 that returns successive psuedo-random
numbers in the range 0 to 32767."
In the FUTURE DIRECTIONS section, it notes:
"The algorithms used in rand() and srand() are obsolete and will
be replaced with algorithms providing better pseudo-random characteristics
in a future issue".
There was never a fourth edition.
On 2025-12-23, John McCue <jmclnx@gmail.com.invalid> wrote:
Michael Sanders <porkchop@invalid.foo> wrote:
Is it incorrect to use 0 (zero) to seed srand()?
int seed = (argc >= 2 && strlen(argv[1]) == 9)
? atoi(argv[1])
: (int)(time(NULL) % 900000000 + 100000000);
srand(seed);
I like to just read /dev/urandom when I need a random
number. Seem easier and more portable across Linux &
the *BSDs.
int s;
read(fd, &s, sizeof(int));
srand takes an unsigned argument.
unsigned s;
read(fd, &s, sizeof s);
Michael S <already5chosen@yahoo.com> wrote:
On Mon, 22 Dec 2025 18:41:10 +0100
Janis Papanagnou <janis_papanagnou+ng@hotmail.com> wrote:
On 2025-12-22 18:13, James Kuyper wrote:
On 2025-12-22 07:18, Janis Papanagnou wrote:
On 2025-12-22 12:44, James Kuyper wrote:
On 2025-12-22 03:48, Michael Sanders wrote:
Is it incorrect to use 0 (zero) to seed srand()?
int seed = (argc >= 2 && strlen(argv[1]) == 9)
? atoi(argv[1])
: (int)(time(NULL) % 900000000 + 100000000);
srand(seed);
No, why whould you think so?
There's number sequence generators that produce 0 sequences if
seeded with 0. ...
The details of how the seed affects the random number sequence
are unspecified by the standard. I personally would consider a
pseudo-random number generator to be quite defective if there
were any seed that produced a constant output.
I wouldn't have mentioned that if there weren't a whole class of
such functions that expose exactly that behavior by design. Have
a look for PN-(Pseudo Noise-)generators and LFSR (Linear Feedback
Shift Registers). These have been defined to produce random noise
(bit pattern with good statistical distribution). With
sophisticated generator polynomials they produce also sequences of
maximum period; say, for N=31 a non-repeating sequence of length
2^N - 1. The one element that is missing from the sequence is the
0 (that reproduces itself).
Technically you pick some bit-values from fixed positions
(depending on the generator polynomial) of the register and xor
the bits to shift the result into the register. Here's ad hoc an
example...
#include <stdio.h>
#include <stdint.h>
int main ()
{
uint32_t init = 0x00000038;
uint32_t reg = init;
uint32_t new_bit;
int count = 0;
do {
new_bit = ((reg >> 2) + (reg >> 4) + (reg >> 6) + (reg >>
30)) & 0x1;
reg <<= 1;
reg |= new_bit;
reg &= 0x7fffffff;
count++;
} while (reg != init);
printf ("period: %d\n", count);
}
Janis
[...]
Pay attention that C Standard only requires for the same seed to
always produces the same sequence. There is no requirement that
different seeds have to produce different sequences.
So, for generator in your example, implementation like below would
be fully legal. Personally, I wouldn't even consider it as
particularly poor quality:
void srand(unsigned seed ) { init = seed | 1;}
[O.T.]
In practice, using LFSR for rand() is not particularly bright idea
for different reason: LFSR is a reasonably good PRNG for a single
bit, but not when you want to generate a group of 31 pseudo-random
bits. In order to get 31 new bits, without predictable repetitions
from the previous value, you would have to do 31 steps. That's
slow! The process can be accelerate by generation of several bits
at time via look up tables, but in order to get decent speed the
table has to be rater big and using big tables in standard library
is bad sportsmanship.
It seems that overwhelming majority C RTLs use Linear Congruential Generators, probably because for Stanadard library compactness of
both code and data is considered more important than very high
speed (not that on modern HW LCGs are slow) or superior random
properties of Mersenne Twisters.
There is a paper "PCG: A Family of Simple Fast Space-Efficient
Statistically Good Algorithms for Random Number Generation"
by M. O’Neill where she gives a family of algorithms and runs
several statistical tests against known algorithms. Mersenne
Twister does not look good in tests. If you have enough (128) bits
LCGs do pass tests. A bunch of generators with 64-bit state also
passes tests. So the only reason to prefer Mersenne Twister is
that it is implemented in available libraries. Otherwise it is
not so good, have large state and needs more execution time
than alternatives.
On Tue, 23 Dec 2025 10:54:23 +0100...
Janis Papanagnou <janis_papanagnou+ng@hotmail.com> wrote:
On 2025-12-23 10:18, Michael S wrote:
MT19937-64 is available out of the box(*) in C++. But not in C,
unfortunately.
This is really strange given that the name ("Mersenne Twister") is
that prominent.
Looking that up I find at least "C" code for MT19937 in Wikipedia
https://de.wikipedia.org/wiki/Mersenne-Twister
It's based on 32 bit logic it seems; interpreting your "MT19937-64"
I assume you're looking for a 64 bit based version?
"Available out of the box" in this sentence means "part of standard
library".
On 2025-12-23 06:50, Michael S wrote:
On Tue, 23 Dec 2025 10:54:23 +0100...
Janis Papanagnou <janis_papanagnou+ng@hotmail.com> wrote:
On 2025-12-23 10:18, Michael S wrote:
MT19937-64 is available out of the box(*) in C++. But not in C,
unfortunately.
This is really strange given that the name ("Mersenne Twister") is
that prominent.
Looking that up I find at least "C" code for MT19937 in Wikipedia
https://de.wikipedia.org/wiki/Mersenne-Twister
It's based on 32 bit logic it seems; interpreting your "MT19937-64"
I assume you're looking for a 64 bit based version?
"Available out of the box" in this sentence means "part of standard
library".
Citation, please? I can find neither Mersenne nor "MT19937-64" anywhere
in n5001.pdf, the latest draft version of the C++ standard that I have
access to, which is dated 2024-12-17.
Testing randomness is complicated matter.
On Wed, 24 Dec 2025 00:08:24 +0200, Michael S wrote:
Testing randomness is complicated matter.
Impossible, really, if you define “random” as “Nobody can know what comes
next”.
On 2025-12-23 21:02, Lawrence D’Oliveiro wrote:
On Wed, 24 Dec 2025 00:08:24 +0200, Michael S wrote:
Testing randomness is complicated matter.
Impossible, really, if you define “random” as “Nobody can know what
comes next”.
The quality of pseudo-random number generators can be measured, but you
need to carefully define what you mean by "quality".
Is it incorrect to use 0 (zero) to seed srand()?
int seed = (argc >= 2 && strlen(argv[1]) == 9)
? atoi(argv[1])
: (int)(time(NULL) % 900000000 + 100000000);
srand(seed);
Wish there was such a 'device' under Windows...
On Tue, 23 Dec 2025 00:39:49 -0000 (UTC), John McCue wrote:
I like to just read /dev/urandom when I need a random
number. Seem easier and more portable across Linux &
the *BSDs.
int s;
read(fd, &s, sizeof(int));
Thanks John. Wish there was such a 'device' under Windows...
On Tue, 23 Dec 2025 07:25:42 -0000 (UTC)
Michael Sanders <porkchop@invalid.foo> wrote:
On Tue, 23 Dec 2025 00:39:49 -0000 (UTC), John McCue wrote:
I like to just read /dev/urandom when I need a random
number. Seem easier and more portable across Linux &
the *BSDs.
int s;
read(fd, &s, sizeof(int));
Thanks John. Wish there was such a 'device' under Windows...
There is.
Windows XP/Vista/7: https://learn.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptgenrandom
Win8 and later: https://learn.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptgenrandom
On Tue, 23 Dec 2025 17:54:05 -0000 (UTC)
antispam@fricas.org (Waldek Hebisch) wrote:
Michael S <already5chosen@yahoo.com> wrote:
On Mon, 22 Dec 2025 18:41:10 +0100
Janis Papanagnou <janis_papanagnou+ng@hotmail.com> wrote:
On 2025-12-22 18:13, James Kuyper wrote:
On 2025-12-22 07:18, Janis Papanagnou wrote:
On 2025-12-22 12:44, James Kuyper wrote:
On 2025-12-22 03:48, Michael Sanders wrote:
Is it incorrect to use 0 (zero) to seed srand()?
int seed = (argc >= 2 && strlen(argv[1]) == 9)
? atoi(argv[1])
: (int)(time(NULL) % 900000000 + 100000000);
srand(seed);
No, why whould you think so?
There's number sequence generators that produce 0 sequences if
seeded with 0. ...
The details of how the seed affects the random number sequence
are unspecified by the standard. I personally would consider a
pseudo-random number generator to be quite defective if there
were any seed that produced a constant output.
I wouldn't have mentioned that if there weren't a whole class of
such functions that expose exactly that behavior by design. Have
a look for PN-(Pseudo Noise-)generators and LFSR (Linear Feedback
Shift Registers). These have been defined to produce random noise
(bit pattern with good statistical distribution). With
sophisticated generator polynomials they produce also sequences of
maximum period; say, for N=31 a non-repeating sequence of length
2^N - 1. The one element that is missing from the sequence is the
0 (that reproduces itself).
Technically you pick some bit-values from fixed positions
(depending on the generator polynomial) of the register and xor
the bits to shift the result into the register. Here's ad hoc an
example...
#include <stdio.h>
#include <stdint.h>
int main ()
{
uint32_t init = 0x00000038;
uint32_t reg = init;
uint32_t new_bit;
int count = 0;
do {
new_bit = ((reg >> 2) + (reg >> 4) + (reg >> 6) + (reg >>
30)) & 0x1;
reg <<= 1;
reg |= new_bit;
reg &= 0x7fffffff;
count++;
} while (reg != init);
printf ("period: %d\n", count);
}
Janis
[...]
Pay attention that C Standard only requires for the same seed to
always produces the same sequence. There is no requirement that
different seeds have to produce different sequences.
So, for generator in your example, implementation like below would
be fully legal. Personally, I wouldn't even consider it as
particularly poor quality:
void srand(unsigned seed ) { init = seed | 1;}
[O.T.]
In practice, using LFSR for rand() is not particularly bright idea
for different reason: LFSR is a reasonably good PRNG for a single
bit, but not when you want to generate a group of 31 pseudo-random
bits. In order to get 31 new bits, without predictable repetitions
from the previous value, you would have to do 31 steps. That's
slow! The process can be accelerate by generation of several bits
at time via look up tables, but in order to get decent speed the
table has to be rater big and using big tables in standard library
is bad sportsmanship.
It seems that overwhelming majority C RTLs use Linear Congruential
Generators, probably because for Stanadard library compactness of
both code and data is considered more important than very high
speed (not that on modern HW LCGs are slow) or superior random
properties of Mersenne Twisters.
There is a paper "PCG: A Family of Simple Fast Space-Efficient
Statistically Good Algorithms for Random Number Generation"
by M. O’Neill where she gives a family of algorithms and runs
several statistical tests against known algorithms. Mersenne
Twister does not look good in tests. If you have enough (128) bits
LCGs do pass tests. A bunch of generators with 64-bit state also
passes tests. So the only reason to prefer Mersenne Twister is
that it is implemented in available libraries. Otherwise it is
not so good, have large state and needs more execution time
than alternatives.
I don't know. Testing randomness is complicated matter.
How can I be sure that L’Ecuyer and Simard’s TestU01 suite tests things that I personally care about and that it does not test things that are
of no interest for me? Especially, the latter.
Also, the TestU01 suit is made for generators with 32-bit output.
M. O’Neill used ad hoc technique to make it applicable to generators
with 64-bit output. Is this technique right? Or may be it put 64-bit
PRNG at unfair disadvantage?
Besides, I strongly disagree with at least one assertion made by
O’Neill: "While security-related applications should
use a secure generator, because we cannot always know the future
contexts in which our code will be used, it seems wise for all
applications to avoid generators that make discovering their entire
internal state completely trivial."
No, I know exactly what I am doing/ I know exactly that for my
application easy discovery of complete state of PRNG is not a defect.
Anyway, even if I am skeptical about her criticism of popular PRNGs, intuitively I agree with the constructive part of the article - medium-quality PRNG that feeds medium quality hash function can
potentially produce very good fast PRNG with rather small internal
state.
On related note, I think that even simple counter fed into high quality
hash function (not cryptographically high quality, far less than that)
can produce excellent PRNG with even smaller internal state. But not
very fast one. Although the speed depends on specifics of used
computer. I can imagine computer that has low-latency Rijndael128 instruction. On such computer, running counter through 3-4 rounds of
Rijndael ill produce very good PRNG that is only 2-3 times slower than,
for example, LCG 128/64.
Michael S <already5chosen@yahoo.com> wrote:
On Tue, 23 Dec 2025 17:54:05 -0000 (UTC)
antispam@fricas.org (Waldek Hebisch) wrote:
Michael S <already5chosen@yahoo.com> wrote:
On Mon, 22 Dec 2025 18:41:10 +0100
Janis Papanagnou <janis_papanagnou+ng@hotmail.com> wrote:
Also, the TestU01 suit is made for generators with 32-bit output.
M. O’Neill used ad hoc technique to make it applicable to generators
with 64-bit output. Is this technique right? Or may be it put 64-bit
PRNG at unfair disadvantage?
My point of view is that generator can be used to generate long
bistream. Then you can cut the bitstream and get number of
desired size. Good tests should check that such usage leads
to reasonable properties. So, fact that one generator produces
32-bit pieces and other produces 64-bit pieces should be irrelevant
to the test.
Besides, I strongly disagree with at least one assertion made by
O’Neill: "While security-related applications should
use a secure generator, because we cannot always know the future
contexts in which our code will be used, it seems wise for all
applications to avoid generators that make discovering their entire internal state completely trivial."
No, I know exactly what I am doing/ I know exactly that for my
application easy discovery of complete state of PRNG is not a
defect.
O’Neill is not a prophet, ignore what she say it you think you
know better (which is probably the above).
Anyway, even if I am skeptical about her criticism of popular PRNGs, intuitively I agree with the constructive part of the article - medium-quality PRNG that feeds medium quality hash function can
potentially produce very good fast PRNG with rather small internal
state.
She seem to care very much about having minimal possible state.
That is may be nice on embeded systems, but in general I would
happily accept slighty bigger state (say 256 bits). But if
we can get good properties with very small state, then why not?
After all looking at state and updating it takes code, so
small state helps with having fast generator.
Concerning Mersenne Twister, she is not the only one toOne theoretical advantage of MT19937 is that it has period of astronomic proportions. Which means that one instance of PRNG could be
criticise it. My personal opinion is that given large
state and not so simple update Mersenne Twister would
have to be very very good to justify its use.
But it
fails some tests, so does not look _better_ than other
generators.
On related note, I think that even simple counter fed into high
quality hash function (not cryptographically high quality, far less
than that) can produce excellent PRNG with even smaller internal
state. But not very fast one. Although the speed depends on
specifics of used computer. I can imagine computer that has
low-latency Rijndael128 instruction. On such computer, running
counter through 3-4 rounds of Rijndael ill produce very good PRNG
that is only 2-3 times slower than, for example, LCG 128/64.
Maybe.
Michael S <already5chosen@yahoo.com> wrote:
On Mon, 22 Dec 2025 18:41:10 +0100
Janis Papanagnou <janis_papanagnou+ng@hotmail.com> wrote:
On 2025-12-22 18:13, James Kuyper wrote:
On 2025-12-22 07:18, Janis Papanagnou wrote:
On 2025-12-22 12:44, James Kuyper wrote:
On 2025-12-22 03:48, Michael Sanders wrote:
Is it incorrect to use 0 (zero) to seed srand()?
int seed = (argc >= 2 && strlen(argv[1]) == 9)
? atoi(argv[1])
: (int)(time(NULL) % 900000000 + 100000000);
srand(seed);
No, why whould you think so?
There's number sequence generators that produce 0 sequences if
seeded with 0. ...
The details of how the seed affects the random number sequence are
unspecified by the standard. I personally would consider a
pseudo-random number generator to be quite defective if there were
any seed that produced a constant output.
I wouldn't have mentioned that if there weren't a whole class of
such functions that expose exactly that behavior by design. Have
a look for PN-(Pseudo Noise-)generators and LFSR (Linear Feedback
Shift Registers). These have been defined to produce random noise
(bit pattern with good statistical distribution). With sophisticated
generator polynomials they produce also sequences of maximum period;
say, for N=31 a non-repeating sequence of length 2^N - 1. The one
element that is missing from the sequence is the 0 (that reproduces
itself).
Technically you pick some bit-values from fixed positions (depending
on the generator polynomial) of the register and xor the bits to shift
the result into the register. Here's ad hoc an example...
#include <stdio.h>
#include <stdint.h>
int main ()
{
uint32_t init = 0x00000038;
uint32_t reg = init;
uint32_t new_bit;
int count = 0;
do {
new_bit = ((reg >> 2) + (reg >> 4) + (reg >> 6) + (reg >>
30)) & 0x1;
reg <<= 1;
reg |= new_bit;
reg &= 0x7fffffff;
count++;
} while (reg != init);
printf ("period: %d\n", count);
}
Janis
[...]
Pay attention that C Standard only requires for the same seed to always
produces the same sequence. There is no requirement that different
seeds have to produce different sequences.
So, for generator in your example, implementation like below would be
fully legal. Personally, I wouldn't even consider it as particularly
poor quality:
void srand(unsigned seed ) { init = seed | 1;}
[O.T.]
In practice, using LFSR for rand() is not particularly bright idea for
different reason: LFSR is a reasonably good PRNG for a single bit, but
not when you want to generate a group of 31 pseudo-random bits. In
order to get 31 new bits, without predictable repetitions from the
previous value, you would have to do 31 steps. That's slow! The process
can be accelerate by generation of several bits at time via look up
tables, but in order to get decent speed the table has to be rater big
and using big tables in standard library is bad sportsmanship.
It seems that overwhelming majority C RTLs use Linear Congruential
Generators, probably because for Stanadard library compactness of both
code and data is considered more important than very high speed (not
that on modern HW LCGs are slow) or superior random properties of
Mersenne Twisters.
There is a paper "PCG: A Family of Simple Fast Space-Efficient
Statistically Good Algorithms for Random Number Generation"
by M. O’Neill where she gives a family of algorithms and runs
several statistical tests against known algorithms. Mersenne
Twister does not look good in tests. If you have enough (128) bits
LCGs do pass tests. A bunch of generators with 64-bit state also
passes tests. So the only reason to prefer Mersenne Twister is
that it is implemented in available libraries. Otherwise it is
not so good, have large state and needs more execution time
than alternatives.
Wish there was such a 'device' under Windows...
You should get one if you install WSL2.
Ike Naar <ike@sdf.org> wrote:
On 2025-12-23, John McCue <jmclnx@gmail.com.invalid> wrote:
Michael Sanders <porkchop@invalid.foo> wrote:
Is it incorrect to use 0 (zero) to seed srand()?
int seed = (argc >= 2 && strlen(argv[1]) == 9)
? atoi(argv[1])
: (int)(time(NULL) % 900000000 + 100000000);
srand(seed);
I like to just read /dev/urandom when I need a random
number. Seem easier and more portable across Linux &
the *BSDs.
int s;
read(fd, &s, sizeof(int));
srand takes an unsigned argument.
unsigned s;
read(fd, &s, sizeof s);
I am not quite sure what you are saying about srand(3).
If you decide to read /dev/urandom, there is no need to
call srand(3), the OS maintains random data itself. So
read(2) will just return the random number of the type
you want based upon the call.
On Tue, 23 Dec 2025 07:25:42 -0000 (UTC)
Michael Sanders <porkchop@invalid.foo> wrote:
On Tue, 23 Dec 2025 00:39:49 -0000 (UTC), John McCue wrote:
I like to just read /dev/urandom when I need a random
number. Seem easier and more portable across Linux &
the *BSDs.
int s;
read(fd, &s, sizeof(int));
Thanks John. Wish there was such a 'device' under Windows...
There is.
Windows XP/Vista/7: https://learn.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptgenrandom
Win8 and later: https://learn.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptgenrandom
On 12/22/2025 12:48 AM, Michael Sanders wrote:
Is it incorrect to use 0 (zero) to seed srand()?
int seed = (argc >= 2 && strlen(argv[1]) == 9)
? atoi(argv[1])
: (int)(time(NULL) % 900000000 + 100000000);
srand(seed);
Forgive me for C++, but this RNG of mine might be useful for detecting
the state of a system:
https://groups.google.com/g/comp.lang.c++/c/7u_rLgQe86k/m/fYU9SnuAFQAJ
Michael Sanders <porkchop@invalid.foo> writes:
On Mon, 22 Dec 2025 13:18:19 +0100, Janis Papanagnou wrote:
There's number sequence generators that produce 0 sequences if seeded
with 0. And maybe the comment in 'man 3 rand', "If no seed value is
provided, the rand() function is automatically seeded with a value
of 1.", may have fostered his doubt.
Janis - naive question for you...
How do I bring up *posix only* man pages using 3?
I see no difference when invoking any of:
man 3 srand
or: man 3 posix srand
or: man posix 3 srand
What I'm doing wrong here?
You're looking in the wrong place.
https://pubs.opengroup.org/onlinepubs/9799919799/
Select <System Interface> in the top left frame,
select (3) in the subsequent bottom left frame and
select the interface name in the bottom left frame. The
manual page will be in the right frame.
https://pubs.opengroup.org/onlinepubs/9799919799/functions/rand.html
On Wed, 24 Dec 2025 10:51:14 +0200, Michael S wrote:
On Tue, 23 Dec 2025 07:25:42 -0000 (UTC)
Michael Sanders <porkchop@invalid.foo> wrote:
On Tue, 23 Dec 2025 00:39:49 -0000 (UTC), John McCue wrote:
I like to just read /dev/urandom when I need a random
number. Seem easier and more portable across Linux &
the *BSDs.
int s;
read(fd, &s, sizeof(int));
Thanks John. Wish there was such a 'device' under Windows...
There is.
Windows XP/Vista/7: https://learn.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptgenrandom
Win8 and later: https://learn.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptgenrandom
Was referring to the concept of a device in the same idiom of BSD/Linux/Apple...
Something that is just as easy to use.
On Wed, 24 Dec 2025 15:28:24 -0000 (UTC)
Michael Sanders <porkchop@invalid.foo> wrote:
On Wed, 24 Dec 2025 10:51:14 +0200, Michael S wrote:
On Tue, 23 Dec 2025 07:25:42 -0000 (UTC)
Michael Sanders <porkchop@invalid.foo> wrote:
On Tue, 23 Dec 2025 00:39:49 -0000 (UTC), John McCue wrote:
I like to just read /dev/urandom when I need a random
number. Seem easier and more portable across Linux &
the *BSDs.
int s;
read(fd, &s, sizeof(int));
Thanks John. Wish there was such a 'device' under Windows...
There is.
Windows XP/Vista/7:
https://learn.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptgenrandom
Win8 and later:
https://learn.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptgenrandom
Was referring to the concept of a device in the same idiom of
BSD/Linux/Apple...
Something that is just as easy to use.
What is not easy in the functions referred above? You do the same
couple of steps as on Unix: open device then read few bytes from it.
Only names are different.
Unix:
$ head -c 8 /dev/urandom | od -An | tr -d ' '
4fa2c3d17b9a8f12
Windows:
PS C:\Users\Bob>
$bytes = New-Object byte[] 8 [System.Security.Cryptography.RandomNumberGenerator]::Create().GetBytes($bytes)
[Console]::Write($bytes | ForEach-Object { "{0:x2}" -f $_ })
My aims (mostly just learning my around C at this point)
are *much* more simple. I needed something that is seed-able/deterministic/portable allowing the user a
shot at replaying a round in a silly game I've been
working on every now & again:
int genseed(int seed_in) {
if (seed_in >= 10000000) return seed_in;
unsigned long t = (unsigned long)time(NULL);
unsigned long c = (unsigned long)clock();
return (int)(((t ^ c) % 80000000UL) + 10000000UL);
}
On Wed, 24 Dec 2025 15:28:24 -0000 (UTC)
Michael Sanders <porkchop@invalid.foo> wrote:
On Wed, 24 Dec 2025 10:51:14 +0200, Michael S wrote:
On Tue, 23 Dec 2025 07:25:42 -0000 (UTC)
Michael Sanders <porkchop@invalid.foo> wrote:
On Tue, 23 Dec 2025 00:39:49 -0000 (UTC), John McCue wrote:
I like to just read /dev/urandom when I need a random
number. Seem easier and more portable across Linux &
the *BSDs.
int s;
read(fd, &s, sizeof(int));
Thanks John. Wish there was such a 'device' under Windows...
There is.
Windows XP/Vista/7:
https://learn.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptgenrandom
Win8 and later:
https://learn.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptgenrandom
Was referring to the concept of a device in the same idiom of
BSD/Linux/Apple...
Something that is just as easy to use.
What is not easy in the functions referred above? You do the same
couple of steps as on Unix: open device then read few bytes from it.
Only names are different.
On 2025-12-24 17:17, Michael Sanders wrote:
Unix:
$ head -c 8 /dev/urandom | od -An | tr -d ' '
4fa2c3d17b9a8f12
Windows:
PS C:\Users\Bob>
$bytes = New-Object byte[] 8
[System.Security.Cryptography.RandomNumberGenerator]::Create().GetBytes($bytes)
[Console]::Write($bytes | ForEach-Object { "{0:x2}" -f $_ })
Amazing! 8-o
Or rather; frightening! ("The little Shop of Horrors")
A mixture (best/worst) of all; OO, Functional, and Shell?
What is that; "Powershell", or something else?
(I've mostly ignored Windows during the past 20+ years.)
Janis
witness: echo hello world? | | tr 'A-Za-z' 'N-ZA-Mn-za-m'
On Wed, 24 Dec 2025 17:27:32 -0000 (UTC), Michael Sanders wrote:
witness: echo hello world? | | tr 'A-Za-z' 'N-ZA-Mn-za-m'
typo, should be: echo hello world? | tr 'A-Za-z' 'N-ZA-Mn-za-m'
set a= 10000001000000000
set /A ab= %a% * 1000
set /A ab= %a% * 20002000000000
set /A ab= %a% * 3000-1294967296
On Wed, 24 Dec 2025 06:16:51 -0000 (UTC), Lawrence D’Oliveiro wrote:
Wish there was such a 'device' under Windows...
You should get one if you install WSL2.
To be fair there is the 'Windows entropy pool' & its
non-deterministic too but its only available via API.
| Sysop: | DaiTengu |
|---|---|
| Location: | Appleton, WI |
| Users: | 1,090 |
| Nodes: | 10 (0 / 10) |
| Uptime: | 45:18:14 |
| Calls: | 13,946 |
| Calls today: | 3 |
| Files: | 187,034 |
| D/L today: |
8,061 files (2,942M bytes) |
| Messages: | 2,460,942 |