जावा: 0 <= x <n श्रेणी में यादृच्छिक लंबी संख्या


135

किसी श्रेणी में रैंडम int उत्पन्न करने के लिए रैंडम क्लास में एक विधि होती है। उदाहरण के लिए:

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

यह 0 से अधिक या 100 के बराबर एक int संख्या उत्पन्न करेगा। मैं लंबी संख्या के साथ बिल्कुल वैसा ही करना चाहूंगा।

long y = magicRandomLongGenerator(100);

रैंडम क्लास में केवल नेक्लांग () होता है, लेकिन यह रेंज सेट करने की अनुमति नहीं देता है।


संबंधित, उपयोगी हो सकता है: stackoverflow.com/questions/2290057/…
TJ Crowder

1
क्या आपने केवल अपने लंबे यादृच्छिक को प्राप्त करने और अपनी सीमा के मॉड को लेने पर विचार किया है? (बेशक, अगर रेंज केवल 100 है, तो मैं एक यादृच्छिक यादृच्छिक उत्पादन करूंगा और इसे लंबे समय तक कास्ट करूंगा।)
Hot Licks

java.util.Randomकेवल 48 बिट वितरण (कार्यान्वयन विवरण देखें) का उपयोग करता है, इसलिए इसका सामान्य वितरण नहीं होगा।
जेफ्री डी स्मेट

1
आधुनिक दिनों में कोई भी org.apache.commons.lang3.RandomUtils # nextLong का उपयोग करने पर विचार कर सकता है।
वास्तव में

जवाबों:


149

जावा 7 (या Android एपीआई स्तर 21 = 5.0+) से शुरू करके आप सीधे ThreadLocalRandom.current().nextLong(n)(0 <x <n के लिए) और ThreadLocalRandom.current().nextLong(m, n)(m for x <n के लिए) का उपयोग कर सकते हैं। विस्तार के लिए @Alex का उत्तर देखें ।


यदि आप जावा 6 (या एंड्रॉइड 4.x) के साथ फंस गए हैं, तो आपको एक बाहरी पुस्तकालय (उदाहरण के लिए org.apache.commons.math3.random.RandomDataGenerator.getRandomGenerator().nextLong(0, n-1), @mawaldne का उत्तर देखें ) का उपयोग करने की आवश्यकता है , या अपना खुद का कार्यान्वयन करें 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: 2 ^ x चेकिंग केवल पीढ़ी को तेज़ बनाता है क्योंकि सीधे उपयोग करने rng.nextLong() % nसे समान मूल्य मिलेंगे (मान लें कि सभी बिट अच्छे हैं)। आप चाहें तो उस हिस्से को अनदेखा कर सकते हैं।
२०:०२ पर kennytm

अगर मैं चाहता हूं m <= x <= n, तो आप अपने समाधान को कैसे संशोधित करेंगे?
बीजे पीटर डेलाक्रूज

6
@BJPeterDeLaCruz: एक के बीच यादृच्छिक संख्या mऔर nके बीच एक यादृच्छिक संख्या के साथ प्राप्त किया जा सकता 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
यह बहुत सरल और इसलिए सबसे अधिक मतदान वाले की तुलना में अधिक उपयोगी है।
युरिन

2
Android के लिए विकास करने वालों के लिए, ध्यान दें कि यह केवल API 21 (लॉलीपॉप, एंड्रॉइड 5.0) से उपलब्ध है: developer.android.com/reference/java/util/concurrent/…
Android डेवलपर

75

किसी श्रेणी में संख्या (उपयोगिता विधि के बिना) उत्पन्न करने की मानक विधि सिर्फ सीमा के साथ दोहरे का उपयोग करना है:

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

आपको 123456789 (अनन्य) के माध्यम से 1234567 (समावेशी) से एक लंबा समय देगा

नोट: कोष्ठकों की जांच करें, क्योंकि लंबे समय तक कास्टिंग गुणन की तुलना में उच्च प्राथमिकता है।


5
मेरा पहला विचार बिल्कुल यही था। लेकिन यह थोड़ा अटपटा लग रहा है। और मैं वितरण की एकरूपता के बारे में चिंतित हूं (ऐसा नहीं है कि मुझे वास्तव में इसकी आवश्यकता है, मैं बस इसे सही करना चाहता हूं)
विलियस नॉर्मेंटस

6
कृपया इसका उपयोग कभी न करें। आउटपुट एक समान नहीं है।
नवीन

2
सबसे बड़ी समस्या यह है कि गोलाई सबसे कम बिट को गैर-समान बना देगा। इसके अलावा, boundसबसे बड़े पूर्णांक से कम होना चाहिए जो एक डबल, 2 ^ 53 में एन्कोड किया जा सकता है।
डबलिनस्की

12

ऊपर दिए गए तरीके बढ़िया काम करते हैं। यदि आप अपाचे कॉमन्स (org.apache.commons.math.random) का उपयोग कर रहे हैं, तो रैंडम डेटा की जाँच करें। इसकी एक विधि है: अगली लम्बी (लंबी कम, लंबी ऊपरी)

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
पोस्टरिटी के लिए: रैंडमडाटा 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
FYI करें: यह हमेशा एक समान वितरण नहीं देता है, और यह वास्तव में कुछ बड़ी श्रेणियों के लिए बुरा है। उदाहरण के लिए यदि min = 0और max = 2 * (MAX_LONG / 3), तो आप दो बार के रूप में होने की संभावना हो एक मूल्य प्राप्त करने के लिए [0, MAX_LONG / 3]के रूप में आप में से एक मिल रहे हैं [MAX_LONG / 3, 2 * (MAX_LONG / 3)]
निक

