자바 : 0 <= x <n 범위의 임의의 긴 숫자


135

Random 클래스에는 주어진 범위에서 random int를 생성하는 메소드가 있습니다. 예를 들면 다음과 같습니다.

Random r = new Random(); 
int x = r.nextInt(100);

이것은 0 이상 100 이하의 int 숫자를 생성합니다. 긴 숫자와 똑같이하고 싶습니다.

long y = magicRandomLongGenerator(100);

임의 클래스에는 nextLong () 만 있지만 범위를 설정할 수 없습니다.



1
당신은 당신의 긴 무작위를 얻고 범위의 모드를 취하는 것을 고려 했습니까? (물론, 범위가 100에 불과하다면 int 랜덤을 생성하여 길게 캐스트 할 것입니다.)
Hot Licks

java.util.Random48 비트 배포 만 사용하므로 (구현 세부 사항 참조) 정규 배포가 없습니다.
Geoffrey De Smet

1
현대에는 org.apache.commons.lang3.RandomUtils # nextLong 사용을 고려할 수 있습니다.
reallynice

답변:


149

에서 시작 자바 7 직접 사용할 수 있습니다 (또는 = 5.0 안드로이드 API 레벨 21) ThreadLocalRandom.current().nextLong(n)(≤ X <N 0)과 ThreadLocalRandom.current().nextLong(m, n)(≤ X <N m)입니다. 자세한 내용은 @Alex 의 답변을 참조하십시오 .


Java 6 (또는 Android 4.x) 이 붙어 있다면 외부 라이브러리 (예 : @mawaldne 의 답변 org.apache.commons.math3.random.RandomDataGenerator.getRandomGenerator().nextLong(0, n-1)참조 )를 사용하거나 직접 구현해야합니다 .nextLong(n)

에 따르면 https://docs.oracle.com/javase/1.5.0/docs/api/java/util/Random.html nextInt 로 구현됩니다

 public int nextInt(int n) {
     if (n<=0)
                throw new IllegalArgumentException("n must be positive");

     if ((n & -n) == n)  // i.e., n is a power of 2
         return (int)((n * (long)next(31)) >> 31);

     int bits, val;
     do {
         bits = next(31);
         val = bits % n;
     } while(bits - val + (n-1) < 0);
     return val;
 }

그래서 우리는 이것을 수행하도록 수정할 수 있습니다 nextLong:

long nextLong(Random rng, long n) {
   // error checking and 2^x checking removed for simplicity.
   long bits, val;
   do {
      bits = (rng.nextLong() << 1) >>> 1;
      val = bits % n;
   } while (bits-val+(n-1) < 0L);
   return val;
}

1
"2 ^ x 점검"부분에 문제가 있습니다. 어떤 아이디어?
Vilius Normantas

@Vilius : 2 ^ x 검사는 직접 사용 rng.nextLong() % n하면 균일 한 값을 제공 하기 때문에 생성 속도가 빨라집니다 (모든 비트가 양호하다고 가정). 원하는 경우 해당 부분을 무시할 수 있습니다.
kennytm

원하는 경우 m <= x <= n솔루션을 어떻게 수정 하시겠습니까?
BJ Peter DeLaCruz

6
@BJPeterDeLaCruz : (A)은 임의의 수 사이 mn사이의 난수를 얻을 수있다 0하고 n-m, 다음에 추가 m.
kennytm

84

ThreadLocalRandom

ThreadLocalRandom갖는 nextLong(long bound)방법.

long v = ThreadLocalRandom.current().nextLong(100);

nextLong(long origin, long bound)0 이외의 원점이 필요한 경우 도 있습니다 . 원점 (포함) 및 바운드 (제외)를 전달하십시오.

long v = ThreadLocalRandom.current().nextLong(10,100); // For 2-digit integers, 10-99 inclusive.

SplittableRandom동일한 nextLong방법을 사용하고 재현 가능한 일련의 숫자를 원할 경우 시드를 선택할 수 있습니다.


5
이것은 가장 투표가 많은 것보다 훨씬 간단하고 더 유용합니다.
yurin

2
Android 용으로 개발하는 사용자는 API 21 (Lollipop, Android 5.0)에서만 사용할 수 있습니다. developer.android.com/reference/java/util/concurrent/…
android developer

75

범위에서 숫자를 생성하는 표준 방법 (유틸리티 방법 없음)은 범위와 함께 double을 사용하는 것입니다.

long range = 1234567L;
Random r = new Random()
long number = (long)(r.nextDouble()*range);

0 (포함)과 범위 (제외) 사이의 긴 값을 제공합니다. 마찬가지로 x와 y 사이의 숫자를 원하는 경우 :

long x = 1234567L;
long y = 23456789L;
Random r = new Random()
long number = x+((long)(r.nextDouble()*(y-x)));

1234567 (포함)부터 123456789 (제외)까지의 길이를 제공합니다

참고 : long으로 캐스트하는 것이 곱셈보다 우선 순위가 높으므로 괄호를 확인하십시오.


