สร้างตัวเลขสุ่มตามการแจกแจงปกติใน C / C ++


114

ฉันจะสร้างตัวเลขสุ่มตามการแจกแจงปกติใน C หรือ C ++ ได้อย่างไร

ฉันไม่ต้องการใช้ Boost ใด ๆ

ฉันรู้ว่า Knuth พูดถึงเรื่องนี้เป็นเวลานาน แต่ตอนนี้ฉันไม่มีหนังสือของเขาอยู่ในมือ


คำตอบ:


92

มีหลายวิธีที่จะมีสร้างตัวเลขแบบเกาส์กระจายจาก RNG

Box-Muller แปลงเป็นที่นิยมใช้ มันสร้างค่าได้อย่างถูกต้องด้วยการแจกแจงปกติ คณิตศาสตร์เป็นเรื่องง่าย คุณสร้างตัวเลขสุ่มสอง (เหมือนกัน) และด้วยการใช้สูตรกับพวกเขาคุณจะได้รับตัวเลขสุ่มแบบกระจายตามปกติสองตัว ส่งคืนหนึ่งและบันทึกอีกอันสำหรับคำขอหมายเลขสุ่มครั้งต่อไป


10
หากคุณต้องการความเร็ววิธีการโพลาร์จะเร็วกว่า และอัลกอริทึม Ziggurat มากยิ่งขึ้น (แม้ว่าจะเขียนซับซ้อนกว่ามากก็ตาม)
Joey

2
พบการใช้งาน Ziggurat ที่นี่people.sc.fsu.edu/~jburkardt/c_src/ziggurat/ziggurat.htmlมันค่อนข้างสมบูรณ์
dwbrito

24
หมายเหตุ C ++ 11 จะเพิ่มstd::normal_distributionสิ่งที่ทำตามที่คุณขอโดยไม่ต้องเจาะลึกรายละเอียดทางคณิตศาสตร์

3
std :: normal_distribution ไม่รับประกันว่าจะสอดคล้องกันในทุกแพลตฟอร์ม ตอนนี้ฉันกำลังทำการทดสอบและ MSVC ให้ชุดของค่าที่แตกต่างจากตัวอย่างเช่นเสียงดัง ดูเหมือนว่าเอ็นจิ้น C ++ 11 จะสร้างลำดับเดียวกัน (ให้เมล็ดพันธุ์เดียวกัน) แต่การแจกแจง C ++ 11 ดูเหมือนจะใช้งานได้โดยใช้อัลกอริทึมที่แตกต่างกันบนแพลตฟอร์มที่แตกต่างกัน
Arno Duvenhage

47

C ++ 11

ข้อเสนอ C ++ 11 std::normal_distributionซึ่งเป็นวิธีที่ฉันจะทำในวันนี้

C หรือ C ++ ที่เก่ากว่า

วิธีแก้ปัญหาตามลำดับความซับซ้อนจากน้อยไปมาก:

  1. เพิ่มตัวเลขสุ่ม 12 ตัวจาก 0 เป็น 1 และลบ 6 ซึ่งจะจับคู่ค่าเฉลี่ยและส่วนเบี่ยงเบนมาตรฐานของตัวแปรปกติ ข้อเสียเปรียบที่ชัดเจนคือช่วงถูก จำกัด ไว้ที่± 6 ซึ่งแตกต่างจากการแจกแจงปกติจริง

  2. การแปลงร่างของ Box-Muller นี่คือรายการข้างต้นและค่อนข้างง่ายในการนำไปใช้ หากคุณต้องการตัวอย่างแม่นยำมาก แต่ทราบว่ากล่อง-Muller แปลงรวมกับบางเครื่องปั่นไฟทุกข์เครื่องแบบจากความผิดปกติที่เรียกว่า Neave ผล1

  3. เพื่อความแม่นยำสูงสุดฉันขอแนะนำให้วาดเครื่องแบบและใช้การแจกแจงปกติสะสมผกผันเพื่อให้ได้ตัวแปรที่กระจายตามปกติ นี่คืออัลกอริทึมที่ดีมากสำหรับการแจกแจงปกติแบบสะสมผกผัน

1. HR Neave,“ เกี่ยวกับการใช้การแปลง Box-Muller ด้วยเครื่องกำเนิดตัวเลขหลอกแบบคูณที่สอดคล้องกัน,” สถิติประยุกต์, 22, 92-97, 1973


