2009-03-04 1 views
52

में एक यादृच्छिक दशमलव उत्पन्न करना मैं एक यादृच्छिक सिस्टम कैसे प्राप्त कर सकता हूं। डेसिमल? System.Random इसे सीधे समर्थन नहीं करता है।सी #

+4

यह न सिर्फ के बीच एक यादृच्छिक पूर्णांक उत्पन्न करने के लिए आसान होगा , कहें, 1 और 99 9, और परिणाम 100 से विभाजित करें? पूर्व। यादृच्छिक संख्या 1 0.01 और 999 होगा 9.99 –

+0

@StefanZCamilleri आपको उस चीज़ पर निर्भर करता है जिसके लिए आपको यादृच्छिक दशमलव की आवश्यकता है। नीचे दिए गए कुछ उत्तरों के माध्यम से पढ़ा है। संभव दशमलव मानों की पूरी श्रृंखला का प्रतिनिधित्व किया जा सकता है जो वास्तव में बड़ा है और कुछ विचारों को यादृच्छिक इंक को दशमलव कन्स्ट्रक्टर में खिलाने के लिए आवश्यक है। फिर जेनरेट किए गए दशमलव मानों के यादृच्छिक वितरण की वर्दी कितनी समस्या है। –

+0

इसके अलावा, अगर मुझे गलत नहीं लगता है, तो01 1 और 999 के बीच नहीं है। यह 1 से कम है, इसलिए वैध प्रतिक्रिया नहीं होगी। –

उत्तर

40

संपादित करें: हटाया पुराने संस्करण

यह डैनियल संस्करण के लिए समान है, लेकिन पूरी श्रृंखला दे देंगे। यह एक यादृच्छिक "कोई पूर्णांक" मान प्राप्त करने के लिए एक नई विस्तार विधि भी प्रस्तुत करता है, जो मुझे लगता है कि आसान है।

ध्यान दें कि दशमलव का वितरण समान नहीं है।

/// <summary> 
/// Returns an Int32 with a random value across the entire range of 
/// possible values. 
/// </summary> 
public static int NextInt32(this Random rng) 
{ 
    int firstBits = rng.Next(0, 1 << 4) << 28; 
    int lastBits = rng.Next(0, 1 << 28); 
    return firstBits | lastBits; 
} 

public static decimal NextDecimal(this Random rng) 
{ 
    byte scale = (byte) rng.Next(29); 
    bool sign = rng.Next(2) == 1; 
    return new decimal(rng.NextInt32(), 
         rng.NextInt32(), 
         rng.NextInt32(), 
         sign, 
         scale); 
} 
+0

मुझे इस और/या ctor के बारे में आश्चर्य हुआ जो बाइट लेता है [] - लेकिन सभी बाइट [] क्रमपरिवर्तन कानूनी हैं? –

+0

@Marc: मेरी यादें यह है कि वे हैं, और अन्य बिट्स को सिर्फ अनदेखा किया जाता है। मैंने हालांकि जांच नहीं की है। –

+0

मैंने किया, यह सिर्फ एक निजी सीटीआर के माध्यम से पारित किया गया है जैसे कि यह कानूनी था। आपको यह कोशिश करनी चाहिए और देखें कि क्या यह समझ में आता है। कार्यान्वयन छिपा हुआ है (InternalCall) और वह जंक डेटा गणना भ्रष्ट कर सकता है। –

2

मैंने थोड़ा सा इसके साथ परेशान किया।

public class DecimalRandom : Random 
    { 
     public override decimal NextDecimal() 
     { 
      //The low 32 bits of a 96-bit integer. 
      int lo = this.Next(int.MinValue, int.MaxValue); 
      //The middle 32 bits of a 96-bit integer. 
      int mid = this.Next(int.MinValue, int.MaxValue); 
      //The high 32 bits of a 96-bit integer. 
      int hi = this.Next(int.MinValue, int.MaxValue); 
      //The sign of the number; 1 is negative, 0 is positive. 
      bool isNegative = (this.Next(2) == 0); 
      //A power of 10 ranging from 0 to 28. 
      byte scale = Convert.ToByte(this.Next(29)); 

      Decimal randomDecimal = new Decimal(lo, mid, hi, isNegative, scale); 

      return randomDecimal; 
     } 
    } 

