C - generates random numbers in the range relative to the average

I need to generate a set of random numbers in an interval that also has an average value. For example, min = 1000, max = 10000 and the average value is 7000. I know how to create numbers within the range, but I am struggling with the average value. Is there a function that I can use?

+1
source share
2 answers

What you are looking for is most easily done using the so-called reception rejection method.

Divide your interval into smaller intervals. Specifying a probability density function (PDF) can be very simple as a step function. For a Gaussian distribution, you would have left and right steps below your average step ie (see Image below, which has a more general distribution).

General approach to generating random values ​​on a PDF

Generate a random number throughout the interval. If the generated number is greater than the value of your PDF at this point, reject the generated number.

Repeat the steps until you get the desired number of points.


EDIT 1

Proof of the concept in Gaussian PDF.

So, the main idea is shown in graph (a).

  • / (PDF). PDF x /. PDF x, : 1) f(x) >= 0 2) ( , 1).
  • (max) " " (z1 < z2) PDF. PDF . (z1, z2), PDF(z1>x>z2) < eta, eta . , ≤ t26 > , , - , PDF(x) , .
  • Ch(z1, z2, max) . , .
  • x , z1<x<z2.
  • y (0, max). y , PDF(x), (x,y) 4. y , PDF(x), x return it.

, PDF.

#include "Random.h"
#include <fstream>
using namespace std;

double gaus(double a, double b, double c, double x)
{
    return a*exp(  -((x-b)*(x-b)/(2*c*c)   ));
}

double* random_on_a_gaus_distribution(double inter_a, double inter_b)
{
    double res [2];
    double a = 1.0; //currently parameters for the Gaussian 
    double b = 2.0; //are defined here to avoid having
    double c = 3.0; //a long function declaration line.

    double x = kiss::Ran(inter_a, inter_b);
    double y = kiss::Ran(0.0, 1.0);

    while (y>gaus(a,b,c,x)) //keep creating values until step 5. is satisfied.
    { 
        x = kiss::Ran(inter_a, inter_b); //this is interval (z1, z2)
        y = kiss::Ran(0.0, 1.0); //this is the interval (0, max)
    }

    res[0] = x;
    res[1] = y;

    return res; //I return (x,y) for plot reasons, only x is the randomly
}               //generated value you're looking for.

void main()
{
    double* x;

    ofstream f;
    f.open("test.txt");

    for(int i=0; i<100000; i++)
    {
        //see bellow how I got -5 and 10 to be my interval (z1, z2) 
        x = random_on_a_gaus_distribution(-5.0, 10.0);
        f << x[0]<<","<<x[1]<<endl;
    }

    f.close();
}

1

, PDF , gaus. .

random_on_a_gaus_distribution, . \ a, b, c, . (1, 2, 3) , , HW ( : , , 7000).

2 3

wolfram mathematica gaus. 1,2,3 , max (z1, z2). . 1.0 , eyeballin ' , - 5,0 10,0.

random_on_a_gaus_distribution , 2) eta, , PDF , . , , . , . . . , "". - , , .

4 5

bash . , . x - . x x .

x x_max x, , PDF(x) < PDF(x_max).

, , PDF x , , xi, PDF(xi)<PDF(x).

x, y, , , , x. matplotlib.

Scatterplot of (x, y) values, (random, probability_it_got_accepted_with)

, . , x, PDF, , .

Histogram of just randomly created variable <code> x </code> in function <code> random_on_a_gaus_distribution </code>.

, , . . , (mersene twister ).

Random.h

#pragma once
#include <stdlib.h>

const unsigned RNG_MAX=4294967295;

namespace kiss{
  //  unsigned int kiss_z, kiss_w, kiss_jsr, kiss_jcong;
  unsigned int RanUns();
  void RunGen();

  double Ran0(int upper_border);
  double Ran(double bottom_border, double upper_border);
}

namespace Crand{
  double Ran0(int upper_border);
  double Ran(double bottom_border, double upper_border);
}

Kiss.cpp

#include "Random.h"

unsigned int kiss_z     = 123456789;  //od 1 do milijardu
unsigned int kiss_w     = 378295763;  //od 1 do milijardu
unsigned int kiss_jsr   = 294827495;  //od 1 do RNG_MAX
unsigned int kiss_jcong = 495749385;  //od 0 do RNG_MAX

