Skip to content

Latest commit

 

History

History
59 lines (55 loc) · 2.28 KB

2020-01-02.md

File metadata and controls

59 lines (55 loc) · 2.28 KB

Date: January 2, 2020
Original Post: https://gist.github.com/ZacharyPatten/728658c5bc13634ee10cdaf3d6ac7baa

Generate Random Weighted Data

using System;
using System.Collections.Generic;
using System.Linq;

namespace MathSyntax
{
    class Program
    {
        static void Main(string[] args)
        {
            const int iterations = 10000000;
            Random random = new Random();
            IEnumerable<(int, double)> pool = Enumerable.Range(0, 10).Select(i => (i, (double)i));
            int[] occurences = new int[pool.Count()];
            for (int i = 0; i < iterations; i++)
                occurences[random.Next(pool)]++;
            double totalWeight = pool.Select(x => x.Item2).Sum();
            double[] expectedProbability = new double[pool.Count()];
            for (int i = 0; i < expectedProbability.Length; i++)
                expectedProbability[i] = (double)i / totalWeight;
            for (int i = 0; i < expectedProbability.Length; i++)
                Console.WriteLine("Value: " + i + " Expected: " + expectedProbability[i] + " Actual: " + ((double)occurences[i] / (double)iterations));
        }
    }

    public static class RandomExtensions
    {
        public static T Next<T>(this Random random, IEnumerable<(T Value, double Weight)> pool)
        {
            double totalWeight = 0;
            foreach (var possibility in pool)
            {
                if (possibility.Weight < 0)
                    throw new ArgumentOutOfRangeException("A value in the pool had a weight less than zero.");
                totalWeight += possibility.Weight;
            }
            if (totalWeight == 0)
                throw new ArgumentOutOfRangeException("The total weight of all values in the pool was zero.");
            if (double.IsInfinity(totalWeight))
                throw new ArgumentOutOfRangeException("The total weight of all values in the pool was an infinite double.");
            double randomDouble = random.NextDouble();
            double range = 0;
            foreach (var possibility in pool)
            {
                range += possibility.Weight;
                if (randomDouble < range / totalWeight)
                    return possibility.Value;
            }
            throw new Exception("There is a bug in the code.");
        }
    }
}