क्या यह एक "पर्याप्त पर्याप्त" यादृच्छिक एल्गोरिदम है; यदि इसका उपयोग तेज हो तो इसका उपयोग क्यों नहीं किया जाता है?


171

मैंने एक कक्षा बुलायी QuickRandom , और इसका काम यादृच्छिक संख्याओं का उत्पादन करना है। यह वास्तव में सरल है: बस पुराना मान लें, एक से गुणा करें double, और दशमलव भाग लें।

यहाँ QuickRandomइसकी संपूर्णता में मेरी कक्षा है:

public class QuickRandom {
    private double prevNum;
    private double magicNumber;

    public QuickRandom(double seed1, double seed2) {
        if (seed1 >= 1 || seed1 < 0) throw new IllegalArgumentException("Seed 1 must be >= 0 and < 1, not " + seed1);
        prevNum = seed1;
        if (seed2 <= 1 || seed2 > 10) throw new IllegalArgumentException("Seed 2 must be > 1 and <= 10, not " + seed2);
        magicNumber = seed2;
    }

    public QuickRandom() {
        this(Math.random(), Math.random() * 10);
    }

    public double random() {
        return prevNum = (prevNum*magicNumber)%1;
    }

}

और यहाँ कोड है जो मैंने इसे परीक्षण करने के लिए लिखा था:

public static void main(String[] args) {
        QuickRandom qr = new QuickRandom();

        /*for (int i = 0; i < 20; i ++) {
            System.out.println(qr.random());
        }*/

        //Warm up
        for (int i = 0; i < 10000000; i ++) {
            Math.random();
            qr.random();
            System.nanoTime();
        }

        long oldTime;

        oldTime = System.nanoTime();
        for (int i = 0; i < 100000000; i ++) {
            Math.random();
        }
        System.out.println(System.nanoTime() - oldTime);

        oldTime = System.nanoTime();
        for (int i = 0; i < 100000000; i ++) {
            qr.random();
        }
        System.out.println(System.nanoTime() - oldTime);
}

यह एक बहुत ही सरल एल्गोरिथ्म है जो बस पिछले डबल को "मैजिक नंबर" डबल से गुणा करता है। मैंने इसे बहुत जल्दी से एक साथ फेंक दिया, इसलिए मैं शायद इसे बेहतर बना सकता था, लेकिन अजीब तरह से, यह ठीक काम कर रहा है।

यह mainविधि में टिप्पणी की गई लाइनों का नमूना आउटपुट है :

0.612201846732229
0.5823974655091941
0.31062451498865684
0.8324473610354004
0.5907187526770246
0.38650264675748947
0.5243464344127049
0.7812828761272188
0.12417247811074805
0.1322738256858378
0.20614642573072284
0.8797579436677381
0.022122999476108518
0.2017298328387873
0.8394849894162446
0.6548917685640614
0.971667953190428
0.8602096647696964
0.8438709031160894
0.694884972852229

हम्म। बहुत यादृच्छिक। वास्तव में, यह एक गेम में यादृच्छिक संख्या जनरेटर के लिए काम करेगा।

यहाँ गैर-टिप्पणी किए गए भाग का नमूना आउटपुट है:

5456313909
1427223941

वाह! की तुलना में यह लगभग 4 गुना तेज प्रदर्शन करता हैMath.random

मुझे याद है कि कहीं-कहीं ऐसा Math.randomइस्तेमाल होता है System.nanoTime()और टैंक्स ऑफ द क्रेजी मॉडुलस और डिवीजन स्टफ होता है। क्या यह सचमुच आवश्यक है? मेरा एल्गोरिथ्म बहुत तेज़ प्रदर्शन करता है और यह बहुत यादृच्छिक लगता है।

मेरे दो सवाल हैं:

  • क्या मेरा एल्गोरिथ्म "काफी अच्छा" है (के लिए, कहते हैं, एक गेम, जहां वास्तव में यादृच्छिक संख्या बहुत महत्वपूर्ण नहीं हैं)?
  • ऐसा क्यों होता Math.randomहै जब यह सिर्फ साधारण गुणा और दशमलव को काटने के लिए पर्याप्त लगता है?

154
"बहुत यादृच्छिक लगता है"; आपको हिस्टोग्राम उत्पन्न करना चाहिए और अपने अनुक्रम पर कुछ स्वत :संबंध चलाना चाहिए ...
ओलिवर चार्ल्सवर्थ

63
उनका अर्थ है "बहुत यादृच्छिक लगता है" वास्तव में यादृच्छिकता का एक उद्देश्य माप नहीं है और आपको कुछ वास्तविक आंकड़े प्राप्त करने चाहिए।
मैट एच

23
@Doorknob: आम आदमी की शर्तों में, आपको जांच करनी चाहिए कि आपके नंबर में 0 और 1 के बीच "फ्लैट" वितरण है या नहीं, और देखें कि क्या समय के साथ कोई आवधिक / दोहरावदार पैटर्न हैं।
ओलिवर चार्ल्सवर्थ

22
कोशिश करो new QuickRandom(0,5)या new QuickRandom(.5, 2)। वे दोनों आपके नंबर के लिए बार-बार आउटपुट 0 करेंगे।
फ्रेंकी कर्नी मैन

119
अपनी खुद की यादृच्छिक संख्या पीढ़ी एल्गोरिथ्म लिखना अपने स्वयं के एन्क्रिप्शन एल्गोरिदम को लिखने जैसा है। हाइपर-क्वालीफाइड लोगों द्वारा इतनी पूर्व कला है, कि इसे सही करने की कोशिश में अपना समय बिताना समझदारी है। जावा लाइब्रेरी फ़ंक्शंस का उपयोग नहीं करने का कोई कारण नहीं है, और यदि आप वास्तव में किसी कारण के लिए अपना खुद का लिखना चाहते हैं, तो विकिपीडिया पर जाएं और वहां मैरसेन ट्विस्टर की तरह एल्गोरिदम देखें।
स्टीवेहा

जवाबों:


351

आपका QuickRandomकार्यान्वयन वास्तव में एक समान वितरण नहीं है। आवृत्तियों आम तौर पर कम मूल्यों पर अधिक होती हैं जबकि Math.random()अधिक समान वितरण होता है। यहाँ एक SSCCE है जो दिखाता है कि:

package com.stackoverflow.q14491966;

import java.util.Arrays;

public class Test {

    public static void main(String[] args) throws Exception {
        QuickRandom qr = new QuickRandom();
        int[] frequencies = new int[10];
        for (int i = 0; i < 100000; i++) {
            frequencies[(int) (qr.random() * 10)]++;
        }
        printDistribution("QR", frequencies);

        frequencies = new int[10];
        for (int i = 0; i < 100000; i++) {
            frequencies[(int) (Math.random() * 10)]++;
        }
        printDistribution("MR", frequencies);
    }

