Modified random distribution

From Rosetta Code
Task
Modified random distribution
You are encouraged to solve this task according to the task description, using any language you may know.

Given a random number generator, (rng), generating numbers in the range 0.0 .. 1.0 called rgen, for example; and a function modifier(x) taking an number in the same range and generating the probability that the input should be generated, in the same range 0..1; then implement the following algorithm for generating random numbers to the probability given by function modifier:

while True:
    random1 = rgen()
    random2 = rgen()
    if random2 < modifier(random1):
        answer = random1
        break
    endif
endwhile
Task
  • Create a modifier function that generates a 'V' shaped probability of number generation using something like, for example:
                      modifier(x)  =  2*(0.5 - x)  if x < 0.5  else 2*(x - 0.5) 
  • Create a generator of random numbers with probabilities modified by the above function.
  • Generate >= 10,000 random numbers subject to the probability modification.
  • Output a textual histogram with from 11 to 21 bins showing the distribution of the random numbers generated.


Show your output here, on this page.

11l

Translation of: Python
F modifier(Float x) -> Float
   R I x < 0.5 {2 * (.5 - x)} E 2 * (x - .5)

F modified_random_distribution((Float -> Float) modifier, Int n) -> [Float]
   [Float] d
   L d.len < n
      V prob = random:()
      I random:() < modifier(prob)
         d.append(prob)
   R d