5
내 첫 번째 아이디어는 정확히 이것입니다. 그러나 약간 우아하지 않은 것 같습니다. 그리고 분포의 균일성에 대해 걱정하고 있습니다 (실제로 필요
하지는 않지만

6
절대 사용하지 마십시오. 출력이 전혀 균일하지 않습니다.
Navin

2
가장 큰 문제는 반올림이 가장 낮은 비트를 매우 불균일하게 만드는 것입니다. 또한 bound2 ^ 53의 이중으로 인코딩 할 수있는 가장 큰 정수보다 작아야합니다.
Aleksandr Dubinsky 12

12

위의 방법은 훌륭하게 작동합니다. 아파치 커먼즈 (org.apache.commons.math.random)를 사용한다면 RandomData를 확인하십시오. 방법이 있습니다 : nextLong (long lower, long upper)

http://commons.apache.org/math/userguide/random.html

http://commons.apache.org/math/api-1.1/org/apache/commons/math/random/RandomData.html#nextLong(long,%20long)


3
후손의 경우 : RandomData는 4.0에서 더 이상 사용되지 않습니다. 사용 commons.apache.org/proper/commons-math/apidocs/org/apache/...
마이클 Tontchev

11

'%'연산자를 사용하십시오.

resultingNumber = (r.nextLong() % (maximum - minimum)) + minimum;

'%'연산자를 사용하면 나머지를 최대 값으로 나눌 때 나머지를 가져옵니다. 이것은 0 (제외)부터 제수 (제외)까지의 숫자 만 남습니다.

예를 들면 다음과 같습니다.

public long randLong(long min, long max) {
    return (new java.util.Random().nextLong() % (max - min)) + min;
}

이것은 좋지만 확인해야합니다if (max == min)
khcpietro

또한 확인if (nextLong() >= 0)
khcpietro

6
참고로, 이것이 항상 균일 한 분포를 제공하는 것은 아니며 일부 큰 범위에서는 실제로 나쁩니다. 예를 들어 min = 0and 및 max = 2 * (MAX_LONG / 3)이면 값을 얻는 것보다 값을 얻을 가능성이 두 배 [0, MAX_LONG / 3]입니다 [MAX_LONG / 3, 2 * (MAX_LONG / 3)].
Nick

이 코드는 작동하지 않습니다. 경우 nextLong반환 음의 값, 나머지는 음수가 될 것이며, 값이 범위를 벗어난 것입니다.
Arnaud

3

kennyTM의 답변 개선 : Java 8의 실제 구현을 고려한 서브 클래스 구현은 다음과 같습니다.

public class MyRandom extends Random {
  public long nextLong(long bound) {
    if (bound <= 0) {
      throw new IllegalArgumentException("bound must be positive");
    }

    long r = nextLong() & Long.MAX_VALUE;
    long m = bound - 1L;
    if ((bound & m) == 0) { // i.e., bound is a power of 2
      r = (bound * r) >> (Long.SIZE - 1);
    } else {
      for (long u = r; u - (r = u % bound) + m < 0L; u = nextLong() & Long.MAX_VALUE);
    }
    return r;
  }
}

나는 이것이 오래된 대답이며 사용되지 않을 것이라는 것을 알고 있지만,이 부분은 명백히 부정확합니다 : if ((bound & m) == 0) { r = (bound * r) >> (Long.SIZE - 1); } 첫째, 단위 테스트를 통해 실제로 [0, bound) 범위의 숫자를 생성하지 않는다는 것을 쉽게 보여줄 수 있습니다. 둘째, 불필요하게 정교합니다. r = r & m원하는 결과를 얻을 수 있으며, 기본적으로 현재 Java 8 구현이하는 것입니다. 이 답변이 작성되었을 때 구현이 다를 수 있지만 표시 된 것은 불가능합니다.
E. 주교

3

[0, m) 범위에서 균일하게 분포 된 의사 난수를 원하면 모듈로 연산자와 절대 값 방법을 nextLong()아래에 표시된 방법과 결합하여 사용하십시오 .

Math.abs(rand.nextLong()) % m;

rand랜덤 오브젝트는 어디에 있습니까 ?

모듈로 연산자는 두 숫자를 나누고 나머지 숫자를 출력합니다. 예를 들어, 3 % 2이다 1(3)과 (2)의 나머지 하나이기 때문이다.

nextLong()[-(2 ^ 48), 2 ^ 48) 범위 (또는 해당 범위 어딘가)에서 균일하게 분포 된 의사 난수를 생성 하므로 절대 값을 가져와야합니다. 그렇지 않으면 nextLong()메소드 의 모듈로가 50 %의 확률로 [0, m) 범위를 벗어난 음수 값을 리턴합니다 .

처음에 요청한 것은 [0,100) 범위의 균일하게 분포 된 의사 난수입니다. 다음 코드는 그렇게합니다.

Math.abs(rand.nextLong()) % 100;

1
모듈로가 바이어스되어 무작위로 사용하지 마십시오. stackoverflow.com/a/10984975/1166266
Sirens

2

이건 어때요:

public static long nextLong(@NonNull Random r, long min, long max) {
    if (min > max)
        throw new IllegalArgumentException("min>max");
    if (min == max)
        return min;
    long n = r.nextLong();
    //abs (use instead of Math.abs, which might return min value) :
    n = n == Long.MIN_VALUE ? 0 : n < 0 ? -n : n;
    //limit to range:
    n = n % (max - min);
    return min + n;
}

?


프레임 워크에 속하는 부분을 제외하고는 괜찮습니다.
Damir Olejar

2

아래 방법은 10000000000에서 9999999999 사이의 값을 반환합니다.

long min = 1000000000L
long max = 9999999999L    

public static long getRandomNumber(long min, long max){

    Random random = new Random();         
    return random.nextLong() % (max - min) + max;

}

내가 긴 min = 1L을 재설정하면; 긴 최대 = 10L; 결과 난수는 최대 값을 초과합니다!
Raj Rajen

랜덤이어야합니다. nextLong () % (max-min) + min;
Jay Jodiwal

2

에서 자바 8 API

그것은에서 실제 구현 취할 쉽게 될 수있는 API의 문서를 https://docs.oracle.com/javase/8/docs/api/java/util/Random.html#longs-long-long-long- 그들은 그것을 사용하는 long 스트림을 생성합니다. 그리고 당신의 원점은 질문 에서처럼 "0"이 될 수 있습니다.

long nextLong(long origin, long bound) {
  long r = nextLong();
  long n = bound - origin, m = n - 1;
  if ((n & m) == 0L)  // power of two
    r = (r & m) + origin;
  else if (n > 0L) {  // reject over-represented candidates
    for (long u = r >>> 1;            // ensure nonnegative
         u + m - (r = u % n) < 0L;    // rejection check
         u = nextLong() >>> 1) // retry
        ;
    r += origin;
  }
  else {              // range not representable as long
    while (r < origin || r >= bound)
      r = nextLong();
  }
  return r;
}

1

랜덤 페이지에서 :

nextLong 메소드는 다음과 같이 Random 클래스에 의해 구현됩니다.

public long nextLong() {
   return ((long)next(32) << 32) + next(32);
}

Random 클래스는 48 비트 만있는 seed를 사용하므로이 알고리즘은 가능한 모든 long 값을 반환하지는 않습니다.

따라서을 얻으려면 Long이미 전체 64 비트 범위를 얻지 못합니다.

2의 거듭 제곱에 가까운 범위를 가지면 다음 Long과 같이 해당 스 니펫과 같이 범위를 구성하는 것이 좋습니다 .

next(32) + ((long)nextInt(8) << 3)

예를 들어 35 비트 범위를 얻으려면.


2
그러나 문서에 따르면 "2 ^ 64 가능한 모든 long 값은 거의 같은 확률로 생성됩니다." 따라서 nextLong () 메소드는 가능한 모든 값을 반환해야합니다. Btw, 시드의 길이는 값의 분포와 어떤 관련이 있습니까?
Vilius Normantas

0

를 사용하는 방법은 다음을 r.nextDouble()사용해야합니다.

long number = (long) (rand.nextDouble()*max);


long number = x+(((long)r.nextDouble())*(y-x));

0
public static long randomLong(long min, long max)
{
    try
    {
        Random  random  = new Random();
        long    result  = min + (long) (random.nextDouble() * (max - min));
        return  result;
    }
    catch (Throwable t) {t.printStackTrace();}
    return 0L;
}

1
Random인스턴스를 즉시 생성해서는 안되며 , 필요하지 않은 Throwable경우 또는 다른 예외를 포착해서는 안됩니다 printStackTrace. 를 사용하는 대신 일종의 로깅 프레임 워크 (예 : SLF4J)로 오류를 기록해야합니다 .
Boguś

0

Java 스트림을 사용할 수있는 경우 다음을 시도 할 수 있습니다.

Random randomizeTimestamp = new Random();
Long min = ZonedDateTime.parse("2018-01-01T00:00:00.000Z").toInstant().toEpochMilli();
Long max = ZonedDateTime.parse("2019-01-01T00:00:00.000Z").toInstant().toEpochMilli();
randomizeTimestamp.longs(generatedEventListSize, min, max).forEach(timestamp -> {
  System.out.println(timestamp);
});

이것은 주어진 범위에서 오랫동안 숫자를 생성합니다.


0
import java.util*;

    Random rnd = new Random ();
    long name = Math.abs(rnd.nextLong());

이 작동합니다


-4

// 좋은 임의의 숫자를 얻기 위해 시스템 시간을 시드 값으로 사용

   Random random = new Random(System.currentTimeMillis());
              long x;
             do{
                x=random.nextLong();
             }while(x<0 && x > n); 

// 0보다 크거나 같고 n보다 작을 때까지 루프


1
이것은 매우 비효율적 일 수 있습니다. 어떤 경우에는 n1, 2 말? 루프는 많은 반복 을 수행 합니다.
Magnilex
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.