    public static void printDistribution(String name, int[] frequencies) {
        System.out.printf("%n%s distribution |8000     |9000     |10000    |11000    |12000%n", name);
        for (int i = 0; i < 10; i++) {
            char[] bar = "                                                  ".toCharArray(); // 50 chars.
            Arrays.fill(bar, 0, Math.max(0, Math.min(50, frequencies[i] / 100 - 80)), '#');
            System.out.printf("0.%dxxx: %6d  :%s%n", i, frequencies[i], new String(bar));
        }
    }

}

औसत परिणाम इस तरह दिखता है:

QR distribution |8000     |9000     |10000    |11000    |12000
0.0xxx:  11376  :#################################                 
0.1xxx:  11178  :###############################                   
0.2xxx:  11312  :#################################                 
0.3xxx:  10809  :############################                      
0.4xxx:  10242  :######################                            
0.5xxx:   8860  :########                                          
0.6xxx:   9004  :##########                                        
0.7xxx:   8987  :#########                                         
0.8xxx:   9075  :##########                                        
0.9xxx:   9157  :###########                                       

MR distribution |8000     |9000     |10000    |11000    |12000
0.0xxx:  10097  :####################                              
0.1xxx:   9901  :###################                               
0.2xxx:  10018  :####################                              
0.3xxx:   9956  :###################                               
0.4xxx:   9974  :###################                               
0.5xxx:  10007  :####################                              
0.6xxx:  10136  :#####################                             
0.7xxx:   9937  :###################                               
0.8xxx:  10029  :####################                              
0.9xxx:   9945  :###################    

यदि आप परीक्षण दोहराते हैं, तो आप देखेंगे कि एमआर वितरण स्थिर है, जबकि क्यूआर वितरण प्रारंभिक बीजों पर निर्भर करता है। कभी-कभी यह वांछित समान वितरण तक पहुंचता है, लेकिन अधिक बार यह नहीं होता है। यहाँ अधिक चरम उदाहरणों में से एक है, यह ग्राफ की सीमाओं से परे है:

QR distribution |8000     |9000     |10000    |11000    |12000
0.0xxx:  41788  :##################################################
0.1xxx:  17495  :##################################################
0.2xxx:  10285  :######################                            
0.3xxx:   7273  :                                                  
0.4xxx:   5643  :                                                  
0.5xxx:   4608  :                                                  
0.6xxx:   3907  :                                                  
0.7xxx:   3350  :                                                  
0.8xxx:   2999  :                                                  
0.9xxx:   2652  :                                                  

17
संख्यात्मक आंकड़ों के लिए +1 - हालांकि कच्चे नंबरों को देखना भ्रामक हो सकता है क्योंकि इसका मतलब यह नहीं है कि उनके पास सांख्यिकीय रूप से महत्वपूर्ण अंतर है।
मैकीज पीचोटका

16
इन परिणामों के लिए पारित प्रारंभिक बीज के साथ भारी भिन्नता है QuickRandom। कभी कभी, यह एक समान करने के लिए करीब है, कभी कभी यह है ज्यादा इस से भी बदतर।
पेट्र जेनेक

68
@ BlueRaja-DannyPflughoeft कोई भी PRNG, जहां आउटपुट की गुणवत्ता प्रारंभिक बीज मूल्य (s) पर निर्भर करती है (जैसा कि आंतरिक स्थिरांक के विपरीत) मेरे लिए टूटा हुआ लगता है।
एक CVn

22
आंकड़ों का पहला नियम: डेटा को प्लॉट करें । आपका विश्लेषण स्पॉट-ऑन है, लेकिन हिस्टोग्राम की साजिश रचने से यह बहुत जल्दी पता चलता है। ;-) (और यह आर में दो पंक्तियाँ हैं)
कोनराड रूडोल्फ

37
अनिवार्य उद्धरण: "जो कोई भी यादृच्छिक अंकों के उत्पादन के अंकगणितीय तरीकों पर विचार करता है, वह निश्चित रूप से पाप की स्थिति में है।" - जॉन वॉन न्यूमैन (1951) "जिस किसी ने भी कम से कम 100 स्थानों पर उपरोक्त उद्धरण नहीं देखा है, वह शायद बहुत पुराना नहीं है।" - डीवी प्रायर (1993) "रैंडम नंबर जनरेटर को यादृच्छिक पर नहीं चुना जाना चाहिए।" - डोनाल्ड नुथ (1986)
हैप्पी ग्रीन किड नैप्स

133

आप जो वर्णन कर रहे हैं, वह एक प्रकार का यादृच्छिक जनरेटर है, जिसे एक रैखिक बधाई जनरेटर कहा जाता है । जनरेटर निम्नानुसार काम करता है:

  • बीज मूल्य और गुणक से शुरू करें।
  • एक यादृच्छिक संख्या उत्पन्न करने के लिए:
    • बीज को गुणक द्वारा गुणा करें।
    • इस मूल्य के बराबर बीज निर्धारित करें।
    • यह मान लौटाओ।

इस जनरेटर में कई अच्छे गुण हैं, लेकिन एक अच्छे यादृच्छिक स्रोत के रूप में महत्वपूर्ण समस्याएं हैं। ऊपर लिंक किया गया विकिपीडिया लेख कुछ ताकत और कमजोरियों का वर्णन करता है। संक्षेप में, यदि आपको अच्छे यादृच्छिक मूल्यों की आवश्यकता है, तो यह संभवतः बहुत अच्छा दृष्टिकोण नहीं है।

उम्मीद है की यह मदद करेगा!


@ louism- यह वास्तव में "यादृच्छिक" नहीं है। परिणाम निर्धारक होंगे। उस ने कहा, मैंने अपना उत्तर लिखते समय इस बारे में नहीं सोचा था; शायद कोई उस विवरण को स्पष्ट कर सकता है?
templatetypedef

2
फ्लोटिंग पॉइंट अंकगणितीय त्रुटियां डिजाइन किए गए कार्यान्वयन हैं। जहाँ तक मुझे पता है, वे एक निश्चित मंच के लिए सुसंगत हैं, लेकिन विभिन्न मोबाइल फोन और पीसी आर्किटेक्चर के बीच उदाहरण के लिए भिन्न हो सकते हैं। यद्यपि एक पंक्ति में फ्लोटिंग पॉइंट गणनाओं की एक श्रृंखला करते समय कभी-कभी अतिरिक्त 'गार्ड बिट्स' जोड़े जाते हैं, और इन गार्ड बिट्स की उपस्थिति या अनुपस्थिति एक गणना को परिणाम में अलग-अलग बना सकती है। (गार्ड बिट्स, उदाहरण के लिए, एक 64 बिट डबल का विस्तार 80 बिट्स तक)
पटाशु

2
इसके अलावा, ध्यान रखें कि LCRNGs के पीछे का सिद्धांत यह मानता है कि आप पूर्णांक के साथ काम कर रहे हैं! इस पर फ्लोटिंग-पॉइंट संख्या फेंकने से परिणामों की गुणवत्ता समान नहीं होगी ।
डस्कवफ-एक्टिव-

