मुझे पार्टी में थोड़ी देर हो गई है लेकिन मुझे एक सामान्य समाधान को लागू करने की आवश्यकता है और यह पता चला है कि कोई भी समाधान मेरी जरूरतों को पूरा नहीं कर सकता है।
स्वीकृत समाधान छोटी श्रेणियों के लिए अच्छा है; हालाँकि, maximum - minimum
बड़ी रेंज के लिए अनंत हो सकता है। तो एक सही संस्करण यह संस्करण हो सकता है:
public static double NextDoubleLinear(this Random random, double minValue, double maxValue)
{
// TODO: some validation here...
double sample = random.NextDouble();
return (maxValue * sample) + (minValue * (1d - sample));
}
यह भी double.MinValue
और के बीच अच्छी तरह से यादृच्छिक संख्या उत्पन्न करता है double.MaxValue
। लेकिन यह एक और "समस्या" का परिचय देता है, जो इस पोस्ट में अच्छी तरह से प्रस्तुत किया गया है : यदि हम ऐसी बड़ी श्रेणियों का उपयोग करते हैं तो मान भी "अनावश्यक" लग सकते हैं। उदाहरण के लिए, 0 के बीच 10,000 यादृच्छिक युगल उत्पन्न करने के बाद और double.MaxValue
सभी मान 2.9579E + 304 और 1.7976E + 308 के बीच थे।
इसलिए मैंने एक और संस्करण भी बनाया, जो एक लघुगणकीय पैमाने पर संख्या उत्पन्न करता है:
public static double NextDoubleLogarithmic(this Random random, double minValue, double maxValue)
{
// TODO: some validation here...
bool posAndNeg = minValue < 0d && maxValue > 0d;
double minAbs = Math.Min(Math.Abs(minValue), Math.Abs(maxValue));
double maxAbs = Math.Max(Math.Abs(minValue), Math.Abs(maxValue));
int sign;
if (!posAndNeg)
sign = minValue < 0d ? -1 : 1;
else
{
// if both negative and positive results are expected we select the sign based on the size of the ranges
double sample = random.NextDouble();
var rate = minAbs / maxAbs;
var absMinValue = Math.Abs(minValue);
bool isNeg = absMinValue <= maxValue ? rate / 2d > sample : rate / 2d < sample;
sign = isNeg ? -1 : 1;
// now adjusting the limits for 0..[selected range]
minAbs = 0d;
maxAbs = isNeg ? absMinValue : Math.Abs(maxValue);
}
// Possible double exponents are -1022..1023 but we don't generate too small exponents for big ranges because
// that would cause too many almost zero results, which are much smaller than the original NextDouble values.
double minExponent = minAbs == 0d ? -16d : Math.Log(minAbs, 2d);
double maxExponent = Math.Log(maxAbs, 2d);
if (minExponent == maxExponent)
return minValue;
// We decrease exponents only if the given range is already small. Even lower than -1022 is no problem, the result may be 0
if (maxExponent < minExponent)
minExponent = maxExponent - 4;
double result = sign * Math.Pow(2d, NextDoubleLinear(random, minExponent, maxExponent));
// protecting ourselves against inaccurate calculations; however, in practice result is always in range.
return result < minValue ? minValue : (result > maxValue ? maxValue : result);
}
कुछ परीक्षण:
यहाँ 0 और Double.MaxValue
दोनों रणनीतियों के साथ 10,000 यादृच्छिक डबल नंबर उत्पन्न करने के लिए हल किए गए परिणाम हैं । परिणाम लघुगणकीय पैमाने का उपयोग करके प्रदर्शित किए जाते हैं:
यद्यपि पहली नज़र में रेखीय यादृच्छिक मान गलत प्रतीत होते हैं, लेकिन आंकड़े बताते हैं कि उनमें से कोई भी अन्य की तुलना में "बेहतर" नहीं है: यहां तक कि रैखिक रणनीति का भी समान वितरण है और मूल्यों के बीच औसत अंतर दोनों रणनीतियों के साथ बहुत समान हैं ।
विभिन्न श्रेणियों के साथ खेलने से मुझे पता चला कि रैखिक रणनीति 0 के बीच की सीमा के साथ "समझदार" हो जाती है और ushort.MaxValue
10.78294704 के "उचित" न्यूनतम मूल्य के साथ ( ulong
न्यूनतम मूल्य 3.03518E + 15 के लिए होता है ; int
: 353341)। ये अलग-अलग पैमानों के साथ प्रदर्शित दोनों रणनीतियों के समान परिणाम हैं:
संपादित करें:
हाल ही में मैंने अपने पुस्तकालयों को खुला स्रोत बनाया , RandomExtensions.NextDouble
पूरी मान्यता के साथ विधि को देखने के लिए स्वतंत्र महसूस करें ।