संपादित करें:: यह सबसे अच्छा मैं के साथ आ सकता है के रूप में टिप्पणी लो, मध्य में बताया गया है और उच्च int.MaxValue शामिल कभी नहीं कर सकते हैं ताकि दशमलव का पूरी श्रृंखला संभव नहीं है।

+0

यह करेगा ... –

+0

काफी नहीं ... Random.Next (int.MinValue, int.MaxValue) कभी भी int.MaxValue वापस नहीं करेगा। मुझे जवाब मिला है, लेकिन मुझे लगता है कि मैं इसमें सुधार कर सकता हूं। –

+0

सांख्यिकी मेरा मजबूत बिंदु नहीं है, इसलिए मैं शायद गलत हूं, लेकिन मुझे चिंता होगी कि वितरण बहुत समान नहीं हो सकता है। –

1
यहाँ

तुम जाओ ... यादृच्छिक बाइट्स की एक जोड़ी उत्पन्न करने के लिए तहखाने लाइब्रेरी का उपयोग करता है, तो एक दशमलव मान के लिए उन्हें convertes ... देखना MSDN for the decimal constructor

using System.Security.Cryptography; 

public static decimal Next(decimal max) 
{ 
    // Create a int array to hold the random values. 
    Byte[] randomNumber = new Byte[] { 0,0 }; 

    RNGCryptoServiceProvider Gen = new RNGCryptoServiceProvider(); 

    // Fill the array with a random value. 
    Gen.GetBytes(randomNumber); 

    // convert the bytes to a decimal 
    return new decimal(new int[] 
    { 
       0,     // not used, must be 0 
       randomNumber[0] % 29,// must be between 0 and 28 
       0,     // not used, must be 0 
       randomNumber[1] % 2 // sign --> 0 == positive, 1 == negative 
    }) % (max+1); 
} 

एक अलग उपयोग करने के लिए संशोधित संख्याओं की एक बेहतर रेंज देने के लिए दशमलव निर्माता

public static decimal Next(decimal max) 
{ 
    // Create a int array to hold the random values. 
    Byte[] bytes= new Byte[] { 0,0,0,0 }; 

    RNGCryptoServiceProvider Gen = new RNGCryptoServiceProvider(); 

    // Fill the array with a random value. 
    Gen.GetBytes(bytes); 
    bytes[3] %= 29; // this must be between 0 and 28 (inclusive) 
    decimal d = new decimal((int)bytes[0], (int)bytes[1], (int)bytes[2], false, bytes[3]); 

     return d % (max+1); 
    } 
+0

इसका मतलब यह है कि हम विशाल संभव सीमा से 65536 मूल्य तक सीमित हैं, है ना? –

+0