1
@duskwuff, आप सही कह रहे हैं। लेकिन अगर फ़्लोटिंग पॉइंट हार्डवेयर समझदार नियमों का पालन करता है, तो ऐसा करना mantissa आकार को मापता है और सिद्धांत लागू होता है। बस आपको जो कर रहे हैं, उसमें अतिरिक्त देखभाल की जरूरत है।
वॉनब्रांड

113

आपका यादृच्छिक संख्या फ़ंक्शन खराब है, क्योंकि इसमें बहुत कम आंतरिक स्थिति है - किसी भी चरण पर फ़ंक्शन द्वारा संख्या आउटपुट पूरी तरह से पिछली संख्या पर निर्भर है। उदाहरण के लिए, यदि हम मानते हैं कि magicNumber2 है (उदाहरण के अनुसार), तो अनुक्रम:

0.10 -> 0.20

समान दृश्यों द्वारा दृढ़ता से प्रतिबिंबित किया जाता है:

0.09 -> 0.18
0.11 -> 0.22

कई मामलों में, यह आपके खेल में ध्यान देने योग्य सहसंबंध उत्पन्न करेगा - उदाहरण के लिए, यदि आप वस्तुओं के लिए X और Y निर्देशांक बनाने के लिए अपने फ़ंक्शन के लिए लगातार कॉल करते हैं, तो ऑब्जेक्ट स्पष्ट विकर्ण पैटर्न बनाएंगे।

जब तक आपके पास यह विश्वास करने का अच्छा कारण नहीं है कि यादृच्छिक संख्या जनरेटर आपके आवेदन को धीमा कर रहा है (और यह बहुत कम संभावना है), अपने स्वयं के प्रयास करने और लिखने का कोई अच्छा कारण नहीं है।


36
एक व्यावहारिक जवाब के लिए +1 ... इसे शूट में अप का उपयोग करें और दुश्मनों को महाकाव्य कई हेडशॉट के लिए विकर्णों के साथ फैलाएं? : डी
विम

@wim: यदि आपको ऐसे पैटर्न चाहिए तो आपको PRNG की आवश्यकता नहीं है।
रेयान

109

इसके साथ असली समस्या यह है कि यह आउटपुट हिस्टोग्राम प्रारंभिक बीज पर बहुत अधिक निर्भर करता है - बहुत समय यह एक समरूप उत्पादन के साथ समाप्त हो जाएगा, लेकिन बहुत समय में विशिष्ट रूप से संयुक्त राष्ट्र के समान उत्पादन होगा।

से प्रेरित होकर कितना बुरा php के बारे में यह लेख rand()समारोह है , मैं कुछ यादृच्छिक मैट्रिक्स छवियों का उपयोग किया QuickRandomऔर System.Random। यह रन दिखाता है कि कभी-कभी बीज एक बुरा प्रभाव डाल सकता है (इस मामले में कम संख्या के पक्ष में) जहां System.Randomबहुत समान है।

QuickRandom

System.Random

और भी बदतर

हम आरंभ तो QuickRandomके रूप में new QuickRandom(0.01, 1.03)हम इस छवि को मिलती है:

कोड

using System;
using System.Drawing;
using System.Drawing.Imaging;

namespace QuickRandomTest
{
    public class QuickRandom
    {
        private double prevNum;
        private readonly double magicNumber;

        private static readonly Random rand = new Random();

        public QuickRandom(double seed1, double seed2)
        {
            if (seed1 >= 1 || seed1 < 0) throw new ArgumentException("Seed 1 must be >= 0 and < 1, not " + seed1);
            prevNum = seed1;
            if (seed2 <= 1 || seed2 > 10) throw new ArgumentException("Seed 2 must be > 1 and <= 10, not " + seed2);
            magicNumber = seed2;
        }

        public QuickRandom()
            : this(rand.NextDouble(), rand.NextDouble() * 10)
        {
        }

        public double Random()
        {
            return prevNum = (prevNum * magicNumber) % 1;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            var rand = new Random();
            var qrand = new QuickRandom();
            int w = 600;
            int h = 600;
            CreateMatrix(w, h, rand.NextDouble).Save("System.Random.png", ImageFormat.Png);
            CreateMatrix(w, h, qrand.Random).Save("QuickRandom.png", ImageFormat.Png);
        }

        private static Image CreateMatrix(int width, int height, Func<double> f)
        {
            var bitmap = new Bitmap(width, height);
            for (int y = 0; y < height; y++) {
                for (int x = 0; x < width; x++) {
                    var c = (int) (f()*255);
                    bitmap.SetPixel(x, y, Color.FromArgb(c,c,c));
                }
            }

            return bitmap;
        }
    }
}

2
अच्छा कोड है। हाँ, यह अच्छा है। मैं भी कभी-कभी ऐसा करता था, इससे एक मात्रात्मक माप प्राप्त करना कठिन है, लेकिन इस क्रम को देखने का एक और अच्छा तरीका है। और यदि आप चौड़ाई * से अधिक के दृश्यों पर एक नज़र रखना चाहते थे, तो आप इस एक पिक्सेल-प्रति-पिक्सेल के साथ अगली छवि को प्राप्त कर सकते हैं। मुझे लगता है कि QuickRandom तस्वीर बहुत अधिक सौंदर्यवादी मनभावन है, हालांकि, यह समुद्री शैवाल कालीन की तरह बनावट के कारण है।
क्रिस स्ट्रींगफेलो

सौंदर्यशास्त्रीय रूप से मनभावन हिस्सा यह है कि आप प्रत्येक पंक्ति के साथ जाने पर अनुक्रम को कैसे बढ़ाते हैं (और फिर से फिर से शुरू करें) क्योंकि magicNumberगुणन एक समान संख्या पैदा करता है prevNum, जो यादृच्छिकता की कमी को दर्शाता है। यदि हम बीज का उपयोग करते हैं new QuickRandom(0.01, 1.03)तो हमें यह i.imgur.com/Q1Yunbe.png मिलता है !
कैलम रोजर्स

हाँ, महान विश्लेषण। चूंकि यह सिर्फ रैपिंग से पहले एक लगातार स्पष्ट रूप से मॉड 1 को गुणा करता है इसलिए आपके द्वारा वर्णित वृद्धि होगी। इस तरह से लगता है कि अगर हम कम महत्वपूर्ण दशमलव placings 1 बिलियन से गुणा करके मॉड 256 रंग पैलेट को कम करने से लिया जा सकता है।
क्रिस स्ट्रींगफेलो

क्या आप मुझे बता सकते हैं कि आपने उन आउटपुट इमेज को बनाने के लिए क्या उपयोग किया है? Matlab?
uday

@uDaY: कोड, C # और पर एक नज़र डालें System.Drawing.Bitmap
कैलम रोजर्स

37