//KISS99*
//Autor: George Marsaglia
unsigned int kiss::RanUns()
{
   kiss_z=36969*(kiss_z&65535)+(kiss_z>>16);
   kiss_w=18000*(kiss_w&65535)+(kiss_w>>16);

   kiss_jsr^=(kiss_jsr<<13);
   kiss_jsr^=(kiss_jsr>>17);
   kiss_jsr^=(kiss_jsr<<5);

   kiss_jcong=69069*kiss_jcong+1234567;
   return (((kiss_z<<16)+kiss_w)^kiss_jcong)+kiss_jsr;
}

void kiss::RunGen()
{
   for (int i=0; i<2000; i++)
     kiss::RanUns();
}

double kiss::Ran0(int upper_border)
{
   unsigned velicinaIntervala = RNG_MAX / upper_border;
   unsigned granicaIzbora= velicinaIntervala*upper_border;
   unsigned slucajniBroj = kiss::RanUns();
   while(slucajniBroj>=granicaIzbora)
     slucajniBroj = kiss::RanUns();
   return slucajniBroj/velicinaIntervala;
}

double kiss::Ran (double bottom_border, double upper_border)
{
  return bottom_border+(upper_border-bottom_border)*kiss::Ran0(100000)/(100001.0);
}

, C: CRands.cpp

#include "Random.h"


//standardni pseudo random generatori iz C-a
double Crand::Ran0(int upper_border)
{
  return rand()%upper_border;
}

double Crand::Ran (double bottom_border, double upper_border)
{
  return (upper_border-bottom_border)*rand()/((double)RAND_MAX+1);
}

(b). PDF, PDF(x) .

, Ch(x) PDF-, y PDF(x); - ! , y , PDF(x) . , , , , max PDF.

Ch(x) , . .

? ? , ? max , , , .

, , , Ch(x) , PDF .

, , , y . z 0 1 lower_height/higher_height, < 1. z , : accept x .

, . , .. function, , eval , , max/min / , , .

!

+2

tl; dr: 0 1 (1 - m) / m, m - ( 0 1). / .


, . , , , , , - , . , , , , .

, , [0, 1) . , . , . , , , .

def randompow(p):
     return random.random() ** p

( Python, . - , . random.random() float 0 1)

, ? , ?

- . , , , .

100%, X...

# x are the values from -3 to 3 (log transformed from the powers used)
# y are the empirically-determined means given all those powers
def fitter(tanscale):
    xsc = tanscale * x
    sigtan = np.tanh(xsc)
    sigtan = (1 - sigtan) / 2

    resid = sigtan - y
    return sum(resid**2)

fit = scipy.optimize.minimize(fitter, 1)

, 1.1514088816214016. , .

, , :

def distpow(mean):
    p = 1 - (mean * 2)
    p = np.arctanh(p) / 1.1514088816214016
    return 10**p

. factory

def randommean(mean):
    p = distpow(mean)
    def f():
        return random.random() ** p
    return f

? 3-4 :

for x in [0.01, 0.1, 0.2, 0.4, 0.5, 0.6, 0.8, 0.9, 0.99]:
    f = randommean(x)
    # sample the distribution 10 million times
    mean = np.mean([f() for _ in range(10000000)])
    print('Target mean: {:0.6f}, actual: {:0.6f}'.format(x, mean))

Target mean: 0.010000, actual: 0.010030
Target mean: 0.100000, actual: 0.100122
Target mean: 0.200000, actual: 0.199990
Target mean: 0.400000, actual: 0.400051
Target mean: 0.500000, actual: 0.499905
Target mean: 0.600000, actual: 0.599997
Target mean: 0.800000, actual: 0.799999
Target mean: 0.900000, actual: 0.899972
Target mean: 0.990000, actual: 0.989996

, , ( factory):

def randommean(m):
    p = np.arctanh(1 - (2 * m)) / 1.1514088816214016
    return random.random() ** (10 ** p)

:, log10, 0.5. arctanh :

def randommean(m):
    '''Return a value from the distribution 0 to 1 with average *m*'''
    return random.random() ** ((1 - m) / m)

, . 1 ( ?), ( ).

+2

All Articles