আমি পার্টিতে কিছুটা দেরি করেছি তবে আমার একটি সাধারণ সমাধান বাস্তবায়ন করা দরকার এবং এটি প্রমাণিত হয়েছে যে সমাধানগুলির কোনওটিই আমার চাহিদা পূরণ করতে পারে না।
স্বীকৃত সমাধান ছোট রেঞ্জের জন্য ভাল; তবে 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 এবং double.MaxValue
সমস্ত মানের মধ্যে 10,000 টি এলোমেলো দ্বিগুণ উত্পন্ন করার পরে 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
সম্পূর্ণ বৈধতা সহ পদ্ধতিটি নির্দ্বিধায় দেখতে পারি ।