आपके रैंडम नंबर जनरेटर के साथ एक समस्या यह है कि कोई 'छिपा हुआ राज्य' नहीं है - अगर मुझे पता है कि अंतिम कॉल पर आप किस रैंडम नंबर पर लौटे हैं, तो मुझे पता है कि हर एक रैंडम नंबर आप समय के अंत तक भेज देंगे, क्योंकि केवल एक ही है अगले परिणाम संभव है, और इतने पर और इतने पर।

एक और बात पर विचार करने के लिए अपने यादृच्छिक संख्या जनरेटर की 'अवधि' है। स्पष्ट रूप से एक परिमित राज्य आकार के साथ, एक डबल के मंटिसा भाग के बराबर, यह केवल लूपिंग से पहले अधिकतम 2 ^ 52 मानों पर वापस जाने में सक्षम होगा। लेकिन यह सबसे अच्छा मामला है - क्या आप यह साबित कर सकते हैं कि 1, 2, 3, 4 की अवधि नहीं है? यदि वहाँ हैं, तो आपका आरएनजी उन मामलों में भयानक, पतित व्यवहार करेगा।

इसके अलावा, क्या आपकी यादृच्छिक संख्या पीढ़ी में सभी शुरुआती बिंदुओं के लिए एक समान वितरण होगा? यदि ऐसा नहीं होता है, तो आपका आरएनजी शुरू होने वाले बीज के आधार पर अलग-अलग तरीकों से पक्षपाती - या बदतर हो जाएगा।

अगर आप इन सभी सवालों का जवाब दे सकते हैं, तो बहुत बढ़िया। यदि आप नहीं कर सकते हैं, तो आप जानते हैं कि अधिकांश लोग पहिया का फिर से आविष्कार क्यों नहीं करते हैं और एक सिद्ध यादृच्छिक संख्या जनरेटर का उपयोग करते हैं;)

(वैसे, एक अच्छा कहावत है: सबसे तेज़ कोड वह कोड है जो नहीं चलता है। आप दुनिया में सबसे तेज़ यादृच्छिक () बना सकते हैं, लेकिन यह बहुत अच्छा नहीं है अगर यह बहुत यादृच्छिक नहीं है)


8
सभी बीजों के लिए इस जनरेटर पर कम से कम एक तुच्छ लूप है 0 -> 0:। बीज के आधार पर, कई अन्य हो सकते हैं। (उदाहरण के लिए, एक 3.0 के बीज, साथ के लिए 0.5 -> 0.5, 0.25 -> 0.75 -> 0.25, 0.2 -> 0.6 -> 0.8 -> 0.4 -> 0.2आदि)
-inactive- duskwuff

36

PRNGs को विकसित करते समय एक सामान्य परीक्षण मैंने हमेशा किया:

  1. आउटपुट को चार मूल्यों में बदलें
  2. किसी फ़ाइल पर वर्ण मान लिखें
  3. फ़ाइल संपीड़ित करें

इसने मुझे उन विचारों पर जल्दी से चलना शुरू कर दिया, जो लगभग 1 से 20 मेगाबाइट के दृश्यों के लिए "काफी अच्छे" PRNG थे। इसने आंख से निरीक्षण करने की तुलना में एक बेहतर टॉप डाउन चित्र भी दिया, क्योंकि राज्य के आधे शब्द के साथ कोई भी "अच्छा पर्याप्त" PRNG जल्दी से चक्र बिंदु को देखने के लिए आपकी आंखों की क्षमता से अधिक हो सकता है।

अगर मैं वास्तव में योग्य था, तो मैं अच्छे एल्गोरिदम ले सकता हूं और उन पर DIEHARD / NIST परीक्षण चला सकता हूं, ताकि अधिक जानकारी मिल सके, और फिर वापस जाएं और कुछ और ट्विक करें।

संपीड़न परीक्षण का लाभ, जैसा कि एक आवृत्ति विश्लेषण के विपरीत है, तुच्छ रूप से यह एक अच्छा वितरण का निर्माण करने के लिए आसान है: बस 256 लंबाई ब्लॉक को मानों के सभी वर्णों से युक्त आउटपुट - 255, और यह 100,000 बार करें। लेकिन इस क्रम में लंबाई 256 का चक्र है।

एक तिरछा वितरण, यहां तक ​​कि एक छोटे से मार्जिन द्वारा, एक संपीड़न एल्गोरिथ्म द्वारा उठाया जाना चाहिए, खासकर यदि आप इसे काम करने के लिए अनुक्रम का पर्याप्त (1 मेगाबाइट) कहते हैं। यदि कुछ वर्ण, या बिगोग्राम, या एन-ग्राम अधिक बार होते हैं, तो एक संपीड़न एल्गोरिथ्म इस वितरण तिरछा कोड को कोड कर सकता है जो छोटे कोड शब्दों के साथ लगातार घटनाओं का पक्ष लेता है, और आपको संपीड़न का एक डेल्टा प्राप्त होता है।

चूंकि अधिकांश संपीड़न एल्गोरिदम तेज हैं, और उन्हें किसी भी कार्यान्वयन की आवश्यकता नहीं है (जैसा कि ओएस ने उन्हें बस चारों ओर झूठ बोल रहा है), संपीड़न टेस्ट एक बहुत ही उपयोगी है जो आपके द्वारा विकसित किए जा रहे PRNG के लिए जल्दी से पास / फेल हो सकता है।

अपने प्रयोगों के साथ शुभकामनाएँ!

ओह, मैंने आपके ऊपर दिए गए रिंक पर यह परीक्षण किया, अपने कोड के निम्नलिखित छोटे मोड का उपयोग करते हुए:

import java.io.*;

public class QuickRandom {
    private double prevNum;
    private double magicNumber;

    public QuickRandom(double seed1, double seed2) {
        if (seed1 >= 1 || seed1 < 0) throw new IllegalArgumentException("Seed 1 must be >= 0 and < 1, not " + seed1);
        prevNum = seed1;
        if (seed2 <= 1 || seed2 > 10) throw new IllegalArgumentException("Seed 2 must be > 1 and <= 10, not " + seed2);
        magicNumber = seed2;
    }

    public QuickRandom() {
        this(Math.random(), Math.random() * 10);
    }

    public double random() {
        return prevNum = (prevNum*magicNumber)%1;
    }

    public static void main(String[] args) throws Exception {
        QuickRandom qr = new QuickRandom();
        FileOutputStream fout = new FileOutputStream("qr20M.bin");

        for (int i = 0; i < 20000000; i ++) {
            fout.write((char)(qr.random()*256));
        }
    }
}

परिणाम थे:

Cris-Mac-Book-2:rt cris$ zip -9 qr20M.zip qr20M.bin2
adding: qr20M.bin2 (deflated 16%)
Cris-Mac-Book-2:rt cris$ ls -al
total 104400
drwxr-xr-x   8 cris  staff       272 Jan 25 05:09 .
drwxr-xr-x+ 48 cris  staff      1632 Jan 25 05:04 ..
-rw-r--r--   1 cris  staff      1243 Jan 25 04:54 QuickRandom.class
-rw-r--r--   1 cris  staff       883 Jan 25 05:04 QuickRandom.java
-rw-r--r--   1 cris  staff  16717260 Jan 25 04:55 qr20M.bin.gz
-rw-r--r--   1 cris  staff  20000000 Jan 25 05:07 qr20M.bin2
-rw-r--r--   1 cris  staff  16717402 Jan 25 05:09 qr20M.zip