หากมีโอกาสใดที่คุณจะมีลิงก์อื่นไปยัง pdf บนเอฟเฟกต์ Neave หรือการอ้างอิงบทความวารสารต้นฉบับ? ขอบคุณ
pyCthon

2
@stonybrooknick มีการเพิ่มข้อมูลอ้างอิงเดิม ข้อสังเกตที่น่าสนใจ: ในขณะที่ googling "box muller neave" เพื่อค้นหาข้อมูลอ้างอิงคำถามนี้เกิดขึ้นในหน้าผลลัพธ์แรก!
Peter G.

ใช่ไม่ใช่ทุกคนที่รู้จักกันดีนอกชุมชนเล็ก ๆ และกลุ่มผลประโยชน์
pyCthon

@Peter G. ทำไมทุกคนถึงลงคะแนนคำตอบของคุณ? - อาจเป็นคนเดียวกันกับความคิดเห็นของฉันด้านล่างซึ่งฉันก็สบายดี แต่ฉันคิดว่าคำตอบของคุณดีมาก จะเป็นการดีถ้า SO ทำการ downvotes บังคับให้แสดงความคิดเห็นจริงฉันสงสัยว่าการโหวตดาวน์ส่วนใหญ่ของหัวข้อเก่า ๆ เป็นเพียงเรื่องเล็กน้อยและไร้สาระ
Pete855217

"เพิ่มตัวเลข 12 ตัวจาก 0-1 และลบ 6" - การแจกแจงของตัวแปรนี้จะมีการแจกแจงปกติหรือไม่? คุณสามารถให้ลิงค์ที่มาพร้อมกับรากศัพท์ได้หรือไม่เพราะในระหว่างการมาของทฤษฎีบทขีด จำกัด กลางการหาค่า n -> + inf เป็นสิ่งที่จำเป็นมาก
bruziuz

31

วิธีที่ง่ายและรวดเร็วคือการรวมตัวเลขสุ่มที่กระจายเท่า ๆ กันจำนวนหนึ่งแล้วนำมาหาค่าเฉลี่ย ดูCentral Limit Theoremสำหรับคำอธิบายทั้งหมดว่าเหตุใดจึงได้ผล


+1 แนวทางที่น่าสนใจมาก ได้รับการตรวจสอบแล้วว่าให้วงดนตรีย่อยที่กระจายตามปกติสำหรับกลุ่มเล็ก ๆ หรือไม่?
Morlock

4
@ มอร์ล็อกยิ่งคุณมีจำนวนตัวอย่างมากเท่าไหร่คุณก็ยิ่งเข้าใกล้การแจกแจงแบบเกาส์เซียนเท่านั้น หากแอปพลิเคชันของคุณมีข้อกำหนดที่เข้มงวดสำหรับความถูกต้องของการกระจายคุณอาจควรใช้สิ่งที่เข้มงวดกว่านี้เช่น Box-Muller แต่สำหรับแอปพลิเคชันจำนวนมากเช่นการสร้างเสียงรบกวนสีขาวสำหรับแอปพลิเคชันเสียงคุณสามารถหลีกเลี่ยงได้ด้วยจำนวนที่ค่อนข้างน้อย ของกลุ่มตัวอย่างเฉลี่ย (เช่น 16)
Paul R

2
นอกจากนี้คุณตั้งค่าพารามิเตอร์นี้อย่างไรเพื่อให้ได้ค่าความแปรปรวนจำนวนหนึ่งบอกว่าคุณต้องการค่าเฉลี่ย 10 โดยมีค่าเบี่ยงเบนมาตรฐานเป็น 1?
Morlock

1
@ เบ็น: คุณช่วยชี้ให้ฉันเห็นว่ามีประสิทธิภาพสำหรับสิ่งนี้ ฉันเคยใช้เทคนิคการหาค่าเฉลี่ยในการสร้างสัญญาณรบกวนแบบเกาส์เซียนโดยประมาณสำหรับการประมวลผลเสียงและภาพโดยมีข้อ จำกัด แบบเรียลไทม์ - หากมีวิธีการทำเช่นนี้ในรอบนาฬิกาที่น้อยลงนั่นอาจเป็นประโยชน์มาก
Paul R