यह कोड काम नहीं करेगा। यदि nextLongकोई ऋणात्मक मान लौटाता है, तो शेष ऋणात्मक होगा, और मान श्रेणी के बाहर होगा।
अरनौद

3

इसके अलावा kennytm के उत्तर में सुधार: जावा में वास्तविक कार्यान्वयन को ध्यान में रखते हुए एक उपवर्ग कार्यान्वयन होगा:

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, बाध्य)। दूसरा, यह अनावश्यक रूप से विस्तृत है: r = r & mवांछित परिणाम को पूरा करेगा, और यह मूल रूप से वर्तमान जावा 8 कार्यान्वयन करता है। यह संभव है कि जब यह उत्तर लिखा गया था तो कार्यान्वयन अलग था, लेकिन यह नहीं दिखाया जा सकता है।
ई। बिशप

3

यदि आप एक समान रूप से वितरित pseudorandom [0 m) की सीमा में लंबे समय तक चाहते हैं , तो modulo ऑपरेटर और निरपेक्ष मान विधि का उपयोग करने की कोशिश करें जो nextLong()कि नीचे दी गई विधि के साथ संयुक्त है :

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

randआपकी रैंडम ऑब्जेक्ट कहां है

मोडुलो ऑपरेटर दो संख्याओं को विभाजित करता है और शेष संख्याओं को आउटपुट करता है। उदाहरण के लिए, 3 % 2है1 क्योंकि 3 और 2 के शेष 1 है।

चूंकि nextLong()[- (२ ^ ४ a), २ ^ ४ somewhere (या उस रेंज में कहीं) की सीमा में समान रूप से वितरित छद्म आयामी उत्पन्न करता है, आपको इसका पूर्ण मूल्य लेने की आवश्यकता होगी। यदि आप नहीं करते हैं, तो nextLong()विधि के मोडुलो में ऋणात्मक मान लौटाने की 50% संभावना है, जो सीमा से बाहर है [0]m ]।

आपने शुरू में जो अनुरोध किया था, वह [0,100) की सीमा में समान रूप से वितरित छद्म आयामी था। निम्न कोड ऐसा करता है:

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

1
सापेक्ष पक्षपाती है, यादृच्छिक के लिए उसका उपयोग नहीं करते stackoverflow.com/a/10984975/1166266
सायरन

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

?


ठीक है, उन हिस्सों को छोड़कर जो एक ढांचे से संबंधित हैं (मुझे लगता है)।
दामिर ओलेजर

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;

}

जब मैं लंबे मिनट = 1 एल रीसेट करता हूं; लंबी अधिकतम = 10 एल; परिणामी यादृच्छिक संख्या अधिकतम मान से आगे बढ़ जाती है!
राज राज

यह random.nextLong ()% (अधिकतम - न्यूनतम) + मिनट होना चाहिए;
जय जोड़ीवाल

2

से जावा 8 एपीआई

एपीआई डॉक से वास्तविक कार्यान्वयन लेना आसान हो सकता है 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

रैंडम पेज से :

अगली विधि क्लास रैंडम द्वारा कार्यान्वित की जाती है जैसे कि:

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

क्योंकि क्लास रैंडम केवल 48 बिट्स के साथ एक बीज का उपयोग करता है, यह एल्गोरिथ्म सभी संभव लंबे मूल्यों को वापस नहीं करेगा।

इसलिए यदि आप एक प्राप्त करना चाहते हैं Long, तो आप पहले से ही पूर्ण 64 बिट श्रेणी प्राप्त नहीं करेंगे।

मेरा सुझाव है कि यदि आपके पास एक सीमा है जो 2 की शक्ति के पास आती है, तो आप Longउस स्निपेट में इस तरह से निर्माण करते हैं:

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

उदाहरण के लिए, 35 बिट रेंज प्राप्त करने के लिए।


2
लेकिन दस्तावेज़ीकरण कहता है "सभी 2 ^ 64 संभावित लंबे मानों (लगभग) समान संभावना के साथ उत्पादन किया जाता है।" तो जाहिरा तौर पर नेक्स्टलांग () विधि में सभी संभावित मूल्यों को वापस करना चाहिए .. Btw, बीज की लंबाई मूल्यों के वितरण से संबंधित है?
विलीस नॉर्मेंटस

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
आपको Randomhoc पर उदाहरण नहीं बनाने चाहिए , आपको Throwables या अन्य अपवादों को नहीं पकड़ना चाहिए, यदि आवश्यक नहीं है, तो आपको उपयोग करने के बजाय कुछ प्रकार की लॉगिंग फ़्रेमवर्क (SLF4J) के साथ त्रुटियों को लॉग करना चाहिए printStackTrace
बोगुś

0

यदि आप जावा स्ट्रीम का उपयोग कर सकते हैं, तो आप निम्नलिखित प्रयास कर सकते हैं:

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 कहें तो क्या होगा ? लूप कई पुनरावृत्तियों का प्रदर्शन करेगा ।
मैग्निलेक्स
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.