Task: Modified random distribution







Python: import random
from typing import List, Callable, Optional


def modifier(x: float) -> float:
    
    return 2*(.5 - x) if x < 0.5 else 2*(x - .5)


def modified_random_distribution(modifier: Callable[[float], float],
                                 n: int) -> List[float]:
    
    d: List[float] = []
    while len(d) < n:
        r1 = prob = random.random()
        if random.random() < modifier(prob):
            d.append(r1)
    return d


if __name__ == '__main__':
    from collections import Counter

    data = modified_random_distribution(modifier, 50_000)
    bins = 15
    counts = Counter(d // (1 / bins) for d in data)
    
    mx = max(counts.values())
    print("   BIN, COUNTS, DELTA: HISTOGRAM\n")
    last: Optional[float] = None
    for b, count in sorted(counts.items()):
        delta = 'N/A' if last is None else str(count - last)
        print(f"  {b / bins:5.2f},  {count:4},  {delta:>4}: "
              f"{'
        last = count





Ada: with Ada.Text_Io;
with Ada.Numerics.Float_Random;
with Ada.Strings.Fixed;

procedure Modified_Distribution is

   Observations : constant := 20_000;
   Buckets      : constant := 25;
   Divider      : constant := 12;
   Char         : constant Character := '*';

   generic
      with function Modifier (X : Float) return Float;
   package Generic_Random is
      function Random return Float;
   end Generic_Random;

   package body Generic_Random is
      package Float_Random renames Ada.Numerics.Float_Random;
      Generator : Float_Random.Generator;

      function Random return Float is
         Random_1 : Float;
         Random_2 : Float;
      begin
         loop
            Random_1 := Float_Random.Random (Generator);
            Random_2 := Float_Random.Random (Generator);
            if Random_2 < Modifier (Random_1) then
               return Random_1;
            end if;
         end loop;
      end Random;

   begin
     Float_Random.Reset (Generator);
   end Generic_Random;

   generic
      Buckets : in Positive;
   package Histograms is
      type Bucket_Index is new Positive range 1 .. Buckets;
      Bucket_Width : constant Float := 1.0 / Float (Buckets);
      procedure Clean;
      procedure Increment_Bucket (Observation : Float);
      function Observations_In (Bucket : Bucket_Index) return Natural;
      function To_Bucket (X : Float) return Bucket_Index;
      function Range_Image (Bucket : Bucket_Index) return String;
   end Histograms;

   package body Histograms is
      Hist : array (Bucket_Index) of Natural := (others => 0);

      procedure Clean is
      begin
         Hist := (others => 0);
      end Clean;

      procedure Increment_Bucket (Observation : Float) is
         Bin : constant Bucket_Index := To_Bucket (Observation);
      begin
         Hist (Bin) := Hist (Bin) + 1;
      end Increment_Bucket;

      function Observations_In (Bucket : Bucket_Index) return Natural
      is (Hist (Bucket));

      function To_Bucket (X : Float) return Bucket_Index
      is (1 + Bucket_Index'Base (Float'Floor (X / Bucket_Width)));

      function Range_Image (Bucket : Bucket_Index) return String is
         package Float_Io is new Ada.Text_Io.Float_Io (Float);
         Image : String := "F.FF..L.LL";
         First : constant Float := Float (Bucket - 1) / Float (Buckets);
         Last  : constant Float := Float (Bucket - 1 + 1) / Float (Buckets);
      begin
         Float_Io.Put (Image (1 .. 4),  First, Exp => 0, Aft => 2);
         Float_Io.Put (Image (7 .. 10), Last,  Exp => 0, Aft => 2);
         return Image;
      end Range_Image;

   begin
      Clean;
   end Histograms;

   function Modifier (X : Float) return Float
   is (if X in Float'First .. 0.5
       then 2.0 * (0.5 - X)
       else 2.0 * (X - 0.5));

   package Modified_Random is
     new Generic_Random (Modifier => Modifier);

   package Histogram_20 is
     new Histograms (Buckets => Buckets);

   function Column (Height : Natural; Char : Character) return String
     renames Ada.Strings.Fixed."*";

   use Ada.Text_Io;
begin
   for N in 1 .. Observations loop
      Histogram_20.Increment_Bucket (Modified_Random.Random);
   end loop;

   Put ("Range      Observations: "); Put (Observations'Image);
   Put ("  Buckets: "); Put (Buckets'Image);
   New_Line;
   for I in Histogram_20.Bucket_Index'Range loop
      Put (Histogram_20.Range_Image (I));
      Put (" ");
      Put (Column (Histogram_20.Observations_In (I) / Divider, Char));
      New_Line;
   end loop;
end Modified_Distribution;