1
@Petter: คุณอาจจะถูกต้องในกรณีทั่วไปสำหรับค่าทศนิยม ยังคงมีพื้นที่แอปพลิเคชันเช่นเสียงที่คุณต้องการเสียงเกาส์เซียนจำนวนเต็ม (หรือจุดคงที่) ที่รวดเร็วและความแม่นยำก็ไม่สำคัญเกินไปซึ่งวิธีการหาค่าเฉลี่ยอย่างง่ายนั้นมีประสิทธิภาพและมีประโยชน์มากกว่า (โดยเฉพาะอย่างยิ่งสำหรับแอปพลิเคชันแบบฝังซึ่งอาจไม่มีด้วยซ้ำ สนับสนุนจุดลอยตัวของฮาร์ดแวร์)
Paul R

24

ฉันสร้างโครงการที่มา C ++ เปิดให้บริการสำหรับการกระจายตามปกติจำนวนสุ่มมาตรฐานรุ่น

มันเปรียบเทียบอัลกอริทึมต่างๆรวมถึง

  • วิธีทฤษฎีบทขีด จำกัด กลาง
  • Box-Muller แปลงร่าง
  • วิธีขั้วโลก Marsaglia
  • อัลกอริทึม Ziggurat
  • วิธีการสุ่มตัวอย่างการแปลงผกผัน
  • cpp11randomใช้ C ++ 11 std::normal_distributionกับstd::minstd_rand(จริงๆแล้วคือ Box-Muller transform ในเสียงดัง)

ผลลัพธ์ของfloatเวอร์ชันsingle-precision ( ) บน iMac Corei5-3330S@2.70GHz, clang 6.1, 64-bit:

normaldistf

เพื่อความถูกต้องโปรแกรมจะตรวจสอบค่าเฉลี่ยค่าเบี่ยงเบนมาตรฐานความเบ้และเคอร์โทซิสของตัวอย่าง พบว่าวิธี CLT โดยการสรุปเลขที่สม่ำเสมอ 4, 8 หรือ 16 ไม่มีความเคอร์โทซิสที่ดีเหมือนวิธีอื่น ๆ

อัลกอริทึม Ziggurat มีประสิทธิภาพที่ดีกว่าขั้นตอนอื่น ๆ อย่างไรก็ตามมันไม่เหมาะสำหรับการขนาน SIMD เนื่องจากต้องการการค้นหาตารางและสาขา Box-Muller พร้อมชุดคำสั่ง SSE2 / AVX นั้นเร็วกว่ามาก (x1.79, x2.99) มากกว่าอัลกอริทึม ziggurat เวอร์ชันที่ไม่ใช่ SIMD

ดังนั้นฉันจะแนะนำให้ใช้ Box-Muller สำหรับสถาปัตยกรรมที่มีชุดคำสั่ง SIMD และอาจเป็น ziggurat เป็นอย่างอื่น


ป.ล. เกณฑ์มาตรฐานใช้ LCG PRNG ที่ง่ายที่สุดในการสร้างตัวเลขสุ่มแบบกระจายสม่ำเสมอ ดังนั้นจึงอาจไม่เพียงพอสำหรับบางแอปพลิเคชัน แต่การเปรียบเทียบประสิทธิภาพควรมีความยุติธรรมเนื่องจากการใช้งานทั้งหมดใช้ PRNG เดียวกันดังนั้นเกณฑ์มาตรฐานจึงทดสอบประสิทธิภาพของการเปลี่ยนแปลงเป็นหลัก


2
"แต่การเปรียบเทียบประสิทธิภาพควรมีความยุติธรรมเนื่องจากการใช้งานทั้งหมดใช้ PRNG เดียวกัน" .. ยกเว้นว่า BM จะใช้อินพุต RN หนึ่งอินพุตต่อเอาต์พุตในขณะที่ CLT ใช้สิ่งอื่น ๆ อีกมากมาย ฯลฯ ... ดังนั้นเวลาในการสร้าง # สุ่มแบบสม่ำเสมอ
greggo

14

นี่คือตัวอย่าง C ++ ตามข้อมูลอ้างอิงบางส่วน สิ่งนี้รวดเร็วและสกปรกคุณจะดีกว่าที่จะไม่ประดิษฐ์ใหม่และใช้ไลบรารีเพิ่ม

