1.目的
? ? ? ? 因为项目需要,需要产生一串随机数,此随机数非均匀分布,而是基于正态分布,同时该随机数需要在指定区间内。
?2.结果展示
? ? ? ? 我的项目中,希望产生一个正态分布的随机数,范围在[20,240],那么正态分布的均值就是130((20+240)/2),经过不断调试结果,设置标准差为50。
? ? ? ? ?上图就是产生的随机数正态分布。
? ? ? ? ? 假如不设置取值范围。见下图:
? ? ? ? 改变标准差到100,让其变得更“胖”。效果如下:
? ? ? ? 通过上述展示,达到了设计目的。
3.实现
3.1 源码
/*
# 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
任意范围的正态分布随机数
环境:Ubuntu32 16.04.1 cairo库实现
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <cairo.h>
#include <math.h>
#include <time.h>
#include "randn.h"
/* 采集样本数量 */
#define N 100
/*
背景图标是1300*600
*/
/* 原点坐标 */
#define OriginX 650 //原点居中
#define OriginY 20
/* 坐标转换 */
#define X(n) ((n)*1.0)
#define Y(n) ((600-(n))*1.0)
/* 坐标系内位置 */
#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);
}
}
/*
创建背景
*/
void createBackground(cairo_t *cr,char *file)
{
cairo_surface_t *g_background;
if(cr == NULL || file == NULL)
{
return;
}
/* 背景图 */
g_background = image_surface_create_from_png(file);
draw_png2surface(cr, 0, 0, g_background);
}
/*
构建坐标系
*/
void createCoordinate(cairo_t *cr)
{
char tempbuf[64];
if(cr == NULL)
{
return;
}
/* 划线 */
cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);/* 设置颜色 -黑色 */
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轴
cairo_line_to (cr, X(OriginX+OFFSET), Y(OriginY));
cairo_stroke (cr);
cairo_move_to (cr, X(OriginX), Y(OriginY));//Y轴
cairo_line_to (cr, X(OriginX), Y(OriginY+550));
cairo_stroke (cr);
/* 量程 */
cairo_select_font_face (cr, "serif", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
cairo_set_font_size (cr, 15.0);
//原点
cairo_move_to (cr, X(OriginX-5), Y(OriginY-15));
cairo_show_text (cr, "0");
//负X轴
cairo_move_to (cr, X(OriginX-OFFSET-15), Y(OriginY-15));
sprintf(tempbuf,"%d",-OFFSET);
cairo_show_text (cr, tempbuf);
//正X轴
cairo_move_to (cr, X(OriginX+OFFSET-15), Y(OriginY-15));
sprintf(tempbuf,"%d",OFFSET);
cairo_show_text (cr, tempbuf);
//Y轴
cairo_move_to (cr, X(OriginX-10), Y(OriginY+550+5));
cairo_show_text (cr, "550");
cairo_stroke (cr);
}
/*
构建坐标点
*/
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);/* 设置颜色 -蓝色 */
cairo_set_line_width(cr, 1);
cairo_arc(cr, PosX(x), PosY(y), 1, ANGLE(0), ANGLE(360));
cairo_stroke (cr);
/* 显示坐标 */
memset(buf,0x00,sizeof(buf));
sprintf(buf,"(%d,%d)",x,y);
cairo_set_source_rgb(cr, 0.0, 0.0, 0.0);/* 设置颜色 -黑色 */
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);
}
/*
构建坐标系Y直线
*/
void createLine(cairo_t *cr,int start_x,int start_y,int end_x,int end_y)
{
if(cr == NULL)
{
return;
}
/* 划线 */
cairo_set_source_rgb (cr, 1.0, 0.0, 0.0);/* 设置颜色 -红色 */
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);
}
/*
创建正态分布曲线
*/
void createNormalCurve(cairo_t *cr,int start_x,int start_y,int end_x,int end_y)
{
}
/*
指数和对数函数测试
*/
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)); //以e为底的对数函数
printf("loge=%f\n",log(2.718282)); //以e为底的对数函数
printf("log10=%f\n",log10(100)); //以10为底的对数函数
printf("sqrt=%f\n",sqrt(16));//平方根
}
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;
/************************ 创建cairo ****************************/
cairo_surface_t *surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 1300, 600);
cairo_t *cr = cairo_create (surface);
/*********************** 创建背景 *****************************/
createBackground(cr,"background.png");
/*********************** 构建坐标系 *****************************/
createCoordinate(cr);
/**************************** 设置随机数种子 ***************************/
/* 最同一轮显示效果中,随机数种子应该保持一致!!!! */
srand(time(0));
r = rand();
//r = 5.0;//
/**************************** 正态分布参数设置 ***************************/
u = 130.0;//均值
g = 100; //标准差
/**************************** 设置随机数范围 ***************************/
o = 0.0; //设置为0,表示为生成的随机数在任意范围,非0,表示产生的随机数在[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);
//设置随机数范围
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");
}
/************************ 对找出的随机数进行绘点 ****************************/
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]);
}
/************************ 创建图片 ****************************/
cairo_surface_write_to_png (surface, "randn.png");
/************************ 销毁cairo ****************************/
cairo_destroy (cr);
cairo_surface_destroy (surface);
return 0;
}
3.2 cairo库
????????基于Linux C编程,图像显示使用cairo库。至于如何使用不在本文论述的重点。详见:
????????https://blog.csdn.net/dingzj2000/article/details/103719104
3.3 随机数种子
? ? ? ? 谈到随机数,必然有随机数种子,代码里用时间产生种子,是为了每一轮结果(一轮60000个点)产生不同的效果。在我的项目中,一轮是从开机到关机整个流程,在设置好初始随机数种子后,就不要在改变。
/**************************** 设置随机数种子 ***************************/
/* 最同一轮显示效果中,随机数种子应该保持一致!!!! */
srand(time(0));
r = rand();
//r = 5.0;//
3.4 显示原理
? ? ? ? 产生的随机数是浮点型,然后强制转换为整型,这个整型对应的像素坐标就加1,在一轮显示后,显示所有像素。
? ? ? ? 因为浮点型强制转换为整型,简单做了一个四舍五入。在实际项目中可以不用。
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 函数参数定义
????????double randn(double u,double g,double *r)
? ? ? ? 参数比较简单:
? ? ? ? u是正态分布平均值;
? ? ? ? g是正态分布标准差;
? ? ? ? *r是随机数种子
/**************************** 正态分布参数设置 ***************************/
u = 130.0;//均值
g = 100; //标准差
/**************************** 设置随机数范围 ***************************/
o = 0.0; //设置为0,表示为生成的随机数在任意范围,非0,表示产生的随机数在[u-o,u+o]之间
3.5 输出结果打印
????????
4.核心算法
????????采用C语言实现,见下图:
5.获取算法
加微信(微信号:dingzj2000),获取详细算法。
?
|