मैं एक PRNG पर विचार करूंगा, अगर आउटपुट फाइल बिल्कुल भी संपीड़ित न हो सके। सच कहूं, तो मुझे नहीं लगता था कि आपका PRNG इतना अच्छा होगा, ~ 20 Megs पर केवल 16% ऐसे सरल निर्माण के लिए बहुत प्रभावशाली है। लेकिन मैं अभी भी इसे विफल मानता हूं।


2
इसे लागू करना या नहीं, मेरे पास जिप वर्षों के साथ एक ही विचार है जब मैं अपने यादृच्छिक जनरेटर का परीक्षण करता हूं।
अरिस्टोस

1
धन्यवाद @Alexandre C. और अरिस्टोस और एडसन। मुझे तुम पर विश्वास है।
क्रिस स्ट्रींगफेलो

33

सबसे तेज़ रैंडम जनरेटर जिसे आप लागू कर सकते हैं वह यह है:

यहां छवि विवरण दर्ज करें

XD, चुटकुले, इसके अलावा सब कुछ यहाँ कहा गया है, मैं यह उद्धृत करने में योगदान देना चाहूंगा कि यादृच्छिक अनुक्रमों का परीक्षण करना "एक कठिन काम है" [1], और कई परीक्षण हैं जो छद्म यादृच्छिक संख्याओं के कुछ गुणों की जांच करते हैं, आप एक पा सकते हैं उनमें से बहुत से यहाँ: http://www.random.org/analysis/#2005

यादृच्छिक जनरेटर "गुणवत्ता" का मूल्यांकन करने का एक सरल तरीका पुराना ची स्क्वायर परीक्षण है।

static double chisquare(int numberCount, int maxRandomNumber) {
    long[] f = new long[maxRandomNumber];
    for (long i = 0; i < numberCount; i++) {
        f[randomint(maxRandomNumber)]++;
    }

    long t = 0;
    for (int i = 0; i < maxRandomNumber; i++) {
        t += f[i] * f[i];
    }
    return (((double) maxRandomNumber * t) / numberCount) - (double) (numberCount);
}

हवाला देते हुए [1]

Is परीक्षण का विचार यह जांचना है कि उत्पादित संख्या यथोचित रूप से फैली हुई है या नहीं। यदि हम N पॉजिटिव नंबर से कम उत्पन्न करते हैं r , तो हम N / r के बारे में पाने की उम्मीद करेंगे प्रत्येक मान के नंबर । लेकिन --- और यह इस मामले का सार है --- सभी मूल्यों के समुद्र-प्रवाह की आवृत्ति बिल्कुल समान नहीं होनी चाहिए: यह यादृच्छिक नहीं होगा!

हम बस प्रत्येक आवृत्ति की घटना के वर्गों की राशि की गणना करते हैं, अपेक्षित आवृत्ति द्वारा स्केल की जाती है, और फिर अनुक्रम के आकार को प्रतिस्थापित करते हैं। यह संख्या, "istic स्टेटिस्टिक" के रूप में गणितीय रूप से व्यक्त की जा सकती है

ची चौकोर सूत्र

यदि numbers स्टेटिस्टिक आर के करीब है , तो संख्या यादृच्छिक हैं; अगर यह बहुत दूर है, तो वे नहीं हैं। "करीब" और "दूर" की धारणाओं को अधिक सटीक रूप से परिभाषित किया जा सकता है: टेबल मौजूद हैं जो बताती हैं कि यादृच्छिक अनुक्रमों के गुणों के लिए सांख्यिकीय से कैसे संबंधित हैं। हम जो सरल परीक्षण कर रहे हैं, उसके लिए आँकड़ा 2 .r के भीतर होना चाहिए

इस सिद्धांत और निम्नलिखित कोड का उपयोग करना:

abstract class RandomFunction {
    public abstract int randomint(int range); 
}

public class test {
    static QuickRandom qr = new QuickRandom();

    static double chisquare(int numberCount, int maxRandomNumber, RandomFunction function) {
        long[] f = new long[maxRandomNumber];
        for (long i = 0; i < numberCount; i++) {
            f[function.randomint(maxRandomNumber)]++;
        }

        long t = 0;
        for (int i = 0; i < maxRandomNumber; i++) {
            t += f[i] * f[i];
        }
        return (((double) maxRandomNumber * t) / numberCount) - (double) (numberCount);
    }

    public static void main(String[] args) {
        final int ITERATION_COUNT = 1000;
        final int N = 5000000;
        final int R = 100000;

        double total = 0.0;
        RandomFunction qrRandomInt = new RandomFunction() {
            @Override
            public int randomint(int range) {
                return (int) (qr.random() * range);
            }
        }; 
        for (int i = 0; i < ITERATION_COUNT; i++) {
            total += chisquare(N, R, qrRandomInt);
        }
        System.out.printf("Ave Chi2 for QR: %f \n", total / ITERATION_COUNT);        

        total = 0.0;
        RandomFunction mathRandomInt = new RandomFunction() {
            @Override
            public int randomint(int range) {
                return (int) (Math.random() * range);
            }
        };         
        for (int i = 0; i < ITERATION_COUNT; i++) {
            total += chisquare(N, R, mathRandomInt);
        }
        System.out.printf("Ave Chi2 for Math.random: %f \n", total / ITERATION_COUNT);
    }
}

मुझे निम्नलिखित परिणाम मिला:

Ave Chi2 for QR: 108965,078640
Ave Chi2 for Math.random: 99988,629040

जो, QuickRandom के लिए, बहुत दूर है r (से बाहर r ± 2 * sqrt(r))

यह कहा गया था, क्विकड्रैगन तेज हो सकता है लेकिन (जैसा कि अन्य उत्तरों में कहा गया है) एक यादृच्छिक संख्या जनरेटर के रूप में अच्छा नहीं है


[१] SEDGEWICK रॉबर्ट, सी में एल्गोरिदम , एडिंसन वेस्ले पब्लिशिंग कंपनी, १ ९९ ०, पृष्ठ ५१६ से ५१GE


9
+1 xkcd के लिए जो एक अद्भुत वोब्साइट (ओह, और शानदार उत्तर) है: P
tckmn

1
धन्यवाद, और हाँ xkcd रैक! XD
हिगुआरो