#include "math.h" // for RAND, and rand
double sampleNormal() {
    double u = ((double) rand() / (RAND_MAX)) * 2 - 1;
    double v = ((double) rand() / (RAND_MAX)) * 2 - 1;
    double r = u * u + v * v;
    if (r == 0 || r > 1) return sampleNormal();
    double c = sqrt(-2 * log(r) / r);
    return u * c;
}

คุณสามารถใช้พล็อต QQ เพื่อตรวจสอบผลลัพธ์และดูว่ามันใกล้เคียงกับการแจกแจงปกติจริงได้ดีเพียงใด (จัดอันดับตัวอย่างของคุณ 1..x เปลี่ยนอันดับเป็นสัดส่วนของจำนวนทั้งหมด x เช่นจำนวนตัวอย่างรับค่า z และลงจุดเส้นตรงขึ้นไปคือผลลัพธ์ที่ต้องการ)


1
sampleNormalManual () คืออะไร?
solutionPuzzles

@solvingPuzzles - ขออภัยแก้ไขรหัสแล้ว เป็นการโทรซ้ำ
Pete855217

1
สิ่งนี้จะทำให้เกิดความผิดพลาดในเหตุการณ์ที่หายากบางอย่าง (การจัดแสดงแอปพลิเคชันให้เจ้านายของคุณกดกริ่ง?) สิ่งนี้ควรดำเนินการโดยใช้การวนซ้ำไม่ใช่การเรียกซ้ำ วิธีการดูไม่คุ้นเคย มีที่มาอย่างไร / เรียกว่าอย่างไร?
สุกร

Box-Muller ถอดเสียงจากการใช้งานจาวา อย่างที่บอกว่ามันเร็วและสกปรกอย่าลังเลที่จะแก้ไข
Pete855217

1
FWIW คอมไพเลอร์จำนวนมากจะสามารถเปลี่ยนการเรียกซ้ำนั้นให้กลายเป็น 'ข้ามไปที่ด้านบนของฟังก์ชัน' คำถามคือคุณต้องการที่จะนับมัน :-) นอกจากนี้ความน่าจะเป็นที่ต้องใช้> 10 ซ้ำคือ 1 ใน 4.8 ล้าน p (> 20) คือรูปสี่เหลี่ยมจัตุรัส ฯลฯ
greggo

12

ใช้std::tr1::normal_distribution.

std :: tr1 namespace ไม่ได้เป็นส่วนหนึ่งของการเพิ่ม เป็นเนมสเปซที่มีการเพิ่มไลบรารีจาก C ++ Technical Report 1 และพร้อมใช้งานในคอมไพเลอร์และ gcc ของ Microsoft ที่เป็นปัจจุบันโดยไม่ขึ้นกับการเพิ่ม


25
เขาไม่ขอมาตรฐานเขาขอ 'ไม่เพิ่ม'
JoeG

12

นี่คือวิธีสร้างตัวอย่างบนคอมไพเลอร์ C ++ ที่ทันสมัย

#include <random>
...
std::mt19937 generator;
double mean = 0.0;
double stddev  = 1.0;
std::normal_distribution<double> normal(mean, stddev);
cerr << "Normal: " << normal(generator) << endl;

generatorจริงๆควรเมล็ด
Walter

มันเป็นเมล็ดเสมอ มีเมล็ดพันธุ์เริ่มต้น
Petter


4

ได้ดูเมื่อ: http://www.cplusplus.com/reference/random/normal_distribution/ เป็นวิธีที่ง่ายที่สุดในการสร้างการแจกแจงแบบปกติ


4

หากคุณใช้ C ++ 11 คุณสามารถใช้std::normal_distribution:

#include <random>

std::default_random_engine generator;
std::normal_distribution<double> distribution(/*mean=*/0.0, /*stddev=*/1.0);

double randomNumber = distribution(generator);

มีการแจกแจงอื่น ๆ อีกมากมายที่คุณสามารถใช้เพื่อแปลงผลลัพธ์ของเอ็นจินตัวเลขสุ่ม



3

ฉันได้ปฏิบัติตามคำจำกัดความของ PDF ที่ให้ไว้ในhttp://www.mathworks.com/help/stats/normal-distribution.htmlและได้สิ่งนี้:

