1. Purpose
Due to the needs of the project, a series of random numbers need to be generated. The random numbers are not uniformly distributed, but based on normal distribution, and the random numbers need to be within the specified interval.
2. Result display
In my project, I want to generate a random number with normal distribution, ranging from [20240], so the mean value of normal distribution is 130 ((20 + 240) / 2). After continuous debugging, the standard deviation is set to 50.
The above figure shows the normal distribution of random numbers.
If the value range is not set. See the figure below:
Change the standard deviation to 100 to make it more "fat". The effects are as follows:
Through the above display, the design purpose is achieved.
3. Realization
3.1 source code
/* # THIS FILE IS PART OF RANDN PROJECT # randn - The core part of the GCC # THIS PROGRAM IS UNFREE SOFTWARE, IS LICENSED UNDER Ding Zhenjin(dingzj2000@163.com) # YOU SHOULD HAVE RECEIVED A COPY OF RANDN LICENSE, IF NOT, PLEASE DO NOT USE. #YOU SHOULD BUY THE COPYRIGHT # Copyright (c) 1987-2087 # Copyright (c) 2021 Ding Zhenjin(dingzj2000@163.com) */ /* 2021.7.9 Normal distribution random number in any range Environment: Ubuntu 32 16.04.1 Cairo library implementation */ #include <stdlib.h> #include <stdio.h> #include <string.h> #include <cairo.h> #include <math.h> #include <time.h> #include "randn.h" /* Number of samples collected */ #define N 100 /* The background icon is 1300 * 600 */ /* Origin coordinates */ #Define originx 650 / / the origin is centered #define OriginY 20 /* coordinate transformation */ #define X(n) ((n)*1.0) #define Y(n) ((600-(n))*1.0) /* Position in coordinate system */ #define PosX(n) (X(OriginX+(n))) #define PosY(n) (Y(OriginY+(n))) #define ANGLE(ang) (ang * 3.1415926 / 180.0) #define OFFSET 600 struct POS{ int x; int y; }; cairo_surface_t *image_surface_create_from_png(const char *filename) { cairo_status_t cst; cairo_surface_t *image_sf=cairo_image_surface_create_from_png(filename); cst = cairo_surface_status (image_sf); if (cst!=CAIRO_STATUS_SUCCESS) { printf( "failed to cairo_image_surface_create_from_png cairo_status_t is:%d file: %s",cst, filename); image_sf = NULL; //if (cst == CAIRO_STATUS_NO_MEMORY) { //image_sf = cairo_image_surface_create_from_jpeg(filename); //} } return image_sf; } void draw_png2surface(cairo_t *cr, double x, double y, cairo_surface_t *surface){ if(surface != NULL){ cairo_set_source_surface(cr, surface, x, y); cairo_paint(cr); } } /* Create background */ void createBackground(cairo_t *cr,char *file) { cairo_surface_t *g_background; if(cr == NULL || file == NULL) { return; } /* Background map */ g_background = image_surface_create_from_png(file); draw_png2surface(cr, 0, 0, g_background); } /* Build coordinate system */ void createCoordinate(cairo_t *cr) { char tempbuf[64]; if(cr == NULL) { return; } /* Scribe */ cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);/* Set color - Black */ cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND); cairo_set_line_width (cr, 1.0); cairo_move_to (cr, X(OriginX-OFFSET), Y(OriginY));//X axis cairo_line_to (cr, X(OriginX+OFFSET), Y(OriginY)); cairo_stroke (cr); cairo_move_to (cr, X(OriginX), Y(OriginY));//Y axis cairo_line_to (cr, X(OriginX), Y(OriginY+550)); cairo_stroke (cr); /* range */ cairo_select_font_face (cr, "serif", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD); cairo_set_font_size (cr, 15.0); //origin cairo_move_to (cr, X(OriginX-5), Y(OriginY-15)); cairo_show_text (cr, "0"); //Negative X axis cairo_move_to (cr, X(OriginX-OFFSET-15), Y(OriginY-15)); sprintf(tempbuf,"%d",-OFFSET); cairo_show_text (cr, tempbuf); //Positive X axis cairo_move_to (cr, X(OriginX+OFFSET-15), Y(OriginY-15)); sprintf(tempbuf,"%d",OFFSET); cairo_show_text (cr, tempbuf); //Y axis cairo_move_to (cr, X(OriginX-10), Y(OriginY+550+5)); cairo_show_text (cr, "550"); cairo_stroke (cr); } /* Construction coordinate point */ void createPoints(cairo_t *cr,int x,int y) { char buf[64]; if(cr == NULL) { return; } cairo_set_source_rgb(cr, 0.0, 0.0, 1.0);/* Set color - Blue */ cairo_set_line_width(cr, 1); cairo_arc(cr, PosX(x), PosY(y), 1, ANGLE(0), ANGLE(360)); cairo_stroke (cr); /* Display coordinates */ memset(buf,0x00,sizeof(buf)); sprintf(buf,"(%d,%d)",x,y); cairo_set_source_rgb(cr, 0.0, 0.0, 0.0);/* Set color - Black */ cairo_select_font_face (cr, "serif", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD); cairo_set_font_size (cr, 2.0); cairo_move_to(cr,PosX(x-8), PosY(y+8)); cairo_show_text (cr, buf); cairo_stroke (cr); } /* Construct coordinate system Y line */ void createLine(cairo_t *cr,int start_x,int start_y,int end_x,int end_y) { if(cr == NULL) { return; } /* Scribe */ cairo_set_source_rgb (cr, 1.0, 0.0, 0.0);/* Set color - red */ cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND); cairo_set_line_width (cr, 1.0); cairo_move_to (cr, PosX(start_x), PosY(start_y)); cairo_line_to (cr, PosX(end_x), PosY(end_y)); cairo_stroke (cr); } /* Create a normal distribution curve */ void createNormalCurve(cairo_t *cr,int start_x,int start_y,int end_x,int end_y) { } /* Exponential and logarithmic function test */ int mathTest(void) { printf("pow(x,y) x= 10,y=2 value=%lf\n",pow(10.0,2.0)); printf("powl(x,y) log x=10,y=100 value=%lf\n",powf(100.0,2.0)); printf("exp(x) e x=1 value=%f\n",exp(1)); printf("exp(x) e x=2 value=%f\n",exp(2)); printf("loge=%f\n",log(10)); //Logarithmic function based on e printf("loge=%f\n",log(2.718282)); //Logarithmic function based on e printf("log10=%f\n",log10(100)); //Base 10 logarithmic function printf("sqrt=%f\n",sqrt(16));//square root } int main(int argc,char *argv[]) { int rand_sum[OFFSET*2+1]={0}; int i,j,i_randn; double u,g,r,o,d_randn,dec; /************************ Create cairo****************************/ cairo_surface_t *surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 1300, 600); cairo_t *cr = cairo_create (surface); /*********************** Create background*****************************/ createBackground(cr,"background.png"); /*********************** Build coordinate system*****************************/ createCoordinate(cr); /**************************** Set random number seed***************************/ /* In the most same round of display effect, the seeds of random numbers should be consistent!!!! */ srand(time(0)); r = rand(); //r = 5.0;// /**************************** Normal distribution parameter setting***************************/ u = 130.0;//mean value g = 100; //standard deviation /**************************** Set random number range***************************/ o = 0.0; //If it is set to 0, it means that the generated random number is in any range. If it is not 0, it means that the generated random number is between [u-o,u+o] for(i = 0; i < 12000; i++) { for(j = 0; j < 5; j++) { d_randn = randn(u,g,&r); printf("%10.7lf ",d_randn); //Set random number range if(o != 0.0) { if(d_randn < u-o || d_randn > u+o) { continue; } } i_randn = (int)d_randn; dec = d_randn-i_randn; if(dec > 0.5) { i_randn++; } if(i_randn >= -OFFSET && i_randn <= OFFSET) { rand_sum[OFFSET+i_randn] = rand_sum[OFFSET+i_randn]+1; } } printf("\n"); } /************************ Plot the random number found****************************/ for(i = 0; i < sizeof(rand_sum)/sizeof(int); i++) { if(rand_sum[i] == 0) { continue; } createLine(cr,i-OFFSET,0,i-OFFSET,rand_sum[i]); } /************************ Create picture****************************/ cairo_surface_write_to_png (surface, "randn.png"); /************************ Destroy cairo****************************/ cairo_destroy (cr); cairo_surface_destroy (surface); return 0; }
3.2 cairo Library
Based on Linux C programming, image display uses cairo library. As for how to use it, it is not the focus of this paper. See:
https://blog.csdn.net/dingzj2000/article/details/103719104
3.3 random number seed
When it comes to random numbers, there must be random number seeds. In the code, time is used to generate seeds in order to produce different effects for each round of results (60000 points in a round). In my project, one round is the whole process from Startup to shutdown. After setting the initial random number seed, don't change it.
/**************************** Set random number seed***************************/ /* In the same round of display effect, the seeds of random numbers should be consistent!!!! */ srand(time(0)); r = rand(); //r = 5.0;//
3.4 display principle
The generated random number is a floating-point number, which is then forcibly converted to an integer. The pixel coordinates corresponding to this integer are added by 1. After one round of display, all pixels are displayed.
Because floating-point types are cast to integers, a simple rounding is done. It can not be used in actual projects.
i_randn = (int)d_randn; dec = d_randn-i_randn; if(dec > 0.5) { i_randn++; } if(i_randn >= -OFFSET && i_randn <= OFFSET) { rand_sum[OFFSET+i_randn] = rand_sum[OFFSET+i_randn]+1; }
3.4 function parameter definition
double randn(double u,double g,double *r)
The parameters are relatively simple:
u is the average value of normal distribution;
g is the standard deviation of normal distribution;
* r is a random number seed
/**************************** Normal distribution parameter setting***************************/ u = 130.0;//mean value g = 100; //standard deviation /**************************** Set random number range***************************/ o = 0.0; //If it is set to 0, it means that the generated random number is in any range. If it is not 0, it means that the generated random number is between [u-o,u+o]
3.5 output result printing
4. Core algorithm
It is implemented in C language, as shown in the figure below:
5. Acquisition algorithm
Add wechat (wechat: dingzj2000) to obtain the detailed algorithm.