सिद्धांत ठीक है, लेकिन निष्पादन खराब है: कोड पूर्णांक अतिप्रवाह के लिए अतिसंवेदनशील है। जावा में सभी int[]को शून्य से आरंभ किया जाता है, इसलिए इस भाग की कोई आवश्यकता नहीं है। जब आप w / डबल्स काम करते हैं तो फ्लोट में कास्टिंग व्यर्थ है। अंतिम: तरीकों को नाम देना random1 और random2 काफी मजाकिया है।
बेस्टसेन्स

@bestsss टिप्पणियों के लिए धन्यवाद! मैंने C कोड से सीधा अनुवाद किया और इस पर ज्यादा ध्यान नहीं दिया = (मैंने कुछ संशोधन किए और उत्तर को अपडेट किया। मैं किसी भी अतिरिक्त सुझाव की सराहना
करूंगा

14

मैंने परिणामों का मूल्यांकन करने के लिए जावास्क्रिप्ट में आपके एल्गोरिथ्म का एक त्वरित मॉक-अप रखा । यह 0 - 99 से 100,000 यादृच्छिक पूर्णांक बनाता है और प्रत्येक पूर्णांक के उदाहरण को ट्रैक करता है।

पहली चीज जो मैंने नोटिस की है, वह यह है कि आपको उच्च संख्या की तुलना में कम संख्या प्राप्त होने की संभावना है। आप इसे तब देखते हैं जब seed1उच्च होता है और seed2कम होता है। कुछ उदाहरणों में, मुझे केवल 3 नंबर मिले।

सबसे अच्छा, आपके एल्गोरिथ्म को कुछ परिष्कृत करने की आवश्यकता है।


8

यदि Math.Random()फ़ंक्शन दिन के समय को प्राप्त करने के लिए ऑपरेटिंग सिस्टम को कॉल करता है, तो आप इसे अपने फ़ंक्शन से तुलना नहीं कर सकते। आपका फ़ंक्शन एक PRNG है, जबकि वह फ़ंक्शन वास्तविक यादृच्छिक संख्याओं के लिए प्रयास कर रहा है। सेब और संतरे।

आपका PRNG तेज़ हो सकता है, लेकिन उसके पास दोहराने से पहले एक लंबी अवधि को प्राप्त करने के लिए पर्याप्त राज्य की जानकारी नहीं है (और इसका तर्क पर्याप्त परिष्कृत नहीं है कि वह उस राज्य की जानकारी के साथ संभव हो सकने वाली अवधि भी प्राप्त कर सकता है)।

पीरियड से पहले खुद को दोहराना शुरू करने से पहले पीरियड की अवधि लंबी होती है। यह तब होता है जब PRNG मशीन एक राज्य में एक राज्य परिवर्तन करती है जो कुछ पिछले राज्य के समान होता है। वहां से, यह उन अवस्थाओं को दोहराएगा जो उस अवस्था में शुरू हुई थीं। PRNG के साथ एक और समस्या अद्वितीय अनुक्रमों की कम संख्या हो सकती है, साथ ही एक विशेष अनुक्रम पर पतित अभिसरण भी हो सकती है जो दोहराता है। अवांछनीय पैटर्न भी हो सकते हैं। उदाहरण के लिए, मान लें कि एक PRNG दशमलव में संख्याओं के मुद्रित होने पर काफी यादृच्छिक लगता है, लेकिन बाइनरी में मूल्यों का एक निरीक्षण बताता है कि बिट 4 बस प्रत्येक कॉल पर 0 और 1 के बीच टॉगल कर रहा है। ऊप्स!

Mersenne ट्विस्टर और अन्य एल्गोरिदम पर एक नज़र डालें। अवधि की लंबाई और सीपीयू चक्रों के बीच संतुलन बनाने के तरीके हैं। एक मूल दृष्टिकोण (Mersenne Twister में प्रयुक्त) राज्य वेक्टर में चारों ओर चक्र है। यह कहना है, जब एक संख्या उत्पन्न हो रही है, यह पूरे राज्य पर आधारित नहीं है, बस राज्य के कुछ शब्दों पर कुछ बिट संचालन के अधीन है। लेकिन प्रत्येक चरण में, एल्गोरिथ्म सरणी में चारों ओर घूमता है, एक बार में सामग्री को थोड़ा-थोड़ा स्क्रैच करता है।


5
मैं आपके पहले पैराग्राफ को छोड़कर ज्यादातर सहमत हूं। बिल्ट-इन रैंडम कॉल (और / dev / random on Unix-like सिस्टम) भी PRNG हैं। मैं कुछ भी कहता हूं जो यादृच्छिक संख्याओं को गतिशील रूप से एक PRNG पैदा करता है, भले ही बीज कुछ ऐसा हो जो भविष्यवाणी करना कठिन हो। कुछ "सच" यादृच्छिक संख्या जनरेटर हैं जो रेडियोधर्मी क्षय, वायुमंडलीय शोर आदि का उपयोग करते हैं, लेकिन ये अक्सर अपेक्षाकृत कुछ बिट्स / सेकंड उत्पन्न करते हैं।
मैट क्रैस

लिनक्स बॉक्स पर, /dev/randomडिवाइस चालकों से प्राप्त वास्तविक यादृच्छिकता का एक स्रोत है, न कि एक PRNG। जब पर्याप्त बिट्स उपलब्ध नहीं होते हैं तो यह ब्लॉक हो जाता है। बहन डिवाइस /dev/urandomभी ब्लॉक नहीं करता है, लेकिन यह अभी भी बिल्कुल PRNG नहीं है क्योंकि यह उपलब्ध होने पर यादृच्छिक बिट्स के साथ अपडेट किया जाता है।
काज

यदि Math.Random () फ़ंक्शन ऑपरेटिंग सिस्टम को दिन का समय प्राप्त करने के लिए कहता है - यह बिल्कुल असत्य है। (जावा के किसी भी जायके / संस्करणों में मैं के बारे में पता)
bestsss

@bestsss यह मूल प्रश्न से है: मुझे याद है कि मैथ.ग्रैंडम ने System.nanoTime () का उपयोग कहीं पढ़ा है । आपका ज्ञान वहाँ या आपके उत्तर में जोड़ने के लायक हो सकता है। मैं इसे सशर्त इस्तेमाल किया एक साथ करता है, तो । :)
काज

कज़, दोनों nanoTime()+ काउंटर / हैश का उपयोग java.util.Randomऑरेकल / ओपनजेडके के डिफ़ॉल्ट बीज के लिए किया जाता है । यह बीज के लिए है तो यह एक मानक LCG है। प्रभाव में ओपी जनरेटर बीज के लिए 2 यादृच्छिक संख्या लेता है, जो ठीक है - इसलिए इससे कोई अंतर नहीं है java.util.RandomSystem.currentTimeMillis()JDK1.4- में डिफ़ॉल्ट बीज था
bestsss

7

वहाँ कई, कई छद्म यादृच्छिक संख्या जनरेटर हैं। उदाहरण के लिए, नथ का रनर , मर्सने ट्विस्टर या LFSR जनरेटर की तलाश करें। नुथ के स्मारकीय "सेमिनुमेरिकल एल्गोरिदम" क्षेत्र को एनालाइज़ करता है, और कुछ रैखिक बधाई जनरेटर (लागू करने के लिए सरल, तेज) प्रस्तावित करता है।