V data = modified_random_distribution(modifier, 50'000)
V bins = 15
DefaultDict[Int, Int] counts
L(d) data
   counts[d I/ (1 / bins)]++

V mx = max(counts.values())
print("   BIN, COUNTS, DELTA: HISTOGRAM\n")
Float? last
L(b, count) sorted(counts.items())
   V delta = I last == N {‘N/A’} E String(count - last)
   print(‘  #2.2,  #4,  #4: ’.format(Float(b) / bins, count, delta)‘’(‘#’ * Int(40 * count / mx)))
   last = count
Output:
   BIN, COUNTS, DELTA: HISTOGRAM

   0.00,  6218,   N/A: #######################################
   0.07,  5313,  -905: #################################
   0.13,  4328,  -985: ###########################
   0.20,  3572,  -756: ######################
   0.27,  2642,  -930: ################
   0.33,  1805,  -837: ###########
   0.40,   877,  -928: #####
   0.47,   216,  -661: #
   0.53,   887,   671: #####
   0.60,  1779,   892: ###########
   0.67,  2644,   865: ################
   0.73,  3618,   974: #######################
   0.80,  4495,   877: ############################
   0.87,  5341,   846: ##################################
   0.93,  6265,   924: ########################################

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;
Output:
Range      Observations:  20000  Buckets:  25
0.00..0.04 ****************************************************************************
0.04..0.08 ************************************************************************
0.08..0.12 **************************************************************
0.12..0.16 **********************************************************
0.16..0.20 **************************************************
0.20..0.24 ******************************************
0.24..0.28 ***************************************
0.28..0.32 *******************************
0.32..0.36 *************************
0.36..0.40 *******************
0.40..0.44 ************
0.44..0.48 *****
0.48..0.52 *
0.52..0.56 *******
0.56..0.60 ***********
0.60..0.64 ********************
0.64..0.68 ***************************
0.68..0.72 **********************************
0.72..0.76 **************************************
0.76..0.80 ********************************************
0.80..0.84 *************************************************
0.84..0.88 **********************************************************
0.88..0.92 ****************************************************************
0.92..0.96 *******************************************************************
0.96..1.00 ************************************************************************

ALGOL 68

Translation of: Wren – with slightly modified output
BEGIN # Modified random distribution - translation of the Wren sample #

    next random; # initialise the random number generator #

    PROC rng = ( PROC(REAL)REAL modifier )REAL:
         BEGIN
            REAL r1, r2;
            WHILE
                r1 := random;
                r2 := random;
                r2 >= modifier( r1 )
            DO SKIP OD;
            r1
         END # rng # ;

    PROC modifier = ( REAL x )REAL: 2 * ABS ( 0.5 - x );

    INT  n              = 100 000;
    INT  num bins       = 21;
    REAL bin size       = 1 / num bins;
    CHAR hist char      = "#";
    INT  hist char size = 125;
    [ 0 : num bins - 1 ]INT  bins ; FOR i FROM LWB bins TO UPB bins DO bins[ i ] := 0 OD;
    FOR i FROM 0 TO n DO
        bins[ ENTIER ( rng( modifier ) / bin size ) ] +:= 1
    OD;

    PROC f2 = ( REAL v )STRING:        # formatting routine #
         BEGIN
            STRING result := fixed( ABS v, 0, 2 );
            IF result[ LWB result ] = "." THEN "0" +=: result FI;
            IF v < 0 THEN "-" +=: result FI;
            result
         END # FMT # ;

    print( ( "Modified random distribution with ", whole( n, 0 ), " samples in range [0, 1):", newline ) );
    print( ( "    Range       Number of samples within that range", newline ) );
    FOR i FROM LWB bins TO UPB bins DO
        STRING hist = hist char * ROUND ( bins[ i ] / hist char size );
        print( ( f2( bin size * i ), " ..< " ) );
        print( ( f2( bin size * ( i + 1 ) ), "  ", whole( bins[ i ], -5 ), " ", hist, newline ) )
    OD

END
Output:
Modified random distribution with 100000 samples in range [0, 1):
    Range       Number of samples within that range
0.00 ..< 0.05   8990 ########################################################################
0.05 ..< 0.10   8043 ################################################################
0.10 ..< 0.14   7265 ##########################################################
0.14 ..< 0.19   6366 ###################################################
0.19 ..< 0.24   5442 ############################################
0.24 ..< 0.29   4631 #####################################
0.29 ..< 0.33   3805 ##############################
0.33 ..< 0.38   2780 ######################
0.38 ..< 0.43   1725 ##############
0.43 ..< 0.48    907 #######
0.48 ..< 0.52    236 ##
0.52 ..< 0.57    915 #######
0.57 ..< 0.62   1778 ##############
0.62 ..< 0.67   2696 ######################
0.67 ..< 0.71   3657 #############################
0.71 ..< 0.76   4539 ####################################
0.76 ..< 0.81   5382 ###########################################
0.81 ..< 0.86   6337 ###################################################
0.86 ..< 0.90   7230 ##########################################################
0.90 ..< 0.95   8173 #################################################################
0.95 ..< 1.00   9104 #########################################################################

C++

#include <cmath>
#include <cstdint>
#include <functional>
#include <iomanip>
#include <iostream>
#include <random>
#include <string>
#include <vector>

std::random_device random;
std::mt19937 generator(random());
std::uniform_real_distribution<double> distribution(0.0F, 1.0F);

double modifier(const double& x) {
	return ( x < 0.5 ) ? 2 * ( 0.5 - x ) : 2 * ( x - 0.5 );
}

double modified_random(const std::function<double(double)>& modify) {
	double result = -1.0;

	while ( result < 0.0 ) {
		double random_one = distribution(generator);
		double random_two = distribution(generator);
		if ( random_two < modify(random_one) ) {
			result = random_one;
		}
	}
	return result;
}

int main() {
	const int32_t sample_size = 100'000;
	const int32_t bin_count = 20;
	const double bin_size = 1.0 / bin_count;

	std::vector<int32_t> bins(bin_count, 0);

	for ( int32_t i = 0; i < sample_size; ++i ) {
		double random = modified_random(modifier);
		int32_t bin_number = floor(random / bin_size);
		bins[bin_number]++;
	}

	std::cout << "Modified random distribution with " << sample_size << " samples in range [0, 1):" 
              << std::endl << std::endl;
	std::cout << "    Range           		  Number of samples within range" << std::endl;

	const int32_t scale_factor = 125;
	for ( float i = 0.0; i < bin_count; ++i ) {
		std::string histogram = " " + std::string(bins[i] / scale_factor, '#') + " ";
		std::cout << std::fixed << std::setw(4)<< std::setprecision(2) << i / bin_count << " ..< "
				  << std::setw(4) << ( i + 1.0 ) / bin_count << histogram << bins[i] << std::endl;
	}
}
Output:
Modified random distribution with 100000 samples in range [0, 1):

    Range           		  Number of samples within range
0.00 ..< 0.05 ############################################################################ 9581
0.05 ..< 0.10 ##################################################################### 8662
0.10 ..< 0.15 ############################################################ 7516
0.15 ..< 0.20 ################################################### 6405
0.20 ..< 0.25 ############################################ 5595
0.25 ..< 0.30 #################################### 4502
0.30 ..< 0.35 ########################### 3464
0.35 ..< 0.40 ################### 2466
0.40 ..< 0.45 ############ 1525
0.45 ..< 0.50 #### 508
0.50 ..< 0.55 ### 482
0.55 ..< 0.60 ########### 1479
0.60 ..< 0.65 ################### 2494
0.65 ..< 0.70 ########################### 3440
0.70 ..< 0.75 ##################################### 4656
0.75 ..< 0.80 ############################################ 5544
0.80 ..< 0.85 ################################################### 6483
0.85 ..< 0.90 ########################################################### 7411
0.90 ..< 0.95 ################################################################### 8389
0.95 ..< 1.00 ########################################################################### 9398

Factor

Works with: Factor version 0.99 2021-02-05
USING: assocs assocs.extras formatting io kernel math
math.functions math.statistics random sequences
tools.memory.private ;

: modifier ( x -- y ) 0.5 over 0.5 < [ swap ] when - dup + ;

: random-unit-by ( quot: ( x -- y ) -- z )
    random-unit dup pick call random-unit 2dup >
    [ 2drop nip ] [ 3drop random-unit-by ] if ; inline recursive

: data ( n quot bins -- histogram )
    '[ _ random-unit-by _ * >integer ] replicate histogram ;
    inline

:: .histogram ( h -- )
    
    h assoc-size :> buckets   ! number of buckets
    h sum-values :> total     ! items in histogram
    h values supremum :> max  ! largest bucket (as in most occurrences)
    40 :> size                ! max size of a bar

    total commas buckets
    "Bin          Histogram (%s items, %d buckets)\n" printf

    h [| k v |
        k buckets / dup buckets recip + "[%.2f, %.2f) " printf
        size v * max / ceiling
        [ "▇" write ] times bl bl v commas print
    ] assoc-each ;

"Modified random distribution of values in [0, 1):" print nl
100,000 [ modifier ] 20 data .histogram
Output:
Modified random distribution of values in [0, 1):

Bin          Histogram (100,000 items, 20 buckets)
[0.00, 0.05) ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇  9,416
[0.05, 0.10) ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇  8,498
[0.10, 0.15) ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇  7,432
[0.15, 0.20) ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇  6,415
[0.20, 0.25) ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇  5,558
[0.25, 0.30) ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇  4,489
[0.30, 0.35) ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇  3,538
[0.35, 0.40) ▇▇▇▇▇▇▇▇▇▇▇  2,532
[0.40, 0.45) ▇▇▇▇▇▇▇  1,553
[0.45, 0.50) ▇▇▇  490
[0.50, 0.55) ▇▇▇  517
[0.55, 0.60) ▇▇▇▇▇▇▇  1,467
[0.60, 0.65) ▇▇▇▇▇▇▇▇▇▇▇  2,519
[0.65, 0.70) ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇  3,559
[0.70, 0.75) ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇  4,546
[0.75, 0.80) ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇  5,569
[0.80, 0.85) ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇  6,444
[0.85, 0.90) ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇  7,428
[0.90, 0.95) ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇  8,487
[0.95, 1.00) ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇  9,543

FreeBASIC

#define NRUNS 100000
#define NBINS 20

function modifier( x as double ) as double
    return iif(x < 0.5, 2*(0.5 - x), 2*(x - 0.5))
end function

function modrand() as double
    dim as double random1, random2
    do
        random1 = rnd
        random2 = rnd
        if random2 < modifier(random1) then
            return random1
        endif
    loop
end function

function histo( byval bn as uinteger ) as string
    dim as double db = NRUNS/(50*NBINS)
    dim as string h
    while bn > db:
        h = h + "#"
        bn -= db
    wend
    return h
    
end function

dim as uinteger bins(0 to NBINS-1), i, b
dim as double db = 1./NBINS, rand

randomize timer

for i = 1 to NRUNS
    rand = modrand()
    b = int(rand/db)
    bins(b) += 1
next i

for b = 0 to NBINS-1
    print using "Bin ## (#.## to #.##): & ####";b;b*db;(b+1)*db;histo(bins(b));bins(b)
next b
Output:
Bin  0 (0.00 to 0.05): ############################################################################################## 9479
Bin  1 (0.05 to 0.10): #################################################################################### 8499
Bin  2 (0.10 to 0.15): ########################################################################## 7416
Bin  3 (0.15 to 0.20): ################################################################## 6650
Bin  4 (0.20 to 0.25): ###################################################### 5457
Bin  5 (0.25 to 0.30): ############################################ 4416
Bin  6 (0.30 to 0.35): ################################## 3469
Bin  7 (0.35 to 0.40): ######################## 2481
Bin  8 (0.40 to 0.45): ############## 1466
Bin  9 (0.45 to 0.50): ####  489
Bin 10 (0.50 to 0.55): ####  475
Bin 11 (0.55 to 0.60): ############## 1472
Bin 12 (0.60 to 0.65): ######################### 2548
Bin 13 (0.65 to 0.70): #################################### 3617
Bin 14 (0.70 to 0.75): ############################################# 4538
Bin 15 (0.75 to 0.80): ####################################################### 5590
Bin 16 (0.80 to 0.85): ############################################################### 6395
Bin 17 (0.85 to 0.90): ########################################################################### 7538
Bin 18 (0.90 to 0.95): #################################################################################### 8401
Bin 19 (0.95 to 1.00): ################################################################################################ 9604

Fōrmulæ

Fōrmulæ programs are not textual, visualization/edition of programs is done showing/manipulating structures but not text. Moreover, there can be multiple visual representations of the same program. Even though it is possible to have textual representation —i.e. XML, JSON— they are intended for storage and transfer purposes more than visualization and edition.

Programs in Fōrmulæ are created/edited online in its website.

In this page you can see and run the program(s) related to this task and their results. You can also change either the programs or the parameters they are called with, for experimentation, but remember that these programs were created with the main purpose of showing a clear solution of the task, and they generally lack any kind of validation.

Solution

The following is the modifier random distribution function. It does not contain the modifier function, it is passed as a lambda expression:

File:Fōrmulæ - Modified random distribution 01.png

The example modifier is the following:

File:Fōrmulæ - Modified random distribution 02.png

The following functions groups a list of numbers in the given number of bins, producing the data necessary for a histogram.

File:Fōrmulæ - Modified random distribution 03.png

File:Fōrmulæ - Modified random distribution 04.png

File:Fōrmulæ - Modified random distribution 05.png

Test case 1. Showing the histogram of 50,000 numbers in 5 bins

File:Fōrmulæ - Modified random distribution 06.png

File:Fōrmulæ - Modified random distribution 07.png

Test case 2. Showing the histogram of 50,000 numbers in 20 bins

File:Fōrmulæ - Modified random distribution 08.png

File:Fōrmulæ - Modified random distribution 09.png

Test case 3. Showing the histogram of 50,000 numbers in 100 bins

File:Fōrmulæ - Modified random distribution 10.png

File:Fōrmulæ - Modified random distribution 11.png

Go

Translation of: Wren
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) // all zero by default
    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]))
    }
}
Output:

