简体   繁体   中英

what is the fastest way to get the nth nextInt value?

I have to find the nth nextInt of each array element. The code below is really slow as the array elements are over 40k, and each array element is over a million.

int[] numbers ={1000000,1004300,2204000,1306000...40k+};
for (int i = 0; i <numbers.length; i++) {
Random ran = new Random(1234);
    int nex = 0;
    for (int n = 0; n <numbers[i]; n++) {
        nex = ran.nextInt();
    }
    System.out.println("Next int value: " + nex);
}

Is there a faster way to get the 1 millionth nextInt? if yes please how?

You are setting the "seed" value of your random number generator. This means that it will produce the same sequence of random numbers every time this code runs, and so the sequence is predictable.

If you were truly generating random numbers, generating the millionth random number would be the same as generating the first random number, because no one could tell the difference between those two unpredictable results.

So, the first potential optimization is: don't use a predictable sequence, and take the first random number. This is would require a small, constant time.

Next, if you require this sort of repeatability, you could pre-compute them, and your code would include that table of results. Then you can look the results in constant time.

If you need a repeatable sequence that looks sort of random, but it doesn't have to be this particular sequence, you could use a different pseudo-random generator. For example, you could encrypt the "index" (1 million in your example) with a block cipher, and use some bytes from the result. This is also a constant time algorithm, regardless of the index.

Here's an implementation of the last idea:

public class PredictableSequenceGenerator {

  private final int[] numbers;

  public PredictableSequenceGenerator(int[] numbers) {
    this.numbers = Objects.requireNonNull(numbers);
  }

  public int[] generate(long seed) {
    ByteBuffer src = ByteBuffer.wrap(new byte[16]);
    ByteBuffer dst = ByteBuffer.wrap(new byte[16]);
    src.putLong(seed).putLong(seed);
    SecretKey key = new SecretKeySpec(src.array(), "AES");
    Cipher cipher;
    try {
      cipher = Cipher.getInstance("AES/ECB/NoPadding");
      cipher.init(Cipher.ENCRYPT_MODE, key);
    } catch (GeneralSecurityException ex) {
      throw new IllegalStateException("Failed to initialize generator.", ex);
    }
    int[] results = new int[numbers.length];
    for (int idx = 0; idx < numbers.length; ++idx) {
      src.clear();
      src.putInt(0, idx);
      dst.clear();
      try {
        cipher.doFinal(src, dst);
      } catch (GeneralSecurityException ex) {
        throw new IllegalStateException("Failed to transform index.", ex);
      }
      results[idx] = dst.flip().getInt();
    }
    return results;
  }

  public static void main(String... argv) {
    int[] numbers = { 1000000, 1004300, 2204000, 1306000, /* 40k+ */ };
    PredictableSequenceGenerator gen = new PredictableSequenceGenerator(numbers);
    int[] random = gen.generate(1234);
    for (int r : random)
      System.out.println(r);
  }

}

Do you really need the seed, so that the random sequence is the same every time? Then you could sort your numbers array ascending. Then for the second element you don't need to reset the random generator but can just continue where you left. This way you will have to call nextInt only as often as the highest number in your array is, instead of 40 billion times

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM