Java: 0 <= x <n aralığında rastgele uzun sayı


135

Rasgele sınıfın belirli bir aralıkta rasgele int üretme yöntemi vardır. Örneğin:

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

Bu, 0'a 100 veya daha küçük bir int numarası üretecektir. Uzun sayıyla tam olarak aynı şeyi yapmak istiyorum.

long y = magicRandomLongGenerator(100);

Rasgele sınıfın yalnızca nextLong () öğesi vardır, ancak aralığın ayarlanmasına izin vermez.



1
Sadece uzun rasgele olmayı ve aralığınızın modunu almayı düşündünüz mü? (Tabii ki, aralık sadece 100 ise rastgele bir int üretip uzun süre
— dökerdim

java.util.Randomyalnızca 48 bit dağıtım kullanır (uygulama ayrıntılarına bakın), bu nedenle normal bir dağıtım olmaz.
— Geoffrey De Smet

1
Modern günlerde org.apache.commons.lang3.RandomUtils # nextLong kullanmayı düşünebilirsiniz.
— reallynice

Yanıtlar:


149

Java 7'den (veya Android API Seviye 21 = 5.0+) başlayarak ThreadLocalRandom.current().nextLong(n)(0 ≤ x <n için) ve ThreadLocalRandom.current().nextLong(m, n)(m ≤ x <n için) doğrudan kullanabilirsiniz . Ayrıntılar için @Alex'in cevabına bakınız .


Java 6 (veya Android 4.x) ile sıkışmışsanız, harici bir kitaplık kullanmanız gerekir (örneğin org.apache.commons.math3.random.RandomDataGenerator.getRandomGenerator().nextLong(0, n-1), @mawaldne'nin cevabına bakın) veya kendi kitaplığınızı uygulamanız gerekir nextLong(n).

Göre https://docs.oracle.com/javase/1.5.0/docs/api/java/util/Random.html nextInt olarak uygulanır

 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;
 }

Bu yüzden bunu gerçekleştirmek için değiştirebiliriz 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 denetleme" bölümü ile ilgili bazı sorunlar yaşıyorum. Herhangi bir fikir?
— Vilius Normantas

@Vilius: 2 ^ x denetimi nesli daha hızlı yapar çünkü doğrudan kullanarak rng.nextLong() % ntekdüze değerler verilecektir (tüm bitlerin iyi olduğunu varsayın). İsterseniz bu kısmı göz ardı edebilirsiniz.
— kennytm

Ben istiyorsanız m <= x <= n, nasıl size çözüm değiştirebilir ki?
— BJ Peter DeLaCruz

6
@BJPeterDeLaCruz: mve arasında rastgele bir sayı ile arasında rastgele bir sayı nelde edilebilir 0ve n-msonra ekleyin m.
— kennytm

84

ThreadLocalRandom

ThreadLocalRandombir nextLong(long bound)yöntemi vardır.

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

Ayrıca nextLong(long origin, long bound)0 dışında bir kaynağa ihtiyacınız varsa vardır. Başlangıç (dahil) ve sınır (özel) geçin.

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

SplittableRandomaynı nextLongyöntemlere sahiptir ve tekrarlanabilir bir sayı dizisi istiyorsanız bir tohum seçmenize izin verir.


5
Bu cevap en çok oylanandan daha basit ve bu nedenle daha kullanışlıdır.
— yurin

2
Android için geliştirenler için, yalnızca API 21'den (Lollipop, Android 5.0) kullanılabilir olduğuna dikkat edin: developer.android.com/reference/java/util/concurrent/…
— android geliştiricisi

75

Bir aralıkta sayı (bir yardımcı program yöntemi olmadan) oluşturmak için standart yöntem, yalnızca aralıkla çiftini kullanmaktır:

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

size 0 (dahil) ve aralık (hariç) arasında uzun bir süre verir. Benzer şekilde x ile y arasında bir sayı istiyorsanız:

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

size 1234567 (dahil) ile 123456789 (özel) arasında uzun bir zaman verecektir

Not: parantezleri kontrol edin, çünkü uzun süre yayınlamanın çarpma işleminden daha yüksek önceliği vardır.


5
İlk fikrim aynen buydu. Ama biraz yetersiz görünüyor. Ve dağılımın homojenliği konusunda endişeliyim (gerçekten ihtiyacım olduğu için değil, sadece doğru yapmak istiyorum)
— Vilius Normantas

6
Lütfen bunu asla kullanmayın. Çıktı hiç düzgün değil.
— Navin

2
En büyük sorun, yuvarlamanın en düşük biti çok düzgün yapmamasıdır. Ayrıca, boundbir çift, 2 ^ 53 kodlanabilir en büyük tamsayıdan daha az olması gerekir.
— Aleksandr Dubinsky

12

Yukarıdaki yöntemler harika çalışıyor. Apache commons (org.apache.commons.math.random) kullanıyorsanız RandomData'ya bakın. Bir yöntemi vardır: nextLong (uzun alt, uzun üst)

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
Posterity için: RandomData 4.0'da kullanımdan kaldırıldı. Commons.apache.org/proper/commons-math/apidocs/org/apache/…
— Michael Tontchev

11

'%' Operatörünü kullanma

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

'%' Operatörünü kullanarak, maksimum değerinize bölündüğünüzde kalanını alırız. Bu bizi sadece 0 (dahil) ile bölen (özel) arasında sayılar bırakır.

Örneğin:

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

Bu güzel, ama kontrol etmelisinizif (max == min)
— khcpietro

Ve ayrıca kontrolif (nextLong() >= 0)
— khcpietro

6
FYI: Bu her zaman tek tip bir dağılım sağlamaz ve bazı geniş aralıklar için gerçekten kötüdür. Örneğin, eğer min = 0ve max = 2 * (MAX_LONG / 3), o zaman iki kat daha olasıdır bir değer elde etmek [0, MAX_LONG / 3]sen almak için ne kadar [MAX_LONG / 3, 2 * (MAX_LONG / 3)].
— Nick

Bu kod çalışmaz. Eğer nextLongdöner negatif bir değer, kalan negatif olur ve değer aralığının dışında olacaktır.
— Arnaud

3

Kennytm'in cevabını daha da iyileştirmek: Java 8'deki asıl uygulamayı dikkate alan bir alt sınıf uygulaması şöyle olacaktır:

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;
  }
}

