![]() |
Forum Index : Microcontroller and PC projects : Monte Carlo estimation of PI
Author | Message | ||||
Nimue![]() Guru ![]() Joined: 06/08/2020 Location: United KingdomPosts: 420 |
One of my goto (no pun intended) programming exercises for more advanced students is to devise a program to estimate PI -- there are many methods available for this, but one of my favourite is to draw a circle in a square (or more precisely 1/4 of a square / circle) and randomly fill with pixels. Count the ratio of inside the circle to outside and you can estimate PI. Today, after a couple of hours with students and the CMM2, we came up with this: 'Estimate PI with Monte Carlo Simulation MODE 1,8 ' default screen settings CLS CONST POINTS = 100000 ' number of points to simulate. More = higher accuracy and slower CONST LENGTH = 450 ' length of square and radius of circle text 250,25, "Monte Carlo Simulation to estimate PI" BOX ((800-LENGTH)/2)-5 ,(600-LENGTH)/2-4,LENGTH+10,LENGTH+10,4 ' bounding box, slightly larger than the area to draw in ARC (800-LENGTH)/2,(LENGTH+(600-LENGTH)/2),LENGTH-1,LENGTH,0,90 ' 1/4 circle, with same radius as square side inside = 0 ' Reset counter for points inside circle FOR i = 0 TO POINTS ' iterate through the points x=INT(RND*(LENGTH+1)) ' random between 0 and Length (int rounds down) y=INT(RND*(LENGTH+1)) d=SQR(x^2+y^2) ' calculate the radius IF d <= LENGTH THEN ' if inside the circle inside = inside +1 PIXEL (x+(800-LENGTH)/2),(600-LENGTH)/2+LENGTH-y,RGB(red) ELSE PIXEL (x+(800-LENGTH)/2),(600-LENGTH)/2+LENGTH-y,RGB(green) ENDIF NEXT i header$="After " + STR$(POINTS) + " Iterations" header2$="PI approximately = " + STR$(inside/POINTS * 4) TEXT 300, 40, header$,,,,RGB(RED) TEXT 280, 55, header2$,,,,RGB(GREEN) The CMM2 will simulate upto 1,000,000 points in a reasonable time - and to be 100% honest, coding the display was far easier than the same exercise in Python - no libraries needed. Thanks to pointers from @matherp regarding the scaling / aspect ratios (note to self - if you use the CMM2 via a HDMI capture card, remember to check the resolution / aspect ration of the window). Nim Entropy is not what it used to be |
||||
GerryL Newbie ![]() Joined: 24/01/2019 Location: AustraliaPosts: 39 |
Hi Nim, I had a similar program on the ARM7 (see cut down version below with all the display stuff removed) and what interested me, apart from how fast it ran, was why its accuracy was no better than a couple of decimal places no matter how long I ran the program. There is probably a sound reason for this but I never figured it out. DIM as FLOAT X =0 DIM as FLOAT Y =0 DIM as FLOAT fInsideCircle = 0 DIM as FLOAT fTotal = 0 DIM as FLOAT f_Pi DIM as FLOAT fError Do X = RND() Y = RND() if sqr(X^2 + Y^2) <= 1.0 then fInsideCircle = fInsideCircle + 1 fTotal = fTotal + 1 f_Pi = 4.0 * (fInsideCircle/ fTotal) fError = PI - f_Pi Loop while inkey$ = "" Do you get PI better than a couple of decimal places? Gerry |
||||
Volhout Guru ![]() Joined: 05/03/2018 Location: NetherlandsPosts: 5091 |
Confirm MMbasic DOS version get's accurate up to 3 decimal places, not more. The DOS verision uses 64 bit variables, so should be capable of higher accuracy than 3 decimal places. Maybe it is the randomizer. If your resolution on the random numbers is not high enought you keep testing the same 'pixels' in your circle. Interesting... Edited 2020-09-08 20:50 by Volhout PicomiteVGA PETSCII ROBOTS |
||||
Nimue![]() Guru ![]() Joined: 06/08/2020 Location: United KingdomPosts: 420 |
Just compared this exact algorithm in (cough) Python (using random and math libraries) and MMBasic. After 10,000,000 iterations: Python: 3.1416352 MMBasic: 3.1409356 As far as I can see, nothing wrong there. So both look like at best 2-3dps with 10,000,000 iterations. The PC took seconds (4GHz, 4-core) - whereas the CMM2 took minutes -- but this wasn't a speed exercise. I'm happy with that -- not going to test further. Might find a better algorithm for PI though. Cheers Nim Entropy is not what it used to be |
||||
mkopack73 Senior Member ![]() Joined: 03/07/2020 Location: United StatesPosts: 261 |
Likely has to do with the size of the circle/square you are using. Remember, you are picking pixels - discrete integer values that there are only so many of to test. If you are trying to do this with a small circle/square there are less possible values to test against. |
||||
TassyJim![]() Guru ![]() Joined: 07/08/2011 Location: AustraliaPosts: 6283 |
IF you want to show the kids Pi to lots of places: https://www.thebackshed.com/forum/ViewTopic.php?TID=12159&PID=151133#151133#151133 how many digits? 100 Started at 07:39:44 11.043mS so far 26.692mS so far starting atan52() atan52() step 2 atan52() step 3 46.259mS so far pi = 3.1415926535 8979323846 2643383279 5028841971 6939937510 50 5820974944 5923078164 0628620899 8628034825 3421170679 100 Total computation time: 48 mS Time to format and print: 4 mS at 07:39:45 > Jim VK7JH MMedit |
||||
TassyJim![]() Guru ![]() Joined: 07/08/2011 Location: AustraliaPosts: 6283 |
As far as MMBasic is concerned, There is no need to use INT at all x=RND*LENGTH ' random between 0 and Length y=RND*LENGTH d=SQR(x^2+y^2) ' calculate the radius Plotting with floats is OK. I am not sure if staying with floats is true to the algorithm but it does help the accuracy a bit. Jim VK7JH MMedit |
||||
Volhout Guru ![]() Joined: 05/03/2018 Location: NetherlandsPosts: 5091 |
GerryL's algorythm uses floats (not pixels). So in theory it should (give sufficient time) reach infinite resolution. It is the randomizer I am worried about. Typically these are build up around 16bit shift registers (or 32 bit). Meaning that whatever scaling you apply, there are only so many different values possible. Even with a good distribution (all values have equal chance), there are only so amny. It should be easy to check if that is the case. In stead of rando numbers, use for-next loops for both x and y with significant resolution. example: x = 0 to 1 step 0.000001 And see where you end up ... PicomiteVGA PETSCII ROBOTS |
||||
Nimue![]() Guru ![]() Joined: 06/08/2020 Location: United KingdomPosts: 420 |
When I compared CMM2 to Pyhton - using the RANDOM library in Python (53-bit precision floats) the outcomes are comparable after 10,000,000 iterations. My method I published upthread was based on a box of certain size and pixels -- but I have now tested this using the same algorithm in both CMM2 and Python (a quarter box of side 1 unit) (which is how this seems to be implemented everywhere). For fun, I've not got CMM2 producing random integers between 1,100 --- and currently is working through 100,000,000 iterations. I'll knock up a BASIC prog to histogram the results. Unless I'm missing something -- I dont have any worries over the random number generator in the CMM2 --> interesting how threads get a life of their own. Entropy is not what it used to be |
||||
matherp Guru ![]() Joined: 11/12/2012 Location: United KingdomPosts: 10315 |
The STM32 h/w generates a 32-bit random number which is then scaled to a float in the range 0-1. Call RND twice to effectively increase no. of bits |
||||
![]() |
![]() |
The Back Shed's forum code is written, and hosted, in Australia. | © JAQ Software 2025 |