Task: Modified random distribution




Go: package main

import (
    "fmt"
    "math"
    "math/rand"
    "strings"
    "time"
)

func rng(modifier func(x float64) float64) float64 {
    for {
        r1 := rand.Float64()
        r2 := rand.Float64()
        if r2 < modifier(r1) {
            return r1
        }
    }
}

func commatize(n int) string {
    s := fmt.Sprintf("%d", n)
    if n < 0 {
        s = s[1:]
    }
    le := len(s)
    for i := le - 3; i >= 1; i -= 3 {
        s = s[0:i] + "," + s[i:]
    }
    if n >= 0 {
        return s
    }
    return "-" + s
}

func main() {
    rand.Seed(time.Now().UnixNano())
    modifier := func(x float64) float64 {
        if x < 0.5 {
            return 2 * (0.5 - x)
        }
        return 2 * (x - 0.5)
    }
    const (
        N              = 100000
        NUM_BINS       = 20
        HIST_CHAR      = "■"
        HIST_CHAR_SIZE = 125
    )
    bins := make([]int, NUM_BINS) 
    binSize := 1.0 / NUM_BINS
    for i := 0; i < N; i++ {
        rn := rng(modifier)
        bn := int(math.Floor(rn / binSize))
        bins[bn]++
    }

    fmt.Println("Modified random distribution with", commatize(N), "samples in range [0, 1):\n")
    fmt.Println("    Range           Number of samples within that range")
    for i := 0; i < NUM_BINS; i++ {
        hist := strings.Repeat(HIST_CHAR, int(math.Round(float64(bins[i])/HIST_CHAR_SIZE)))
        fi := float64(i)
        fmt.Printf("%4.2f ..< %4.2f  %s %s\n", binSize*fi, binSize*(fi+1), hist, commatize(bins[i]))
    }
}








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;