const double DBL_EPS_COMP = 1 - DBL_EPSILON; // DBL_EPSILON is defined in <limits.h>.
inline double RandU() {
    return DBL_EPSILON + ((double) rand()/RAND_MAX);
}
inline double RandN2(double mu, double sigma) {
    return mu + (rand()%2 ? -1.0 : 1.0)*sigma*pow(-log(DBL_EPS_COMP*RandU()), 0.5);
}
inline double RandN() {
    return RandN2(0, 1.0);
}

อาจไม่ใช่แนวทางที่ดีที่สุด แต่ก็ค่อนข้างง่าย


-1 ไม่ทำงานเช่น RANDN2 (0.0, d + 1.0) มาโครมีชื่อเสียงในเรื่องนี้
Petter

แมโครจะล้มเหลวถ้าrand()ของRANDUผลตอบแทนที่เป็นศูนย์ตั้งแต่ Ln (0) จะไม่ได้กำหนด
interDist

คุณได้ลองใช้รหัสนี้จริงหรือไม่? ดูเหมือนว่าคุณได้สร้างฟังก์ชั่นที่สร้างตัวเลขซึ่งเป็นRayleigh กระจาย เปรียบเทียบกับกล่อง-Muller เปลี่ยนที่พวกเขาคูณด้วยในขณะที่คุณคูณด้วยcos(2*pi*rand/RAND_MAX) (rand()%2 ? -1.0 : 1.0)
HelloGoodbye

1

รายการ comp.lang.c คำถามที่พบบ่อยหุ้นสามวิธีที่แตกต่างกันได้อย่างง่ายดายสร้างตัวเลขสุ่มที่มีการกระจายแบบเกาส์

คุณสามารถดูได้ที่: http://c-faq.com/lib/gaussian.html


1

การใช้งาน Box-Muller:

#include <cstdlib>
#include <cmath>
#include <ctime>
#include <iostream>
using namespace std;
 // return a uniformly distributed random number
double RandomGenerator()
{
  return ( (double)(rand()) + 1. )/( (double)(RAND_MAX) + 1. );
}
 // return a normally distributed random number
double normalRandom()
{
  double y1=RandomGenerator();
  double y2=RandomGenerator();
  return cos(2*3.14*y2)*sqrt(-2.*log(y1));
}

int main(){
double sigma = 82.;
double Mi = 40.;
  for(int i=0;i<100;i++){
double x = normalRandom()*sigma+Mi;
    cout << " x = " << x << endl;
  }
  return 0;
}

1

มีอัลกอริทึมต่างๆสำหรับการแจกแจงปกติสะสมผกผัน ความนิยมมากที่สุดในการเงินเชิงปริมาณได้รับการทดสอบในhttp://chasethedevil.github.io/post/monte-carlo--inverse-cumulative-normal-distribution/

ในความคิดของฉันไม่มีแรงจูงใจในการใช้อย่างอื่นมากไปกว่าอัลกอริทึม AS241 จากWichuraนั่นคือความแม่นยำของเครื่องจักรเชื่อถือได้และรวดเร็ว ปัญหาคอขวดมักไม่ค่อยเกิดขึ้นในการสร้างตัวเลขสุ่มแบบเกาส์

นอกจากนี้ยังแสดงให้เห็นถึงข้อเสียเปรียบของ Ziggurat เช่นแนวทาง

คำตอบยอดนิยมสำหรับผู้สนับสนุน Box-Müllerคุณควรทราบว่ามีข้อบกพร่องที่ทราบแล้ว ฉันอ้างhttps://www.sciencedirect.com/science/article/pii/S0895717710005935 :

ในวรรณกรรม Box - Muller บางครั้งถูกมองว่าด้อยกว่าเล็กน้อยสาเหตุหลักมาจากสองประการ ขั้นแรกถ้ามีใครใช้วิธี Box – Muller กับตัวเลขจากเครื่องกำเนิดไฟฟ้าเชิงเส้นที่ไม่ดีตัวเลขที่แปลงแล้วจะให้พื้นที่ครอบคลุมที่แย่มาก พล็อตตัวเลขแปลงร่างที่มีหางเป็นเกลียวมีอยู่ในหนังสือหลายเล่มโดยเฉพาะอย่างยิ่งในหนังสือคลาสสิกของ Ripley ซึ่งน่าจะเป็นคนแรกที่สังเกตเห็น "


0