लेकिन मैं आपको सुझाव दूंगा कि वे java.util.Randomया तो छड़ी करें Math.random, वे उपवास करें और कभी-कभार उपयोग के लिए कम से कम ठीक रहें (जैसे, गेम और ऐसे)। यदि आप वितरण (बस कुछ मोंटे कार्लो कार्यक्रम, या एक जेनेटिक अल्गोरिदम) पर विपरित हैं , तो उनके कार्यान्वयन की जाँच करें (स्रोत कहीं उपलब्ध है), और उन्हें कुछ सही मायने में यादृच्छिक संख्या के साथ बीज दें, या तो आपके ऑपरेटिंग सिस्टम से या random.org से । यदि यह कुछ एप्लिकेशन के लिए आवश्यक है जहां सुरक्षा महत्वपूर्ण है, तो आपको खुद को खोदना होगा। और उस स्थिति में आपको विश्वास नहीं होना चाहिए कि कुछ रंगीन वर्ग गायब बिट्स के साथ यहाँ हैं, अब मैं चुप रहूँगा।


7

यह बहुत कम संभावना नहीं है कि यादृच्छिक संख्या पीढ़ी का प्रदर्शन किसी भी उपयोग-मामले के लिए एक मुद्दा होगा, जब तक कि आप Randomकई थ्रेड्स से एकल उदाहरण तक पहुंच नहीं सकते (क्योंकि Randomयह है)synchronized ) ।

हालाँकि, अगर वास्तव में ऐसा है और आपको बहुत सारे रैंडम नंबरों की आवश्यकता है, तो आपका समाधान बहुत अधिक अविश्वसनीय है। कभी-कभी यह अच्छे परिणाम देता है, कभी-कभी यह भयानक परिणाम देता है (प्रारंभिक सेटिंग्स के आधार पर)।

यदि आप वही संख्याएँ चाहते हैं जो Randomवर्ग आपको देता है, केवल तेज़ी से, तो आप वहाँ के सिंक्रनाइज़ेशन से छुटकारा पा सकते हैं:

public class QuickRandom {

    private long seed;

    private static final long MULTIPLIER = 0x5DEECE66DL;
    private static final long ADDEND = 0xBL;
    private static final long MASK = (1L << 48) - 1;

    public QuickRandom() {
        this((8682522807148012L * 181783497276652981L) ^ System.nanoTime());
    }

    public QuickRandom(long seed) {
        this.seed = (seed ^ MULTIPLIER) & MASK;
    }

    public double nextDouble() {
        return (((long)(next(26)) << 27) + next(27)) / (double)(1L << 53);
    }

    private int next(int bits) {
        seed = (seed * MULTIPLIER + ADDEND) & MASK;
        return (int)(seed >>> (48 - bits));
    }

}

मैंने बस java.util.Randomकोड लिया और सिंक्रनाइज़ेशन को हटा दिया, जिसके परिणामस्वरूप मेरे ओरेकल हॉटस्पॉट जेवीएम 7 यू 9 पर मूल की तुलना में दोगुना प्रदर्शन हुआ। यह अभी भी आपकी तुलना में धीमा है QuickRandom, लेकिन यह बहुत अधिक सुसंगत परिणाम देता है। सटीक होने के लिए, समान seedमूल्यों और एकल थ्रेडेड अनुप्रयोगों के लिए, यह मूल श्रेणी के समान छद्म-यादृच्छिक संख्या देता हैRandom


यह कोड java.util.RandomOpenJDK 7u में वर्तमान पर आधारित है जिसे GNU GPL v2 के तहत लाइसेंस प्राप्त है ।


EDIT 10 महीने बाद:

मुझे अभी पता चला है कि आपको एक असम्बद्ध Randomउदाहरण प्राप्त करने के लिए ऊपर दिए गए मेरे कोड का उपयोग करने की आवश्यकता नहीं है । JDK में भी एक है!

जावा 7 की ThreadLocalRandomकक्षा को देखें। इसके अंदर का कोड मेरे कोड के लगभग समान है। वर्ग बस एक स्थानीय थ्रेड-पृथक Randomसंस्करण है जो यादृच्छिक संख्याओं को जल्दी से उत्पन्न करने के लिए उपयुक्त है। केवल नकारात्मक पक्ष यह है कि आप इसे seedमैन्युअल रूप से सेट नहीं कर सकते हैं ।

उदाहरण उपयोग:

Random random = ThreadLocalRandom.current();

2
@Edit हम्म, मैं कुछ समय के लिए QR, Math.random, और ThreadLocalRandom की तुलना कर सकता हूँ जब मैं बहुत आलसी नहीं हूँ :), यह दिलचस्प है, धन्यवाद!
tckmn

