2

In Java I wish to generate a randomly picked long number within an exclusive upper bound.

Normally if it were an Int I could do

int nextInt = new SecureRandom.nextInt(500);

Why can't I also do

long nextLong = new SecureRandom.nextLong(4294967296L);

Is there a work around to this?

Thanks

Michiel Leegwater
  • 1,172
  • 4
  • 11
  • 27
mekings
  • 361
  • 3
  • 17
  • 2
    Possible duplicate of [Java: random long number in 0 <= x < n range](https://stackoverflow.com/questions/2546078/java-random-long-number-in-0-x-n-range) – Marvin Sep 26 '19 at 19:29
  • Also: https://stackoverflow.com/questions/44278281/why-there-is-no-nextdouble-nextfloat-and-nextlong-which-accept-a-bound-in – Marvin Sep 26 '19 at 19:29
  • The accepted answer of the dupe question won't work, but the second answer ([Java: random long number in 0 <= x < n range](//stackoverflow.com/a/2546158)). – Tom Sep 26 '19 at 19:31
  • Thanks for all your inputs. However, I am more interested in a Cryptographically secured approach. I think `ThreadLocalRandom` isn't cryptographically secured. Please correct me if I am wrong. – mekings Sep 26 '19 at 19:39
  • That's why I said you should use the other answer (the one I've linked). That uses `Random`, but would work with `SecureRandom` as well. – Tom Sep 26 '19 at 19:46
  • 1
    @Tom as the comments say, that version is not uniform distributed. If you want Secure you definitly want uniform. – k5_ Sep 26 '19 at 19:48
  • Probably, as workaround you can use `SecureRandom.longs` method introduced in Java 8. I added more details in the answer below. – Oleksii Zghurskyi Sep 26 '19 at 20:00

2 Answers2

3

Probably, as workaround you can use longs method introduced in Java 8. So, if you need to get SecureRandom long value in the range [minLong, maxLong], one approach would be:

long minLong = -1L;
long maxLong = 4294967296L;

long boundedLong = 
     new SecureRandom()
        .longs(minLong, maxLong + 1)
        .findFirst()
        .getAsLong();

Oleksii Zghurskyi
  • 3,967
  • 1
  • 16
  • 17
0

Does it have to be a SecureRandom?

If not, then you have two easy options, using nextLong​(long bound) of SplittableRandom or ThreadLocalRandom:

long nextLong = new SplittableRandom().nextLong(4294967296L);

long nextLong = ThreadLocalRandom.current().nextLong(4294967296L);

UPDATE

If it has to be SecureRandom, you can always copy the code of those two methods, which are implemented the same (below copied from Java 11):

public static long nextLong(SecureRandom random, long bound) {
    if (bound <= 0)
        throw new IllegalArgumentException(BadBound);
    long r = random.nextLong();
    long m = bound - 1;
    if ((bound & m) == 0L) // power of two
        r &= m;
    else { // reject over-represented candidates
        for (long u = r >>> 1;
             u + m - (r = u % bound) < 0L;
             u = random.nextLong() >>> 1)
            ;
    }
    return r;
}

That should answer the question "Is there a work around to this?", since writing your own code is a valid workaround.

Andreas
  • 154,647
  • 11
  • 152
  • 247
  • Why to bother copying method implementations if `SecureRandom` API already has bonded versions like [`longs`](https://docs.oracle.com/javase/8/docs/api/java/util/Random.html#longs-long-long-long-) ? See [answer](https://stackoverflow.com/questions/58123495/how-to-specify-a-maximum-value-in-javas-securerandom-nextlong/58123834#58123834) below for more details. – Oleksii Zghurskyi Sep 26 '19 at 20:35
  • @Zgurskyi Because you had already given that answer, so I'm providing an alternative to using streams. – Andreas Sep 27 '19 at 00:14