हाँ, यह करता है। :-( –

+2

क्या हम 16-बिट कंप्यूटिंग के दिनों में रह रहे हैं? इसका क्या अर्थ है? –

6

आप आम तौर पर एक यादृच्छिक संख्या-जनरेटर टी से उम्मीद होती है टोपी ने न केवल यादृच्छिक संख्याएं उत्पन्न की, बल्कि संख्याएं समान रूप से यादृच्छिक रूप से उत्पन्न हुईं।

समान रूप से यादृच्छिक की दो परिभाषाएं हैं: discrete uniformly random और continuous uniformly random

विघटित रूप से समान रूप से यादृच्छिक यादृच्छिक संख्या जेनरेटर के लिए समझ में आता है जिसमें विभिन्न संभावित परिणामों की सीमित संख्या होती है। उदाहरण के लिए 1 और 10 के बीच एक पूर्णांक उत्पन्न करना। आप उम्मीद करेंगे कि 4 प्राप्त करने की संभावना 7 हो रही है।

यादृच्छिक संख्या जनरेटर एक सीमा में संख्याएं उत्पन्न करते समय लगातार समान रूप से यादृच्छिक समझ में आता है। उदाहरण के लिए एक जनरेटर जो 0 और 1 के बीच वास्तविक संख्या उत्पन्न करता है, तब आप उम्मीद करेंगे कि 0 और 0.5 के बीच की संख्या प्राप्त करने की संभावना 0.5 और 1.

जब कोई यादृच्छिक संख्या जनरेटर फ्लोटिंग-पॉइंट नंबर उत्पन्न करता है (जो मूल रूप से एक सिस्टम है। डेसिमल है - यह केवल फ्लोटिंग-पॉइंट है जो आधार 10) है, यह तर्कसंगत है कि समान रूप से यादृच्छिक की उचित परिभाषा क्या है:

एक ओर, फ़्लोटिंग के बाद से -पॉइंट नंबर को कंप्यूटर में निश्चित संख्या में बिट्स द्वारा दर्शाया जा रहा है, यह स्पष्ट है कि संभावित परिणामों की एक सीमित संख्या है। तो कोई तर्क दे सकता है कि उचित वितरण एक समान निरंतर वितरण है जिसमें प्रत्येक प्रतिनिधित्व योग्य संख्या समान संभावना है। यह मूल रूप से Jon Skeet's और John Leidegren's कार्यान्वयन करता है।

दूसरी तरफ, कोई तर्क दे सकता है कि एक फ्लोटिंग-पॉइंट नंबर वास्तविक संख्या के अनुमान के रूप में माना जाता है, फिर भी हम निरंतर यादृच्छिक संख्या जनरेटर के व्यवहार का अनुमान लगाने की कोशिश करके बेहतर होंगे - भले ही वास्तविक आरएनजी वास्तव में अलग हैं। यह रैंडम से प्राप्त व्यवहार है।NextDouble(), जहां - 0.00001-0.00002 की सीमा में लगभग कई प्रतिनिधित्व योग्य संख्याएं हैं, भले ही 0.8-0.9 की सीमा में हैं, आप दूसरी श्रेणी में एक हजार गुना अधिक होने की संभावना रखते हैं - जैसा कि आप करेंगे उम्मीद करते हैं।

तो एक Random.NextDecimal() का उचित कार्यान्वयन संभवतः लगातार समान रूप से वितरित किया जाना चाहिए।

public static decimal NextDecimal(this Random rng) 
{ 
    return new decimal(rng.NextInt32(), 
         rng.NextInt32(), 
         rng.Next(0x204FCE5E), 
         false, 
         0); 
} 

तुम भी कैसे पर एक समान वितरण प्राप्त करने के बारे में बात कर सकते हैं:

यहाँ जॉन स्कीट के जवाब का एक सरल भिन्नता है कि समान रूप से (मैं उसकी NextInt32() विस्तार विधि का पुन: उपयोग) 0 और 1 के बीच वितरित किया जाता है है दशमलव की पूरी श्रृंखला। शायद यह करने के लिए एक आसान तरीका है, लेकिन John Leidegren's answer के इस मामूली संशोधन एक अपेक्षाकृत समान वितरण का उत्पादन करना चाहिए:

private static int GetDecimalScale(Random r) 
{ 
    for(int i=0;i<=28;i++){ 
    if(r.NextDouble() >= 0.1) 
     return i; 
    } 
    return 0; 
} 

public static decimal NextDecimal(this Random r) 
{ 
    var s = GetDecimalScale(r); 
    var a = (int)(uint.MaxValue * r.NextDouble()); 
    var b = (int)(uint.MaxValue * r.NextDouble()); 
    var c = (int)(uint.MaxValue * r.NextDouble()); 
    var n = r.NextDouble() >= 0.5; 
    return new Decimal(a, b, c, n, s); 
} 

असल में, हम यह सुनिश्चित करें कि पैमाने के मूल्यों इसी रेंज के आकार के अनुपात में चुना जाता है बनाते हैं।

इसका मतलब है कि हम समय की 0 90% के पैमाने मिलना चाहिए - समय से 1 9% के पैमाने, आदि

अभी भी कर रहे हैं - के बाद से है कि सीमा संभव सीमा के 90% होता है कार्यान्वयन के साथ कुछ समस्याएं, क्योंकि यह ध्यान में रखती है कि कुछ संख्याओं में कई प्रतिनिधित्व होते हैं - लेकिन यह अन्य कार्यान्वयन की तुलना में एक समान वितरण के करीब होना चाहिए।

+0

आपका स्केल अनुपात 0.1 क्यों है? यह मेरे लिए समान नहीं लगता है। शायद 1.0/28 अधिक समान है। –

+0

और कैसे यह '28 * r.NextDouble()' –

+0

से अलग है, यह काफी रोचक है, क्योंकि हम पूरी तरह से कचरे में डाल रहे हैं। माना जाता है कि आप 0 और 1 के बीच एक अच्छा वर्दी वितरण चाहते हैं और फिर आप इसे स्केल करेंगे आपको कभी भी आवश्यकता होती है। हालांकि मैं यह देखने में असफल रहा कि यह कैसे पूरा करता है? –

1
static decimal GetRandomDecimal() 
    { 

     int[] DataInts = new int[4]; 
     byte[] DataBytes = new byte[DataInts.Length * 4]; 

     // Use cryptographic random number generator to get 16 bytes random data 
     RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider(); 

     do 
     { 
      rng.GetBytes(DataBytes); 

      // Convert 16 bytes into 4 ints 
      for (int index = 0; index < DataInts.Length; index++) 
      { 
       DataInts[index] = BitConverter.ToInt32(DataBytes, index * 4); 
      } 

      // Mask out all bits except sign bit 31 and scale bits 16 to 20 (value 0-31) 
      DataInts[3] = DataInts[3] & (unchecked((int)2147483648u | 2031616)); 

      // Start over if scale > 28 to avoid bias 
     } while (((DataInts[3] & 1835008) == 1835008) && ((DataInts[3] & 196608) != 0)); 

     return new decimal(DataInts); 
    } 
    //end 
5

यहां रेंज कार्यान्वयन के साथ दशमलव यादृच्छिक है जो मेरे लिए ठीक काम करता है। बाहर रेडीमेड कार्यान्वयन के लिए नीचे दिए गए लिंक

public static decimal NextDecimal(this Random rnd, decimal from, decimal to) 
{ 
    byte fromScale = new System.Data.SqlTypes.SqlDecimal(from).Scale; 
    byte toScale = new System.Data.SqlTypes.SqlDecimal(to).Scale; 

    byte scale = (byte)(fromScale + toScale); 
    if (scale > 28) 
     scale = 28; 

    decimal r = new decimal(rnd.Next(), rnd.Next(), rnd.Next(), false, scale); 
    if (Math.Sign(from) == Math.Sign(to) || from == 0 || to == 0) 
     return decimal.Remainder(r, to - from) + from; 

    bool getFromNegativeRange = (double)from + rnd.NextDouble() * ((double)to - (double)from) < 0; 
    return getFromNegativeRange ? decimal.Remainder(r, -from) + from : decimal.Remainder(r, to); 
} 
1

चेक कि मदद करनी चाहिए:

MathNet.Numerics, Random Numbers and Probability Distributions

व्यापक वितरण विशेष रूप से ब्याज की हैं, यादृच्छिक संख्या जनरेटर के शीर्ष (MersenneTwister, आदि पर बनाया गया ।) सीधे सिस्टम से निकाला गया है। यादृच्छिक, सभी आसान विस्तार विधियां प्रदान करते हैं (जैसे NextFullRangeInt32, NextFullRangeInt64, NextDecimal, आदि)। आप, निश्चित रूप से, केवल डिफ़ॉल्ट SystemRandomSource का उपयोग कर सकते हैं, जो कि बस सिस्टम है। विस्तार विधियों के साथ यादृच्छिक।

ओह, और यदि आपको इसकी आवश्यकता हो तो आप अपने आरएनजी उदाहरणों को थ्रेड सुरक्षित बना सकते हैं।

वास्तव में बहुत आसान है!

यह एक पुराना सवाल है, लेकिन जो लोग इसे पढ़ रहे हैं, उनके लिए पहिया का पुन: आविष्कार क्यों किया जाता है?

3

मुझे पता है कि यह एक पुराना सवाल है, लेकिन distribution issue Rasmus Faber described ने मुझे परेशान रखा ताकि मैं निम्नलिखित के साथ आया। मैंने NextInt32 implementation provided by Jon Skeet पर गहराई से नहीं देखा है और मुझे लगता है कि यह उम्मीद है कि यह Random.Next() के समान वितरण है।

//Provides a random decimal value in the range [0.0000000000000000000000000000, 0.9999999999999999999999999999) with (theoretical) uniform and discrete distribution. 
public static decimal NextDecimalSample(this Random random) 
{ 
    var sample = 1m; 
    //After ~200 million tries this never took more than one attempt but it is possible to generate combinations of a, b, and c with the approach below resulting in a sample >= 1. 
    while (sample >= 1) 
    { 
     var a = random.NextInt32(); 
     var b = random.NextInt32(); 
     //The high bits of 0.9999999999999999999999999999m are 542101086. 
     var c = random.Next(542101087); 
     sample = new Decimal(a, b, c, false, 28); 
    } 
    return sample; 
} 

public static decimal NextDecimal(this Random random) 
{ 
    return NextDecimal(random, decimal.MaxValue); 
} 

public static decimal NextDecimal(this Random random, decimal maxValue) 
{ 
    return NextDecimal(random, decimal.Zero, maxValue); 
} 

public static decimal NextDecimal(this Random random, decimal minValue, decimal maxValue) 
{ 
    var nextDecimalSample = NextDecimalSample(random); 
    return maxValue * nextDecimalSample + minValue * (1 - nextDecimalSample); 
} 
1

ईमानदार होने के लिए मुझे विश्वास नहीं है कि सी # दशमलव के आंतरिक प्रारूप में कई लोग सोचते हैं। इस कारण से कम से कम यहां दिए गए कुछ समाधान संभवतः अमान्य हैं या लगातार काम नहीं कर सकते हैं।निम्नलिखित 2 नंबर पर विचार करें और कैसे वे दशमलव प्रारूप में जमा हो जाती है:

0.999999999999999m 
Sign: 00 
96-bit integer: 00 00 00 00 FF 7F C6 A4 7E 8D 03 00 
Scale: 0F 

और

0.9999999999999999999999999999m 
Sign: 00 
96-bit integer: 5E CE 4F 20 FF FF FF 0F 61 02 25 3E 
Scale: 1C 

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

प्रयोग में मैंने पाया कि संख्या 0.9 99 99 99 99 99 99 99 99 99 99 99 99 999 मीटर है, जिसमें 28 नाइन हैं, दशमलव की अधिकतम संख्या 1.0 मीटर तक पहुंचने से पहले संभव है।

इसके अलावा प्रयोग साबित कर दिया निम्नलिखित कोड मूल्य 0.9999999999999999999999999999m को चर "दिसं" सेट:

double DblH = 0.99999999999999d; 
double DblL = 0.99999999999999d; 
decimal Dec = (decimal)DblH + (decimal)DblL/1E14m; 

यह इस खोज है कि मैं यादृच्छिक वर्ग के लिए एक्सटेंशन में देखा जा सकता है कि के साथ आया था से है नीचे कोड मेरा मानना ​​है कि यह कोड पूरी तरह कार्यात्मक और अच्छे कामकाजी क्रम में है, लेकिन अन्य आंखों के लिए गलतियों के लिए इसे जांचने में खुशी होगी। मैं एक सांख्यिकीविद् नहीं हूं इसलिए मैं यह नहीं कह सकता कि यह कोड वास्तव में दशमलव के समान वितरण का उत्पादन करता है, लेकिन अगर मुझे लगता है कि मैं कहूंगा कि यह पूर्णता में विफल रहता है लेकिन बहुत करीब आता है (जैसा कि 51 ट्रिलियन में से 1 कॉल में से एक है संख्याओं की कुछ सीमा)।

पहले NextDecimal() फ़ंक्शन के बराबर या 0.0m से अधिक और 1.0m से कम मूल्यों का उत्पादन करना चाहिए। डू/जबकि कथन रैंडएच और रैंडल को मूल्य से 0.999 99 99 99 99 999 डी से अधिक होने से रोकता है जब तक वे उस मूल्य से नीचे न हों। मेरा मानना ​​है कि कभी भी दोहराने वाले इस लूप की बाधाएं 51 ट्रिलियन में हैं (शब्द पर जोर देती है, मुझे अपने गणित पर भरोसा नहीं है)। बदले में यह कार्यों को रिटर्न वैल्यू को 1.0 मीटर तक गोल करने से रोकना चाहिए।

दूसरा NextDecimal() फ़ंक्शन केवल पूर्णांकों के बजाय दशमलव मान के साथ, Random.Next() फ़ंक्शन के रूप में ही काम करना चाहिए। मैं वास्तव में इस दूसरे NextDecimal() फ़ंक्शन का उपयोग नहीं कर रहा हूं और इसका परीक्षण नहीं किया है। यह काफी सरल है, इसलिए मुझे लगता है कि मेरे पास यह सही है, लेकिन फिर से, मैंने इसका परीक्षण नहीं किया है - इसलिए आप यह सुनिश्चित करना चाहते हैं कि यह उस पर भरोसा करने से पहले सही तरीके से काम कर रहा है।

public static class ExtensionMethods { 
    public static decimal NextDecimal(this Random rng) { 
     double RandH, RandL; 
     do { 
      RandH = rng.NextDouble(); 
      RandL = rng.NextDouble(); 
     } while((RandH > 0.99999999999999d) || (RandL > 0.99999999999999d)); 
     return (decimal)RandH + (decimal)RandL/1E14m; 
    } 
    public static decimal NextDecimal(this Random rng, decimal minValue, decimal maxValue) { 
     return rng.NextDecimal() * (maxValue - minValue) + minValue; 
    } 
} 
2

यह आसान सामान की शक्ति के माध्यम भी है, ऐसा करने के लिए:

var rand = new Random(); 
var item = new decimal(rand.NextDouble()); 
0

मैं 9 दशमलव स्थानों के लिए "यादृच्छिक" दशमलव उत्पन्न करना चाहता था। मेरा दृष्टिकोण सिर्फ एक डबल उत्पन्न करना और दशमलव के लिए इसे विभाजित करना था।

int randomInt = rnd.Next(0, 100); 

double randomDouble = rnd.Next(0, 999999999); 
decimal randomDec = Convert.ToDecimal(randomint) + Convert.ToDecimal((randomDouble/1000000000)); 

"randomInt" दशमलव स्थान से पहले नंबर है, तो आप सिर्फ 0. डाल

0

विभाजित बाद में दशमलव अंक आसानी से हटा "9" रों यादृच्छिक में और "0" रों कम करने के लिए कर सकता है ओपी सवाल बहुत गले लगा रहा है और बस एक यादृच्छिक प्रणाली चाहते हैं। बिना किसी प्रतिबंध के डेसिमल, नीचे एक बहुत ही सरल समाधान है जो मेरे लिए काम करता है।

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

Random rnd = new Random(); 
decimal val; 
int decimal_places = 2; 
val = Math.Round(new decimal(rnd.NextDouble()), decimal_places); 

मेरी विशिष्ट मामले में, मुझे एक यादृच्छिक दशमलव एक पैसा स्ट्रिंग के रूप में उपयोग करने के लिए के लिए देख रहा था, तो मेरा पूरा समाधान था:

string value; 
value = val = Math.Round(new decimal(rnd.NextDouble()) * 1000,2).ToString("0.00", System.Globalization.CultureInfo.InvariantCulture);