1) วิธีที่ใช้งานง่ายแบบกราฟิกที่คุณสามารถสร้างตัวเลขสุ่มแบบเกาส์เซียนคือการใช้สิ่งที่คล้ายกับวิธีมอนติคาร์โล คุณจะสร้างจุดสุ่มในกล่องรอบ ๆ เส้นโค้งเกาส์เซียนโดยใช้ตัวสร้างตัวเลขสุ่มหลอกใน C คุณสามารถคำนวณได้ว่าจุดนั้นอยู่ภายในหรือใต้การแจกแจงแบบเสียนโดยใช้สมการของการแจกแจง หากจุดนั้นอยู่ภายในการแจกแจงแบบเกาส์แสดงว่าคุณจะได้ตัวเลขสุ่มแบบเกาส์เซียนเป็นค่า x ของจุด

วิธีนี้ไม่สมบูรณ์แบบเนื่องจากในทางเทคนิคแล้วเส้นโค้งแบบเกาส์เซียนจะไปสู่อินฟินิตี้และคุณไม่สามารถสร้างกล่องที่เข้าใกล้อินฟินิตี้ในมิติ x ได้ แต่เส้นโค้ง Guassian เข้าใกล้ 0 ในมิติ y เร็วมากดังนั้นฉันจึงไม่ต้องกังวลเรื่องนั้น ข้อ จำกัด ของขนาดของตัวแปรใน C อาจเป็นปัจจัยจำกัดความแม่นยำของคุณมากกว่า

2) อีกวิธีหนึ่งคือการใช้ Central Limit Theorem ซึ่งระบุว่าเมื่อมีการเพิ่มตัวแปรสุ่มอิสระจะเป็นการแจกแจงแบบปกติ เมื่อคำนึงถึงทฤษฎีบทนี้คุณสามารถประมาณจำนวนสุ่มแบบเสียนได้โดยการเพิ่มตัวแปรสุ่มอิสระจำนวนมาก

วิธีการเหล่านี้ไม่ใช่วิธีที่ใช้ได้จริงที่สุด แต่เป็นสิ่งที่คาดหวังได้เมื่อคุณไม่ต้องการใช้ไลบรารีที่มีมาก่อน โปรดทราบว่าคำตอบนี้มาจากผู้ที่มีประสบการณ์ด้านแคลคูลัสหรือสถิติเพียงเล็กน้อยหรือไม่มีเลย


0

วิธีมอนติคาร์โลวิธี ที่ง่ายที่สุดในการทำเช่นนี้คือการใช้วิธีมอนติคาร์โล ใช้ช่วงที่เหมาะสม -X, + X ค่า X ที่มากขึ้นจะส่งผลให้การแจกแจงแบบปกติแม่นยำขึ้น แต่ใช้เวลาในการบรรจบกันนานขึ้น ก. เลือกตัวเลขสุ่มzระหว่าง -X ถึง X ข. คงไว้ด้วยความน่าจะเป็นN(z, mean, variance)ที่ N คือการแจกแจงแบบเกาส์เซียน ปล่อยอย่างอื่นแล้วกลับไปที่ขั้นตอน (a)



-3

คอมพิวเตอร์เป็นอุปกรณ์กำหนด ไม่มีการสุ่มในการคำนวณ ยิ่งไปกว่านั้นอุปกรณ์เลขคณิตใน CPU สามารถประเมินผลรวมเหนือชุดตัวเลขจำนวนเต็ม จำกัด (ทำการประเมินผลในเขตข้อมูล จำกัด ) และชุดจำนวนจริงที่มีเหตุผล และยังดำเนินการในระดับบิต คณิตศาสตร์จัดการกับเซตที่ยอดเยี่ยมอื่น ๆ เช่น [0.0, 1.0] โดยมีจำนวนคะแนนไม่สิ้นสุด

คุณสามารถฟังสายในคอมพิวเตอร์ด้วยคอนโทรลเลอร์บางตัวได้ แต่จะมีการแจกแจงแบบสม่ำเสมอหรือไม่? ฉันไม่รู้ แต่ถ้าสันนิษฐานว่าสัญญาณเป็นผลมาจากการสะสมค่าตัวแปรสุ่มอิสระจำนวนมากคุณจะได้รับตัวแปรสุ่มแบบกระจายปกติโดยประมาณ (พิสูจน์แล้วในทฤษฎีความน่าจะเป็น)