Bunun eski bir cevap olduğunu ve kullanılmasının pek mümkün olmadığını biliyorum, ancak bu bölüm açıkça yanlış: if ((bound & m) == 0) { r = (bound * r) >> (Long.SIZE - 1); } İlk olarak, birim testlerinde bunun aslında [0, bağlı) aralığında sayı üretmediğini göstermek kolaydır. İkincisi, gereksiz yere ayrıntılıdır: r = r & mistenen sonucu elde eder ve temel olarak mevcut Java 8 uygulamasının yaptığı budur. Bu cevap yazıldığında uygulamanın farklı olması mümkündür, ancak gösterilen şey bu olamaz.
— E Bishop

3

[0, m) aralığında eşit olarak dağıtılmış bir takma ad istiyorsanız , modulo operatörünü ve aşağıdaki yöntemle birlikte mutlak değer yöntemini kullanmayı deneyin nextLong():

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

randRastgele nesneniz nerede .

Modulo operatörü iki sayıyı böler ve bu sayıların kalanını verir. Örneğin, 3 % 2bir 13 ve 2'nin kalan 1'dir.

Yana nextLong()aralığında uzun bir düzgün dağılmış yalancı rasgele oluşturur [- (2 ^ 48) ^ 48 2) (ya da bir yere bu aralıkta), bunun mutlak değerini almak gerekir. Bunu yapmazsanız, nextLong()yöntemin modulo'unun negatif değer döndürme şansı% 50'dir ve bu değer [0, m) aralığının dışındadır .

Başlangıçta talep ettiğiniz şey, [0,100) aralığında eşit olarak dağıtılmış bir takma ad idi. Aşağıdaki kod bunu yapar:

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

1
modulo önyargılı, rastgele için kullanmayın stackoverflow.com/a/10984975/1166266
— Sirens

2

Buna ne dersin:

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;
}

?


Bir çerçeveye ait parçalar hariç sanırım (sanırım).
— Damir Olejar

2

Aşağıdaki yöntem size 10000000000 ila 9999999999 arasında bir değer döndürür

long min = 1000000000L
long max = 9999999999L    

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

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

}

Uzun min = 1L sıfırladığımda; uzun max = 10L; Ortaya çıkan rastgele sayı maksimum değerin ötesine geçer!
— Raj Rajen

Random.nextLong ()% (max - min) + min olmalıdır;
— Jay Jodiwal

2

Gönderen Java 8 API

Gerçek dokümanı API belgesinden almak daha kolay olabilir https://docs.oracle.com/javase/8/docs/api/java/util/Random.html#longs-long-long-long- bunu kullanıyorlar uzun ürün akışı üret. Ve kaynağınız sorudaki gibi "0" olabilir.

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

Rastgele sayfadan :

NextLong yöntemi, Rastgele sınıfı tarafından şu şekilde uygulanır:

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

Random sınıfı yalnızca 48 bitlik bir tohum kullandığından, bu algoritma olası tüm uzun değerleri döndürmez.

Eğer bir almak Longistiyorsanız, zaten 64 bit aralığının tamamını elde edemezsiniz.

2 gücüne yakın bir aralığınız varsa Long, bu snippet'teki gibi oluşturduğunuzu öneririm :

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

Örneğin, 35 bitlik bir aralık elde etmek için.


2
Ancak belgelerde "Tüm 2 ^ 64 olası uzun değerlerin tümü (yaklaşık) eşit olasılıkla üretilir." Görünüşe göre nextLong () yöntemi tüm olası değerleri döndürmelidir. Btw, tohumun uzunluğu değerlerin dağılımı ile ilişkilidir?
— Vilius Normantas

0

Kullanılması r.nextDouble()gereken yöntemler :

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
Hoc'de Randomörnekler oluşturmamalısınız , gerekirse Throwables veya diğer istisnaları yakalamamalısınız , hataları kullanmak yerine bir tür günlükleme çerçevesiyle (yani SLF4J) günlüğe kaydetmelisiniz printStackTrace.
— Boguś

0

Java akışlarını kullanabiliyorsanız aşağıdakileri deneyebilirsiniz:

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);
});

Bu, verilen aralıkta uzun süre sayı üretecektir.


0
import java.util*;

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

Bu çalışmalı


-4

// iyi bir rasgele sayı elde etmek için sistem zamanını tohum değeri olarak kullan

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

// 0'dan büyük veya ona eşit ve n'den küçük bir sayı alana kadar döngü yap


1
Bu aşırı derecede yetersiz olabilir. n1 veya 2 ise ne olur ? Döngü birçok yineleme gerçekleştirecektir .
— Magnilex
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.