Specimen run:

Modified random distribution with 100,000 samples in range [0, 1):

    Range           Number of samples within that range
0.00 ..< 0.05  ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 9,396
0.05 ..< 0.10  ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 8,434
0.10 ..< 0.15  ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 7,484
0.15 ..< 0.20  ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 6,576
0.20 ..< 0.25  ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 5,516
0.25 ..< 0.30  ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 4,625
0.30 ..< 0.35  ■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 3,478
0.35 ..< 0.40  ■■■■■■■■■■■■■■■■■■■■ 2,506
0.40 ..< 0.45  ■■■■■■■■■■■■ 1,504
0.45 ..< 0.50  ■■■■ 505
0.50 ..< 0.55  ■■■■ 511
0.55 ..< 0.60  ■■■■■■■■■■■■■ 1,563
0.60 ..< 0.65  ■■■■■■■■■■■■■■■■■■■■■ 2,582
0.65 ..< 0.70  ■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 3,520
0.70 ..< 0.75  ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 4,326
0.75 ..< 0.80  ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 5,489
0.80 ..< 0.85  ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 6,589
0.85 ..< 0.90  ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 7,472
0.90 ..< 0.95  ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 8,592
0.95 ..< 1.00  ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 9,332

Haskell

The modifier is a pure function which consumes a sequence of numbers (probably, random) and applies a modification rule to it.

import System.Random
import Data.List
import Text.Printf

modify :: Ord a => (a -> a) -> [a] -> [a]
modify f = foldMap test . pairs 
  where
    pairs lst = zip lst (tail lst)
    test (r1, r2) = if r2 < f r1 then [r1] else []

vShape x = if x < 0.5 then 2*(0.5-x) else 2*(x-0.5)

hist b lst = zip [0,b..] res
  where
    res = (`div` sum counts) . (*300) <$> counts
    counts = map length $ group $
             sort $ floor . (/b) <$> lst

showHist h = foldMap mkLine h
  where
    mkLine (b,n) = printf "%.2f\t%s %d%%\n" b (replicate n '▇') n
λ> showHist $ hist 0.05 $ take 50000 $ modify vShape $ randoms $ mkStdGen 1234
0.00	▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 28%
0.05	▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 25%
0.10	▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 22%
0.15	▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 19%
0.20	▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 16%
0.25	▇▇▇▇▇▇▇▇▇▇▇▇▇ 13%
0.30	▇▇▇▇▇▇▇▇▇▇ 10%
0.35	▇▇▇▇▇▇▇ 7%
0.40	▇▇▇▇ 4%
0.45	▇ 1%
0.50	▇ 1%
0.55	▇▇▇▇ 4%
0.60	▇▇▇▇▇▇▇ 7%
0.65	▇▇▇▇▇▇▇▇▇▇▇ 11%
0.70	▇▇▇▇▇▇▇▇▇▇▇▇▇ 13%
0.75	▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 16%
0.80	▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 19%
0.85	▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 22%
0.90	▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 25%
0.95	▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 29%

J

Implementation:

