0

Is there any (simple) random generation function that can work without variable assignment? Most functions I read look like this current = next(current). However currently I have a restriction (from SQLite) that I cannot use any variable at all.

Is there a way to generate a number sequence (for example, from 1 to max) with only n (current number index in the sequence) and seed?

Currently I am using this:

cast(((1103515245 * Seed * ROWID + 12345) % 2147483648) / 2147483648.0 * Max as int) + 1

with max being 47, ROWID being n. However for some seed, the repeat rate is too high (3 unique out of 47).

In my requirements, repetition is ok as long as it's not too much (<50%). Is there any better function that meets my need?

The question has sqlite tag but any language/pseudo-code is ok.

P.s: I have tried using Linear congruential generators with some a/c/m triplets and Seed * ROWID as Seed, but it does not work well, it's even worse.

EDIT: I currently use this one, but I do not know where it's from. The rate looks better than mine:

((((Seed * ROWID) % 79) * 53) % "Max") + 1

Luke Vo
  • 17,859
  • 21
  • 105
  • 181

3 Answers3

1

What about using good hash function and map result into [1...max] range?

Along the lines (in pseudocode). sha1 was added to SQLite 3.17.

sha1(ROWID) % Max + 1

Or use any external C code for hash (murmur, chacha, ...) as shown here

Severin Pappadeux
  • 18,636
  • 3
  • 38
  • 64
  • Sadly my `sqlite_version()` is 3.15.2, and I am in a sandbox environment and are not allowed to update/make any change to SQLite engine itself. Thanks anyway, this is a valid solution for people with less restriction than mine. – Luke Vo May 15 '19 at 15:59
  • @LukeVo Maybe there are loadable modules? I'm not very familiar with SQLite. Basically, any decent hash with good avalanche properties (https://en.wikipedia.org/wiki/Avalanche_effect) will do the job. – Severin Pappadeux May 15 '19 at 17:42
1

I am not sure if you still have the same problem but I might have a solution for you. What you could do is use Pseudo Random M-sequence generators based on shifting registers. Where you just have to take high enough order of you primitive polynomial and you don't need to store any variables really. For more info you can check the wiki page

What you would need to code is just the primitive polynomial shifting equation and I have checked in an online editor it should be very easy to do. I think the easiest way for you would be to use Binary base and use PRBS sequences and depending on how many elements you will have you can choose your sequence length. For example this is the implementation for length of 2^15 = 32768 (PRBS15), the primitive polynomial I took from the wiki page (There youcan find the primitive polynomials all the way to PRBS31 what would be 2^31=2.1475e+09) Basically what you need to do is:

SELECT (((ROWID << 1) | (((ROWID >> 14) <> (ROWID >> 13)) & 1)) & 0x7fff)

The beauty of this approach is if you take the sequence of the PRBS with longer period than your ROWID largest value you will have unique random index. Very simple. :)

If you need help with searching for primitive polynomials you can see my github repo which deals exactly with finding primitive polynomials and unique m-sequences. It is currently written in Matlab, but I plan to write it in python in next few days.

Cheers!

Antun Skuric
  • 126
  • 2
0

A linear congruential generator with appropriately-chosen parameters (a, c, and modulus m) will be a full-period generator, such that it cycles pseudorandomly through every integer in its period before repeating. Although you may have tried this idea before, have you considered that m is equivalent to max in your case? For a list of parameter choices for such generators, see L'Ecuyer, P., "Tables of Linear Congruential Generators of Different Sizes and Good Lattice Structure", Mathematics of Computation 68(225), January 1999.

Note that there are some practical issues to implementing this in SQLite, especially if your SQLite version supports only 32-bit integers and 64-bit floating-point numbers (with 52 bits of precision). Namely, there may be a risk of—

  • overflow if an intermediate multiplication exceeds 32 bits for integers, and
  • precision loss if an intermediate multiplication results in a greater-than-52-bit number.

Also, consider why you are creating the random number sequence:

  • Is the sequence intended to be unpredictable? In that case, a linear congruential generator alone is not enough, and you should generate unique identifiers by other means, such as by combining unique numbers with cryptographically random numbers.
  • Will the numbers generated this way be exposed in any way to end users? If not, there is no need to obfuscate them by "shuffling" them.

Also, depending on the SQLite API you're using (for your programming language), there may be a way to write a custom function to convert the seed and ROWID to a random unique number. The details, however, depend heavily on the specific SQLite API. Another answer shows an example for Perl.

Peter O.
  • 32,158
  • 14
  • 82
  • 96
  • The problem with LCG is I have never seen implementation that is not using variable (knowing x(n) without knowing x(n-1)). That's my main limitation now. As for programming language, I do not have access to it (it's in context of sandbox and I am giving only the DB) – Luke Vo May 15 '19 at 02:29
  • Is `max` a constant in your application (e.g., is it always the number 47)? Also, consider why you need to use "random" unique numbers, as opposed to just "unique" numbers. Will those numbers be exposed in any way to end users? Do the numbers have to be "unpredictable", or merely unique? Why can't you use sequential numbers or the `ROWID` number instead? – Peter O. May 15 '19 at 02:42
  • Ah sorry I forgot about those. Well, it's not about security, and it should be easy-going as long as acceptable result is obtainable. The max is not really constants but should usually be around 43-50 (but in some case may be higher, but not much). They don't have to be absolutely unique or random. – Luke Vo May 15 '19 at 02:47
  • Okay, then: Isn't the `ROWID` number enough for your purposes? If not, why not? – Peter O. May 15 '19 at 02:51
  • well... I need them to be random and can be reproducible given the same seed number. – Luke Vo May 15 '19 at 10:56
  • With a nonconstant `max` and your constraints, a linear congruential generator is not ideal, since a new formula has to be used for each value of `max` that you anticipate. (Perhaps the best you can do is choose an `m` close to the highest value for `max` that you expect, and use one of the parameter choices in L'Ecuyer 1999, or a custom choice found in the manner suggested in that paper.) I am also aware of linear feedback shift registers for unique pseudorandom numbers, but they only work for powers of 2, not arbitrary values for `max`. – Peter O. May 15 '19 at 12:28