Home
JAQForum Ver 24.01
Log In or Join  
Active Topics
Local Time 06:59 02 Aug 2025 Privacy Policy
Jump to

Notice. New forum software under development. It's going to miss a few functions and look a bit ugly for a while, but I'm working on it full time now as the old forum was too unstable. Couple days, all good. If you notice any issues, please contact me.

Forum Index : Microcontroller and PC projects : Monte Carlo estimation of PI

Author Message
Nimue

Guru

Joined: 06/08/2020
Location: United Kingdom
Posts: 420
Posted: 06:43pm 07 Sep 2020
Copy link to clipboard 
Print this post

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: Australia
Posts: 39
Posted: 02:08am 08 Sep 2020
Copy link to clipboard 
Print this post

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: Netherlands
Posts: 5091
Posted: 10:47am 08 Sep 2020
Copy link to clipboard 
Print this post

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 Kingdom
Posts: 420
Posted: 02:10pm 08 Sep 2020
Copy link to clipboard 
Print this post

  Volhout said  Confirm

MMbasic DOS version get's accurate up to 3 decimal places, not more.
The DOS version 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 enough you keep testing the same 'pixels' in your circle.

Interesting...


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 States
Posts: 261
Posted: 06:55pm 08 Sep 2020
Copy link to clipboard 
Print this post

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: Australia
Posts: 6283
Posted: 09:47pm 08 Sep 2020
Copy link to clipboard 
Print this post

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: Australia
Posts: 6283
Posted: 10:43pm 08 Sep 2020
Copy link to clipboard 
Print this post

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: Netherlands
Posts: 5091
Posted: 09:01am 10 Sep 2020
Copy link to clipboard 
Print this post

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 Kingdom
Posts: 420
Posted: 09:15am 10 Sep 2020
Copy link to clipboard 
Print this post

  Volhout said  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 ...


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 Kingdom
Posts: 10315
Posted: 11:07am 10 Sep 2020
Copy link to clipboard 
Print this post

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
 
Print this page


To reply to this topic, you need to log in.

The Back Shed's forum code is written, and hosted, in Australia.
© JAQ Software 2025