1. आप मास्क को गिराकर कुछ और गति प्राप्त कर सकते हैं क्योंकि उच्चतम 16 बिट्स उपयोग किए गए बिट्स को प्रभावित नहीं करते हैं। 2. आप उन बिट्स का उपयोग कर सकते हैं, एक घटाव को बचा सकते हैं और एक बेहतर जनरेटर प्राप्त कर सकते हैं (बड़ा राज्य; एक उत्पाद के सबसे महत्वपूर्ण बिट सबसे अच्छी तरह से वितरित किए जाते हैं, लेकिन कुछ मूल्यांकन की आवश्यकता होगी)। 3. सूर्य के लोगों ने केवल नथ द्वारा एक पुरातन RGG लागू किया और तुल्यकालन जोड़ा। :(
मातरिनस

3

'रैंडम' केवल संख्या प्राप्त करने के बारे में अधिक है .... आपके पास छद्म यादृच्छिक है

यदि छद्म यादृच्छिक आपके उद्देश्यों के लिए पर्याप्त है, तो निश्चित रूप से, यह तेज़ है (और XOR + Bitshift आपके पास जो भी है उससे तेज होगा)

रॉल्फ

संपादित करें:

ठीक है, इस उत्तर में बहुत जल्दबाजी करने के बाद, मुझे वास्तविक कारण का जवाब देना चाहिए कि आपका कोड अधिक तेज़ क्यों है:

गणित के लिए JavaDoc से। आयामी ()

यह विधि एक से अधिक थ्रेड द्वारा सही उपयोग की अनुमति देने के लिए ठीक से सिंक्रनाइज़ है। हालांकि, अगर कई थ्रेड्स को एक महान दर पर छद्म आयामी संख्या उत्पन्न करने की आवश्यकता होती है, तो यह प्रत्येक थ्रेड के लिए अपने स्वयं के छद्म आयामी-संख्या जनरेटर के लिए विवाद को कम कर सकता है।

यह संभावना है कि आपका कोड अधिक तेज़ क्यों है।


3
बहुत कुछ भी है कि एक हार्डवेयर शोर जनरेटर या ओएस के आई / ओ सामान में एक सीधी रेखा को शामिल नहीं करता है, छद्म यादृच्छिक होने जा रहा है। केवल एक एल्गोरिथ्म द्वारा वास्तविक यादृच्छिकता उत्पन्न नहीं की जा सकती; आपको कहीं से शोर की आवश्यकता है। (कुछ OS 'RNG अपने इनपुट को सामान की माप के द्वारा प्राप्त करते हैं जैसे / जब आप माउस को स्थानांतरित करते हैं, तो सामान टाइप करते हैं, आदि माइक्रोसेकंड के पैमाने पर नैनोसेकंड तक
मापे जाते हैं

@OliCharlesworth: वास्तव में, जहां तक ​​मुझे पता है कि वायुमंडलीय शोर का उपयोग करके केवल सही यादृच्छिक मान पाए जाते हैं।
जीरो वेनवेल

@me ... जल्दबाजी में जवाब देना बेवकूफी है। Math.random pseudorandom है, और भी, यह सिंक्रनाइज़ है
रॉल्फेल

@rolfl: सिंक्रोनाइज़ेशन बहुत अच्छी तरह समझा सकता है कि क्यों Math.random()धीमा है। इसे या तो Randomहर बार एक नया सिंक्रनाइज़ करना होगा या बनाना होगा , और न ही बहुत आकर्षक प्रदर्शन करना होगा। अगर मुझे प्रदर्शन की परवाह है, तो मैं अपना खुद का निर्माण करूंगा new Randomऔर बस इसका उपयोग करूंगा । : P
cHao

@JeroenVannevel रेडियोधर्मी क्षय यादृच्छिक भी है।
आरएक्सएस

3

java.util.Random बहुत अलग नहीं है, एक बुनियादी LCG जिसे नथ द्वारा वर्णित किया गया है। हालाँकि इसके मुख्य 2 मुख्य लाभ / अंतर हैं:

  • थ्रेड सेफ - प्रत्येक अपडेट एक कैस है जो एक साधारण लेखन की तुलना में अधिक महंगा है और एक शाखा की आवश्यकता है (भले ही पूरी तरह से एकल थ्रेडेड भविष्यवाणी की गई हो)। सीपीयू के आधार पर यह महत्वपूर्ण अंतर हो सकता है।
  • अघोषित आंतरिक स्थिति - यह कुछ भी गैर-तुच्छ के लिए बहुत महत्वपूर्ण है। आप चाहते हैं कि यादृच्छिक संख्या पूर्वानुमेय न हो।

नीचे यह java.util.Random में 'रैंडम' पूर्णांक उत्पन्न करने वाला मुख्य रूटीन है।


  protected int next(int bits) {
        long oldseed, nextseed;
        AtomicLong seed = this.seed;
        do {
          oldseed = seed.get();
          nextseed = (oldseed * multiplier + addend) & mask;
        } while (!seed.compareAndSet(oldseed, nextseed));
        return (int)(nextseed >>> (48 - bits));
    }

यदि आप एटॉमिकलॉन्ग और अघोषित संप्रदाय को हटाते हैं (अर्थात सभी बिट्स का उपयोग करते हुए long), तो आपको डबल गुणा / मोडुलो की तुलना में अधिक प्रदर्शन मिलेगा।

अंतिम नोट: Math.randomकुछ भी लेकिन सरल परीक्षणों के लिए उपयोग नहीं किया जाना चाहिए, यह विवाद का खतरा है और यदि आपके पास कुछ जोड़े भी हैं जो इसे समवर्ती प्रदर्शन को कॉल करते हैं। इसकी एक छोटी ज्ञात ऐतिहासिक विशेषता जावा में कैस का परिचय है - एक बदनाम बेंचमार्क (पहले आईबीएम द्वारा आंतरिकता के माध्यम से और फिर सन ने "जावा से कैस बनाया") को हराया।


0

यह यादृच्छिक कार्य है जो मैं अपने खेल के लिए उपयोग करता हूं। यह बहुत तेज़ है, और इसका अच्छा (पर्याप्त) वितरण है।

public class FastRandom {

    public static int randSeed;

      public static final int random()
      {
        // this makes a 'nod' to being potentially called from multiple threads
        int seed = randSeed;

        seed    *= 1103515245;
        seed    += 12345;
        randSeed = seed;
        return seed;
      }

      public static final int random(int range)
      {
        return ((random()>>>15) * range) >>> 17;
      }

      public static final boolean randomBoolean()
      {
         return random() > 0;
      }

       public static final float randomFloat()
       {
         return (random()>>>8) * (1.f/(1<<24));
       }

       public static final double randomDouble() {
           return (random()>>>8) * (1.0/(1<<24));
       }
}

1
यह प्रश्न का उत्तर प्रदान नहीं करता है। किसी लेखक से स्पष्टीकरण मांगने या उसका अनुरोध करने के लिए, उनके पोस्ट के नीचे एक टिप्पणी छोड़ दें।
जॉन विलेमसे

मुझे लगता है कि यह पहले से ही स्थापित था कि मूल एल्गोरिथ्म पर्याप्त अच्छा नहीं है? शायद जो बहुत अच्छा है उसका एक उदाहरण प्रेरणा में कैसे सुधार कर सकता है?
तेरिज

हां, हो सकता है, लेकिन यह सवाल का बिल्कुल भी जवाब नहीं देता है और आपके एल्गोरिथ्म का समर्थन करने वाला कोई डेटा वास्तव में "अच्छा पर्याप्त" नहीं है। आमतौर पर, यादृच्छिक संख्या वाले अल्गोरिटम्स और निकटता से संबंधित एन्क्रिप्शन एल्गोरिदम कभी भी उतने अच्छे नहीं होते जितना कि विशेषज्ञों ने उन्हें प्रोग्रामिंग भाषा में लागू किया। इसलिए, यदि आप अपने दावे का समर्थन कर सकते हैं और इस बारे में विस्तार से बता सकते हैं कि प्रश्न में एल्गोरिथम से बेहतर क्यों है तो आप कम से कम पूछे गए प्रश्न का उत्तर देंगे।
जॉन विलेमसे

अच्छी तरह से ... विशेषज्ञों ने उन्हें प्रोग्रामिंग भाषा में "सही" वितरण के लिए लागू किया, जबकि एक खेल में, आपको कभी भी इसकी आवश्यकता नहीं होती है। आप गति चाहते हैं, और "अच्छा पर्याप्त" वितरण। यह कोड यह प्रदान करता है। यदि यह यहाँ अनुचित है, तो मैं उत्तर को हटा दूंगा, कोई बात नहीं।
तेरेज

मल्टीथ्रेडिंग के बारे में, स्थानीय वेरिएबल का आपका उपयोग एक नो-ऑप है, जैसे कि volatile, कंपाइलर स्थानीय चर को समाप्त करने (या परिचय) के लिए स्वतंत्र है।
मांर्टिनस
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.