มีอยู่อัลกอริทึมที่เรียกว่า - ตัวสร้างสุ่มหลอก ในขณะที่ฉันเข้าใจจุดประสงค์ของตัวสร้างสุ่มหลอกคือการเลียนแบบการสุ่ม และเกณฑ์ของความดีคือ: - การกระจายเชิงประจักษ์จะถูกรวมเข้าด้วยกัน (ในบางแง่ - ชี้, สม่ำเสมอ, L2) เป็นทางทฤษฎี - ค่าที่คุณได้รับจากเครื่องกำเนิดไฟฟ้าแบบสุ่มดูเหมือนจะเป็นค่าที่เหมาะสม แน่นอนว่ามันไม่เป็นความจริงจาก 'มุมมองที่แท้จริง' แต่เราคิดว่ามันเป็นความจริง

วิธีหนึ่งที่ได้รับความนิยม - คุณสามารถ summ 12 irv ด้วยการแจกแจงแบบสม่ำเสมอ .... แต่พูดตามตรงในระหว่างการหาค่า Central Limit Theorem ด้วยการช่วย Fourier Transform, Taylor Series จำเป็นต้องมี n -> + inf สมมติฐานสองสามครั้ง ตัวอย่างเช่นทฤษฎี - โดยส่วนตัวแล้วฉันไม่ได้เน้นย้ำว่าผู้คนทำผลรวมของ 12 irv ด้วยการแจกแจงแบบสม่ำเสมออย่างไร

ฉันมีทฤษฎีความสามารถในการเรียนในมหาวิทยาลัย และอนุภาคสำหรับฉันมันเป็นเพียงคำถามทางคณิตศาสตร์ ในมหาวิทยาลัยฉันเห็นโมเดลต่อไปนี้:


double generateUniform(double a, double b)
{
  return uniformGen.generateReal(a, b);
}

double generateRelei(double sigma)
{
  return sigma * sqrt(-2 * log(1.0 - uniformGen.generateReal(0.0, 1.0 -kEps)));
}
double generateNorm(double m, double sigma)
{
  double y2 = generateUniform(0.0, 2 * kPi);
  double y1 = generateRelei(1.0);
  double x1 = y1 * cos(y2);
  return sigma*x1 + m;
}

วิธีการทำเช่นนี้เป็นเพียงตัวอย่างฉันเดาว่ามีวิธีอื่นในการนำไปใช้

การพิสูจน์ว่าถูกต้องสามารถพบได้ในหนังสือเล่มนี้ "Moscow, BMSTU, 2004: XVI Probability Theory, Example 6.12, p.246-247" ของKrishchenko Alexander Petrovich ISBN 5-7038-2485-0

น่าเสียดายที่ฉันไม่รู้เกี่ยวกับการแปลหนังสือเล่มนี้เป็นภาษาอังกฤษ


ฉันมีการโหวตดาวน์หลายครั้ง แจ้งให้เราทราบสิ่งที่ไม่ดีที่นี่?
bruziuz

คำถามคือวิธีสร้างตัวเลขสุ่มหลอกในคอมพิวเตอร์ (ฉันรู้ว่าภาษาหลวมที่นี่) ไม่ใช่คำถามเกี่ยวกับการดำรงอยู่ทางคณิตศาสตร์
user2820579

ใช่คุณพูดถูก. และคำตอบคือวิธีสร้างหมายเลขสุ่มหลอกด้วยการแจกแจงปกติตามตัวกำเนิดที่มีการแจกแจงแบบสม่ำเสมอ มีการระบุซอร์สโค้ดคุณสามารถเขียนซ้ำในภาษาใดก็ได้
bruziuz

แน่นอนฉันคิดว่าผู้ชายที่กำลังมองหาเช่น "สูตรตัวเลขใน C / C ++" อย่างไรก็ตามเพื่อเสริมการสนทนาของเราผู้เขียนหนังสือเล่มสุดท้ายนี้ให้การอ้างอิงที่น่าสนใจสำหรับเครื่องกำเนิดไฟฟ้าแบบสุ่มหลอกสองสามเครื่องที่ตอบสนองมาตรฐานสำหรับการเป็นเครื่องกำเนิดไฟฟ้าที่ "เหมาะสม"
user2820579

1
ฉันสำรองข้อมูลไว้ที่นี่sites.google.com/site/burlachenkok/download
bruziuz
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.