probmod=: {{y
  while.do.r=.?0 0
    if. (<u)/r do. {:r return.end.
  end.
}}

mod=: {{|1-2*y}}

Task example:

   rnd=: mod probmod"0 i.1e4

   bins=: 17%~i.18 NB. upper bounds (0 does not appear in result)
   (":,.' ',.'#'#"0~0.06 <.@* {:@|:)/:~(~.,.#/.~) bins{~bins I. rnd
0.0588235 1128 ###################################################################
 0.117647  977 ##########################################################         
 0.176471  843 ##################################################                 
 0.235294  670 ########################################                           
 0.294118  563 #################################                                  
 0.352941  423 #########################                                          
 0.411765  260 ###############                                                    
 0.470588  125 #######                                                            
 0.529412   27 #                                                                  
 0.588235  129 #######                                                            
 0.647059  280 ################                                                   
 0.705882  408 ########################                                           
 0.764706  559 #################################                                  
 0.823529  628 #####################################                              
 0.882353  854 ###################################################                
 0.941176  996 ###########################################################        
        1 1130 ###################################################################

Java

import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
import java.util.stream.Collectors;
import java.util.stream.Stream;

interface ModifierInterface {	
	double modifier(double aDouble);	
}

public final class ModifiedRandomDistribution222 {

	public static void main(String[] aArgs) {
		final int sampleSize = 100_000;
		final int binCount = 20;
		final double binSize = 1.0 / binCount;
		
		List<Integer> bins = Stream.generate( () -> 0 ).limit(binCount).collect(Collectors.toList());
		
	    for ( int i = 0; i < sampleSize; i++ ) {
	    	double random = modifiedRandom(modifier);
	        int binNumber = (int) Math.floor(random / binSize);
	        bins.set(binNumber, bins.get(binNumber) + 1);
	    }
		
		System.out.println("Modified random distribution with " + sampleSize + " samples in range [0, 1):");
		System.out.println();
		System.out.println("    Range           		  Number of samples within range");
		
		final int scaleFactor = 125;
		for ( int i = 0; i < binCount; i++ ) {
			String histogram = String.valueOf("#").repeat(bins.get(i) / scaleFactor);
			System.out.println(String.format("%4.2f ..< %4.2f %s %s",
				(float) i / binCount, (float) ( i + 1.0 ) / binCount, histogram, bins.get(i)));			
		}		
	}
	
	private static double modifiedRandom(ModifierInterface aModifier) {
		double result = -1.0;
		
		while ( result < 0.0 ) {
			double randomOne = RANDOM.nextDouble();
			double randomTwo = RANDOM.nextDouble();
			if ( randomTwo < aModifier.modifier(randomOne) ) {
				result = randomOne;
			}
		}
		
		return result;		
	}		
	
	private static ModifierInterface modifier = aX -> ( aX < 0.5 ) ? 2 * ( 0.5 - aX ) : 2 * ( aX - 0.5 );	
	
	private static final ThreadLocalRandom RANDOM = ThreadLocalRandom.current();

}
Output:
Modified random distribution with 100000 samples in range [0, 1):

    Range           		  Number of samples within range
0.00 ..< 0.05 ############################################################################ 9545
0.05 ..< 0.10 ################################################################### 8457
0.10 ..< 0.15 ############################################################ 7519
0.15 ..< 0.20 #################################################### 6513
0.20 ..< 0.25 ############################################ 5515
0.25 ..< 0.30 ################################### 4412
0.30 ..< 0.35 ############################ 3545
0.35 ..< 0.40 #################### 2507
0.40 ..< 0.45 ########### 1497
0.45 ..< 0.50 ### 475
0.50 ..< 0.55 #### 500
0.55 ..< 0.60 ########### 1496
0.60 ..< 0.65 #################### 2511
0.65 ..< 0.70 ############################ 3539
0.70 ..< 0.75 ################################### 4444
0.75 ..< 0.80 ########################################### 5494
0.80 ..< 0.85 ################################################### 6429
0.85 ..< 0.90 ############################################################ 7571
0.90 ..< 0.95 ################################################################### 8474
0.95 ..< 1.00 ############################################################################ 9557

JavaScript

function modifier(x) { return (x < .5 ? -1 : +1)*(2*(x-.5)) }

function random(m) {
  let random1, random2;
  while (true) {
    random1 = Math.random();
    random2 = Math.random();
    if (random2 < m(random1)) {
      return random1;
    }
  }
}

const N = 10000;
const bins = 20;
var numbers = [];
for (i=0;i<N;i++) {
  let number = random(modifier);
  numbers.push(number);
}

const delta = 1.0/bins;
var count = 0;
for (ceil=delta; ceil<1.0+delta; ceil+=delta) {
  for (n of numbers) {
    if ((n < ceil) && (ceil - delta <= n)) {
      count++;
    }
  }
  let width = count/N * 80;
  let bar = '';

  for (i = 0; i<width; i++) bar+='#';
  console.log(bar);
  count = 0;
}
Output:
########
#######
#######
######
#####
####
###
###
##
#
#
##
###
###
####
#####
######
######
#######
########

Julia

using UnicodePlots

modifier(x) = (y = 2x - 1; y < 0 ? -y : y)
modrands(rands1, rands2) = [x for (i, x) in enumerate(rands1) if rands2[i] < modifier(x)]
histogram(modrands(rand(50000), rand(50000)), nbins = 20)
Output:

                ┌                                        ┐ 
   [0.0 , 0.05) ┤▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 2412   
   [0.05, 0.1 ) ┤▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 2164      
   [0.1 , 0.15) ┤▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 1850           
   [0.15, 0.2 ) ┤▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 1652              
   [0.2 , 0.25) ┤▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 1379                  
   [0.25, 0.3 ) ┤▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 1121                     
   [0.3 , 0.35) ┤▇▇▇▇▇▇▇▇▇▇▇▇▇ 903                         
   [0.35, 0.4 ) ┤▇▇▇▇▇▇▇▇▇▇ 695                            
   [0.4 , 0.45) ┤▇▇▇▇▇▇ 407                                
   [0.45, 0.5 ) ┤▇▇ 118                                    
   [0.5 , 0.55) ┤▇▇ 126                                    
   [0.55, 0.6 ) ┤▇▇▇▇▇ 358                                 
   [0.6 , 0.65) ┤▇▇▇▇▇▇▇▇▇ 639                             
   [0.65, 0.7 ) ┤▇▇▇▇▇▇▇▇▇▇▇▇ 837                          
   [0.7 , 0.75) ┤▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 1121                    
   [0.75, 0.8 ) ┤▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 1332                 
   [0.8 , 0.85) ┤▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 1608             
   [0.85, 0.9 ) ┤▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 1920         
   [0.9 , 0.95) ┤▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 2204     
   [0.95, 1.0 ) ┤▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 2348   
                └                                        ┘
                                Frequency

Mathematica/Wolfram Language

ClearAll[Modifier, CreateRandomNumber]
Modifier[x_] := If[x < 0.5, 2 (0.5 - x), 2 (x - 0.5)]
CreateRandomNumber[] := Module[{r1, r2, done = True},
  While[done,
   r1 = RandomReal[];
   r2 = RandomReal[];
   If[r2 < Modifier[r1],
    Return[r1];
    done = False
    ]
   ]
  ]
numbers = Table[CreateRandomNumber[], 100000];
{bins, counts} = HistogramList[numbers, {0, 1, 0.05}, "PDF"];
Grid[MapThread[{#1, " - ", StringJoin@ConstantArray["X", Round[20 #2]]} &, {Partition[bins, 2, 1], counts}], Alignment -> Left]
Output:
{0.,0.05}	 - 	XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
{0.05,0.1}	 - 	XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
{0.1,0.15}	 - 	XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
{0.15,0.2}	 - 	XXXXXXXXXXXXXXXXXXXXXXXXXX
{0.2,0.25}	 - 	XXXXXXXXXXXXXXXXXXXXXX
{0.25,0.3}	 - 	XXXXXXXXXXXXXXXXXX
{0.3,0.35}	 - 	XXXXXXXXXXXXXX
{0.35,0.4}	 - 	XXXXXXXXXX
{0.4,0.45}	 - 	XXXXXX
{0.45,0.5}	 - 	XX
{0.5,0.55}	 - 	XX
{0.55,0.6}	 - 	XXXXXX
{0.6,0.65}	 - 	XXXXXXXXXX
{0.65,0.7}	 - 	XXXXXXXXXXXXXX
{0.7,0.75}	 - 	XXXXXXXXXXXXXXXXXX
{0.75,0.8}	 - 	XXXXXXXXXXXXXXXXXXXXXX
{0.8,0.85}	 - 	XXXXXXXXXXXXXXXXXXXXXXXXXX
{0.85,0.9}	 - 	XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
{0.9,0.95}	 - 	XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
{0.95,1.}	 - 	XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Nim

Translation of: Wren
import random, strformat, strutils, sugar

type ValRange = range[0.0..1.0]

func modifier(x: ValRange): ValRange =
  if x < 0.5: 2 * (0.5 - x) else: 2 * (x - 0.5)

proc rand(modifier: (float) -> float): ValRange =
  while true:
    let r1 = rand(1.0)
    let r2 = rand(1.0)
    if r2 < modifier(r1):
      return r1

const
  N = 100_000
  NumBins = 20
  HistChar = "■"
  HistCharSize = 125
  BinSize = 1 / NumBins

randomize()

var bins: array[NumBins, int]
for i in 0..<N:
  let rn = rand(modifier)
  let bn = int(rn / BinSize)
  inc bins[bn]

echo &"Modified random distribution with {N} samples in range [0, 1):"
echo "    Range           Number of samples within that range"
for i in 0..<NumBins:
  let hist = repeat(HistChar, (bins[i] / HistCharSize).toInt)
  echo &"{BinSize * float(i):4.2f} ..< {BinSize * float(i + 1):4.2f}  {hist} {bins[i]}"
Output:
Modified random distribution with 100000 samples in range [0, 1):
    Range           Number of samples within that range
0.00 ..< 0.05  ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 9480
0.05 ..< 0.10  ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 8469
0.10 ..< 0.15  ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 7631
0.15 ..< 0.20  ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 6484
0.20 ..< 0.25  ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 5472
0.25 ..< 0.30  ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 4327
0.30 ..< 0.35  ■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 3523
0.35 ..< 0.40  ■■■■■■■■■■■■■■■■■■■■ 2528
0.40 ..< 0.45  ■■■■■■■■■■■■ 1500
0.45 ..< 0.50  ■■■■ 444
0.50 ..< 0.55  ■■■■ 513
0.55 ..< 0.60  ■■■■■■■■■■■■ 1536
0.60 ..< 0.65  ■■■■■■■■■■■■■■■■■■■■ 2459
0.65 ..< 0.70  ■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 3505
0.70 ..< 0.75  ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 4600
0.75 ..< 0.80  ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 5525
0.80 ..< 0.85  ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 6512
0.85 ..< 0.90  ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 7482
0.90 ..< 0.95  ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 8581
0.95 ..< 1.00  ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 9429

Perl

Translation of: Raku

Uses any supplied distribution function, but defaults to uniform otherwise.

use strict;
use warnings;
use List::Util 'max';

sub distribution {
    my %param = ( function => \&{scalar sub {return 1}}, sample_size => 1e5, @_);
    my @values;
    do {
        my($r1, $r2) = (rand, rand);
        push @values, $r1 if &{$param{function}}($r1) > $r2;
    } until @values == $param{sample_size};
    wantarray ? @values : \@values;
}

sub modifier_notch {
    my($x) = @_;
    return 2 * ( $x < 1/2 ? ( 1/2 - $x  )
                          : ( $x  - 1/2 ) );
}

sub print_histogram {
    our %param = (n_bins => 10, width => 80, @_);
    my %counts;
    $counts{ int($_ * $param{n_bins}) / $param{n_bins} }++ for @{$param{data}};
    our $max_value = max values %counts;
    print "Bin  Counts  Histogram\n";
    printf "%4.2f %6d: %s\n", $_, $counts{$_}, hist($counts{$_}) for sort keys %counts;
    sub hist { scalar ('■') x ( $param{width} * $_[0] / $max_value ) }
}

print_histogram( data => \@{ distribution() } );
print "\n\n";

my @samples = distribution( function => \&modifier_notch, sample_size => 50_000);
print_histogram( data => \@samples, n_bins => 20, width => 64);
Output:
Bin  Counts  Histogram
0.00  10114: ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
0.10   9958: ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
0.20   9960: ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
0.30  10043: ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
0.40   9874: ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
0.50  10013: ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
0.60  10085: ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
0.70   9877: ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
0.80  10079: ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
0.90   9997: ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■

Bin  Counts  Histogram
0.00   4772: ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
0.05   4329: ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
0.10   3728: ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
0.15   3249: ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
0.20   2749: ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
0.25   2163: ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
0.30   1735: ■■■■■■■■■■■■■■■■■■■■■■■
0.35   1317: ■■■■■■■■■■■■■■■■■
0.40    764: ■■■■■■■■■■
0.45    259: ■■■
0.50    231: ■■■
0.55    721: ■■■■■■■■■
0.60   1255: ■■■■■■■■■■■■■■■■
0.65   1730: ■■■■■■■■■■■■■■■■■■■■■■■
0.70   2282: ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
0.75   2720: ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
0.80   3302: ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
0.85   3712: ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
0.90   4219: ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
0.95   4763: ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■

Phix

function rng(integer modifier)
    while true do
        atom r1 := rnd()
        if rnd() < modifier(r1) then
            return r1
        end if
    end while
end function
 
function modifier(atom x)
    return iff(x < 0.5 ? 2 * (0.5 - x)
                       : 2 * (x - 0.5))
end function

constant N              = 100000,
         NUM_BINS       = 20,
         HIST_CHAR_SIZE = 125,
         BIN_SIZE       = 1/NUM_BINS,
         LO = sq_mul(tagset(NUM_BINS-1,0),BIN_SIZE),
         HI = sq_mul(tagset(NUM_BINS),BIN_SIZE),
         LBLS = apply(true,sprintf,{{"[%4.2f,%4.2f)"},columnize({LO,HI})})

sequence bins := repeat(0, NUM_BINS)
for i=1 to N do
    bins[floor(rng(modifier) / BIN_SIZE)+1] += 1
end for
 
printf(1,"Modified random distribution with %,d samples in range [0, 1):\n\n",N)
for i=1 to NUM_BINS do
    sequence hist := repeat('#', round(bins[i]/HIST_CHAR_SIZE))
    printf(1,"%s  %s %,d\n", {LBLS[i], hist, bins[i]})
end for
Output:
Modified random distribution with 100,000 samples in range [0, 1):

[0.00,0.05)  ############################################################################ 9,521
[0.05,0.10)  #################################################################### 8,449
[0.10,0.15)  ############################################################ 7,519
[0.15,0.20)  ##################################################### 6,651
[0.20,0.25)  ############################################ 5,470
[0.25,0.30)  #################################### 4,504
[0.30,0.35)  ########################### 3,364
[0.35,0.40)  #################### 2,475
[0.40,0.45)  ############ 1,494
[0.45,0.50)  #### 518
[0.50,0.55)  #### 482
[0.55,0.60)  ############ 1,536
[0.60,0.65)  ##################### 2,568
[0.65,0.70)  ############################ 3,498
[0.70,0.75)  #################################### 4,559
[0.75,0.80)  ############################################ 5,447
[0.80,0.85)  #################################################### 6,512
[0.85,0.90)  ############################################################ 7,486
[0.90,0.95)  #################################################################### 8,484
[0.95,1.00)  ############################################################################ 9,463

plot

Library: Phix/pGUI

A simple graphical plot. Note the labels are on the X-axis, so it's v-shaped, not <-shaped: IupPlot does not support putting user-supplied labels on the Y-axis.

include pGUI.e
IupOpen()
Ihandle plot = IupPlot("GRID=YES, AXS_YAUTOMIN=NO")
IupPlotBegin(plot, true) -- (true means x-axis are labels)
for i=1 to length(bins) do
    IupPlotAddStr(plot, LBLS[i], bins[i]);
end for
{} = IupPlotEnd(plot)
IupSetAttribute(plot,"DS_MODE","BAR")
IupSetAttribute(plot,"DS_COLOR",IUP_DARK_BLUE)
IupShow(IupDialog(plot, `TITLE=Histogram, RASTERSIZE=1300x850`))
IupMainLoop()
IupClose()

Python

import random
from typing import List, Callable, Optional


def modifier(x: float) -> float:
    """
    V-shaped, modifier(x) goes from 1 at 0 to 0 at 0.5 then back to 1 at 1.0 .

    Parameters
    ----------
    x : float
        Number, 0.0 .. 1.0 .

    Returns
    -------
    float
        Target probability for generating x; between 0 and 1.

    """
    return 2*(.5 - x) if x < 0.5 else 2*(x - .5)


def modified_random_distribution(modifier: Callable[[float], float],
                                 n: int) -> List[float]:
    """
    Generate n random numbers between 0 and 1 subject to modifier.

    Parameters
    ----------
    modifier : Callable[[float], float]
        Target random number gen. 0 <= modifier(x) < 1.0 for 0 <= x < 1.0 .
    n : int
        number of random numbers generated.

    Returns
    -------
    List[float]
        n random numbers generated with given probability.

    """
    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"{'#' * int(40 * count / mx)}")
        last = count
Output:
   BIN, COUNTS, DELTA: HISTOGRAM

   0.00,  6326,   N/A: ########################################
   0.07,  5327,  -999: #################################
   0.13,  4487,  -840: ############################
   0.20,  3495,  -992: ######################
   0.27,  2601,  -894: ################
   0.33,  1744,  -857: ###########
   0.40,   914,  -830: #####
   0.47,   225,  -689: #
   0.53,   899,   674: #####
   0.60,  1783,   884: ###########
   0.67,  2623,   840: ################
   0.73,  3566,   943: ######################
   0.80,  4383,   817: ###########################
   0.87,  5422,  1039: ##################################
   0.93,  6205,   783: #######################################

R

Although it may not be immediately obvious, both modifier and gen are equivalent to the corresponding functions in the task.

library(NostalgiR) #For the textual histogram.
modifier <- function(x) 2*abs(x - 0.5)
gen <- function()
{
  repeat
  {
    random <- runif(2)
    if(random[2] < modifier(random[1])) return(random[1])
  } 
}
data <- replicate(100000, gen())
NostalgiR::nos.hist(data, breaks = 20, pch = "#")
Output:
> NostalgiR::nos.hist(data, breaks = 20, pch = "#")
  10000 +--+---------------------+---------------------+----------------------+---------------------+---------------------+--+
        |                                                                                                              #     |
        |    #                                                                                                         #     |
        |    #                                                                                                         #     |
        |    #     #                                                                                              #    #     |
        |    #     #                                                                                              #    #     |
   8000 +    #     #                                                                                              #    #     +
        |    #     #                                                                                              #    #     |
        |    #     #    #                                                                                   #     #    #     |
        |    #     #    #                                                                                   #     #    #     |
        |    #     #    #     #                                                                        #    #     #    #     |
F       |    #     #    #     #                                                                        #    #     #    #     |
r  6000 +    #     #    #     #                                                                        #    #     #    #     +
e       |    #     #    #     #     #                                                            #     #    #     #    #     |
q       |    #     #    #     #     #                                                            #     #    #     #    #     |
u       |    #     #    #     #     #                                                            #     #    #     #    #     |
e       |    #     #    #     #     #    #                                                  #    #     #    #     #    #     |
n  4000 +    #     #    #     #     #    #                                                  #    #     #    #     #    #     +
c       |    #     #    #     #     #    #     #                                            #    #     #    #     #    #     |
y       |    #     #    #     #     #    #     #                                      #     #    #     #    #     #    #     |
        |    #     #    #     #     #    #     #                                      #     #    #     #    #     #    #     |
        |    #     #    #     #     #    #     #                                #     #     #    #     #    #     #    #     |
        |    #     #    #     #     #    #     #    #                           #     #     #    #     #    #     #    #     |
   2000 +    #     #    #     #     #    #     #    #                           #     #     #    #     #    #     #    #     +
        |    #     #    #     #     #    #     #    #     #                #    #     #     #    #     #    #     #    #     |
        |    #     #    #     #     #    #     #    #     #                #    #     #     #    #     #    #     #    #     |
        |    #     #    #     #     #    #     #    #     #                #    #     #     #    #     #    #     #    #     |
        |    #     #    #     #     #    #     #    #     #     #    #     #    #     #     #    #     #    #     #    #     |
        |    #     #    #     #     #    #     #    #     #     #    #     #    #     #     #    #     #    #     #    #     |
      0 +    #     #    #     #     #    #     #    #     #     #    #     #    #     #     #    #     #    #     #    #     +
        +--+---------------------+---------------------+----------------------+---------------------+---------------------+--+
           0                    0.2                   0.4                    0.6                   0.8                    1   

REXX

If a vertical histograph   (instead of a   <   shaped horizontal histograph)   were to be used,   it would be a   V   shaped.

/*REXX program generates a "<" shaped probability of number generation using a modifier.*/
parse arg randn bins seed .                      /*obtain optional argument from the CL.*/
if randN=='' | randN==","  then randN= 100000    /*Not specified?  Then use the default.*/
if  bins=='' |  bins==","  then  bins=     20    /* "      "         "   "   "     "    */
if datatype(seed, 'W')   then call random ,,seed /* "      "         "   "   "     "    */
call MRD
!.= 0
      do j=1  for randN;   bin= @.j*bins%1
      !.bin= !.bin + 1                           /*bump the applicable bin counter.     */
      end   /*j*/
mx= 0
      do k=1  for randN;   mx= max(mx, !.k)      /*find the maximum, used for histograph*/
      end   /*k*/

say '  bin'
say '────── '   center('(with '    commas(randN)    " samples",  80 - 10)

       do b=0  for bins;  say format(b/bins,2,2)   copies('■', 70*!.b%mx)" "   commas(!.b)
       end   /*b*/
exit 0
/*──────────────────────────────────────────────────────────────────────────────────────*/
commas:   arg ?;  do jc=length(?)-3  to 1  by -3;  ?=insert(',', ?, jc);  end;    return ?
rand:     return random(0, 100000) / 100000
/*──────────────────────────────────────────────────────────────────────────────────────*/
modifier: parse arg y;   if y<.5  then return  2 * (.5 -  y)
                                  else return  2 * ( y - .5)
/*──────────────────────────────────────────────────────────────────────────────────────*/
MRD:      #=0;                      @.=          /*MRD:  Modified Random distribution.  */
            do until #==randN;      r= rand()    /*generate a random number; assign bkup*/
            if rand()>=modifier(r)  then iterate /*Doesn't meet requirement?  Then skip.*/
            #= # + 1;               @.#= r       /*bump counter; assign the MRD to array*/
            end   /*until*/
          return
output   when using the default inputs:
  bin
──────                         (with  100,000  samples
 0.00 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■  9,476
 0.05 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■  8,471
 0.10 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■  7,528
 0.15 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■  6,403
 0.20 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■  5,593
 0.25 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■  4,541
 0.30 ■■■■■■■■■■■■■■■■■■■■■■■■  3,424
 0.35 ■■■■■■■■■■■■■■■■■■  2,514
 0.40 ■■■■■■■■■■■  1,508
 0.45 ■■■  463
 0.50 ■■■  493
 0.55 ■■■■■■■■■■  1,501
 0.60 ■■■■■■■■■■■■■■■■■■  2,508
 0.65 ■■■■■■■■■■■■■■■■■■■■■■■■  3,416
 0.70 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■  4,574
 0.75 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■  5,556
 0.80 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■  6,506
 0.85 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■  7,551
 0.90 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■  8,383
 0.95 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■  9,590

Raku

sub modified_random_distribution ( Code $modifier --> Seq ) {
    return lazy gather loop {
        my ( $r1, $r2 ) = rand, rand;
        take $r1 if $modifier.($r1) > $r2;
    }
}
sub modifier ( Numeric $x --> Numeric ) {
    return 2 * ( $x < 1/2 ?? ( 1/2 - $x  )
                          !! ( $x  - 1/2 ) );
} 
sub print_histogram ( @data, :$n-bins, :$width ) { # Assumes minimum of zero.
    my %counts = bag @data.map: { floor( $_ * $n-bins ) / $n-bins };
    my $max_value = %counts.values.max;
    sub hist { '■' x ( $width * $^count / $max_value ) }
    say ' Bin, Counts: Histogram';
    printf "%4.2f, %6d: %s\n", .key, .value, hist(.value) for %counts.sort;
}

my @d = modified_random_distribution( &modifier );

print_histogram( @d.head(50_000), :n-bins(20), :width(64) );
Output:
 Bin, Counts: Histogram
0.00,   4718: ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
0.05,   4346: ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
0.10,   3685: ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
0.15,   3246: ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
0.20,   2734: ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
0.25,   2359: ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
0.30,   1702: ■■■■■■■■■■■■■■■■■■■■■■
0.35,   1283: ■■■■■■■■■■■■■■■■■
0.40,    702: ■■■■■■■■■
0.45,    250: ■■■
0.50,    273: ■■■
0.55,    745: ■■■■■■■■■■
0.60,   1231: ■■■■■■■■■■■■■■■■
0.65,   1757: ■■■■■■■■■■■■■■■■■■■■■■■
0.70,   2209: ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
0.75,   2738: ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
0.80,   3255: ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
0.85,   3741: ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
0.90,   4268: ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
0.95,   4758: ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■

Ruby

def modifier(x)  =  (x - 0.5).abs * 2

def mod_rand
  loop do
    random1, random2 = rand, rand
    return random1 if random2 < modifier(random1)
  end
end

bins = 15
bin_size = 1.0/bins
h = {}
(0...bins).each{|b| h[b*bin_size] = 0}

tally = 50_000.times.map{ (mod_rand).div(bin_size) * bin_size}.tally(h)
m = tally.values.max/40
tally.each {|k,v| puts "%f...%f  %s %d" % [k, k+bin_size, "*"*(v/m) , v] }
Output:
0.000000...0.066667  **************************************** 6241
0.066667...0.133333  ********************************* 5286
0.133333...0.200000  *************************** 4365
0.200000...0.266667  ********************** 3576
0.266667...0.333333  ***************** 2724
0.333333...0.400000  *********** 1837
0.400000...0.466667  ***** 925
0.466667...0.533333  * 207
0.533333...0.600000  ***** 843
0.600000...0.666667  *********** 1761
0.666667...0.733333  ***************** 2699
0.733333...0.800000  *********************** 3629
0.800000...0.866667  **************************** 4514
0.866667...0.933333  ********************************* 5301
0.933333...1.000000  *************************************** 6092

Rust

use ndhistogram::{Histogram, ndhistogram, axis::Uniform};
use rand::Rng;

/// change x in [0.0, 1.0) to a split with minimum probability at 0.5 
fn modifier(x: f64) -> f64 {
    if x < 0.5 {
        return 2.0 * (0.5 - &x);
    } else {
        return 2.0 * (&x - 0.5);
    }
}

const WANTED: usize = 20_000;

fn main() {
    let mut hist = ndhistogram!(Uniform::new(19, -0.0, 1.0));
    let mut rng = rand::thread_rng();
    for _ in 0.. WANTED {
        loop {
            let x: f64 = rng.gen::<f64>();
            let y: f64 = rng.gen::<f64>();
            if y < modifier(x) {
                hist.fill(&f64::from(x));
                break;
            }
        }
    }
    println!("{}", hist);
}
Output:
VecHistogram1D(21 bins, sum=20000)
   (-inf, -0.00) | 
    [0.00, 0.05) | #################################################
    [0.05, 0.11) | ############################################     
    [0.11, 0.16) | #######################################
    [0.16, 0.21) | ##################################
    [0.21, 0.26) | ###########################
    [0.26, 0.32) | ######################
    [0.32, 0.37) | ################
    [0.37, 0.42) | ###########
    [0.42, 0.47) | #####
    [0.47, 0.53) | #
    [0.53, 0.58) | #####
    [0.58, 0.63) | ###########
    [0.63, 0.68) | ###############
    [0.68, 0.74) | ######################
    [0.74, 0.79) | ############################
    [0.79, 0.84) | #################################
    [0.84, 0.89) | ######################################
    [0.89, 0.95) | ############################################
    [0.95, 1.00) | ##################################################
     [1.00, inf) |                                                    

UNIX Shell

Works with: bash
# NOTE: In bash, RANDOM returns an integer from 0 to 32767 (2**15-1)
random() {
  local m="$1"
  local -i random1 random2
  while true
  do
    random1=RANDOM
    random2=RANDOM
    if ((random2 < $("$m" $random1)))
    then echo $random1; break
    fi
  done
}

modifier() {
  local -i x=$1
  echo $((x < 2**14 ? 2**14 - x : x - 2**14 ))
}

declare -i N=10000 bins=20
declare -a histogram
for ((i=0;i<N;i++))
do ((histogram[bins*$(random modifier)/2**15]++))
done

for ((i=0;i<bins;i++))
do
  for ((j=0;j< ${histogram[i]-0}*bins*50/N;j++))
  do echo -n '#'
  done
  echo
done
Output:
#################################################################################################
################################################################################
############################################################################
###################################################################
#######################################################
###############################################
###################################
##########################
#############
######
#####
###############
##########################
##################################
#############################################
#####################################################
##############################################################
#######################################################################
####################################################################################
################################################################################################

Wren

Library: Wren-fmt
import "random" for Random
import "./fmt" for Fmt

var rgen = Random.new()

var rng = Fn.new { |modifier|
    while (true) {
        var r1 = rgen.float()
        var r2 = rgen.float()
        if (r2 < modifier.call(r1)) {
            return r1
        }
    }
}

var modifier = Fn.new { |x| (x < 0.5) ? 2 * (0.5 - x) : 2 * (x - 0.5) }

var N = 100000
var NUM_BINS = 20
var HIST_CHAR = "■"
var HIST_CHAR_SIZE = 125
var bins = List.filled(NUM_BINS, 0)
var binSize = 1 / NUM_BINS
for (i in 0...N) {
    var rn = rng.call(modifier)
    var bn = (rn / binSize).floor
    bins[bn] = bins[bn] + 1
}

Fmt.print("Modified random distribution with $,d samples in range [0, 1):\n", N)
System.print("    Range           Number of samples within that range")
for (i in 0...NUM_BINS) {
    var hist = HIST_CHAR * (bins[i] / HIST_CHAR_SIZE).round
    Fmt.print("$4.2f ..< $4.2f  $s $,d", binSize * i, binSize * (i + 1), hist, bins[i])
}
Output:

Specimen run:

Modified random distribution with 100,000 samples in range [0, 1):

    Range           Number of samples within that range
0.00 ..< 0.05  ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 9,605
0.05 ..< 0.10  ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 8,573
0.10 ..< 0.15  ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 7,440
0.15 ..< 0.20  ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 6,582
0.20 ..< 0.25  ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 5,482
0.25 ..< 0.30  ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 4,472
0.30 ..< 0.35  ■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 3,478
0.35 ..< 0.40  ■■■■■■■■■■■■■■■■■■■■ 2,497
0.40 ..< 0.45  ■■■■■■■■■■■■ 1,519
0.45 ..< 0.50  ■■■■ 489
0.50 ..< 0.55  ■■■■ 485
0.55 ..< 0.60  ■■■■■■■■■■■■ 1,453
0.60 ..< 0.65  ■■■■■■■■■■■■■■■■■■■■ 2,477
0.65 ..< 0.70  ■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 3,492
0.70 ..< 0.75  ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 4,453
0.75 ..< 0.80  ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 5,535
0.80 ..< 0.85  ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 6,480
0.85 ..< 0.90  ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 7,573
0.90 ..< 0.95  ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 8,372
0.95 ..< 1.00  ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 9,543