Monte Carlo estimator of Pi

25

3

Happy Pi Day everyone! For no reason at all, I'm trying to construct a Monte Carlo estimator of Pi that is as short as possible. Can we construct one that can fit in a tweet?

To clarify, what I have in mind is the typical approach of drawing random points from the unit square and calculating the ratio that fall within the unit circle. The number of samples can be hard coded or not. If you hardcode them, you must use at least 1000 samples. The result may be returned or printed as a floating point, fixed point or rational number.

No trig functions or Pi constants, must be a Monte Carlo approach.

This is code golf, so the shortest submission (in bytes) wins.

keegan

Posted 2015-03-14T15:46:32.610

Reputation: 369

2are trig functions allowed? I suggest you explicitly ban them. – Level River St – 2015-03-14T16:08:28.703

((0..4e9).map{rand**2+rand**2<1}.to_s.sub(/./,"$1.") – John Dvorak – 2015-03-14T18:37:38.317

@JanDvorak How is that supposed to work? Doesn't the map give you an array of true and false? – Martin Ender – 2015-03-14T19:16:33.163

@MartinBüttner Ah, oops, sorry. .filter{...}.size should work, though. – John Dvorak – 2015-03-14T19:51:47.473

@JanDvorak Indeed. That's really neat :) – Martin Ender – 2015-03-14T19:53:51.317

Good point, minimum of 1000, any return type. – keegan – 2015-03-14T20:12:59.173

What about types of programs? Full programs, functions. Do you require stdin->stdout? – Maltysen – 2015-03-14T20:14:12.903

@Maltysen we've got defaults for that (see the tag wiki). – Martin Ender – 2015-03-14T20:17:04.700

I actually did post a π approximation in a tweet: https://twitter.com/ERDekhayser/status/568170358664237057

– erdekhayser – 2015-03-15T17:35:42.663

Answers

17

80386 machine code, 40 38 bytes

Hexdump of the code:

60 33 db 51 0f c7 f0 f7 e0 52 0f c7 f0 f7 e0 58
03 d0 72 03 83 c3 04 e2 eb 53 db 04 24 58 db 04
24 58 de f9 61 c3

How to get this code (from assembly language):

    // ecx = n (number of iterations)
    pushad;
    xor ebx, ebx; // counter
    push ecx; // save n for later
myloop:
    rdrand eax; // make a random number x (range 0...2^32)
    mul eax; // calculate x^2 / 2^32
    push edx;
    rdrand eax; // make another random number y
    mul eax; // calculate y^2 / 2^32
    pop eax;
    add edx, eax; // calculate D = x^2+y^2 / 2^32 (range 0...2^33)
    jc skip; // skip the following if outside the circle
    add ebx, 4; // accumulate the result multiplied by 4
skip:
    loop myloop;
    push ebx; // convert the result
    fild dword ptr [esp]; // to floating-point
    pop eax;
    fild dword ptr [esp]; // convert n to floating-point
    pop eax;
    fdivp st(1), st; // divide

    popad;
    ret;

This is a function using MS fastcall calling convention (number of iterations is passed in register ecx). It returns the result in the st register.

Fun things about this code:

  • rdrand - just 3 bytes to generate a random number!
  • It uses (unsigned) integer arithmetic until the final division.
  • The comparison of squared distance (D) with squared radius (2^32) is performed automatically - the carry flag contains the result.
  • To multiply the count by 4, it counts the samples in steps of 4.

anatolyg

Posted 2015-03-14T15:46:32.610

Reputation: 10 719

Comment should read "Calculate x^2 % 2^32" – Cole Johnson – 2015-03-20T23:31:55.317

@ColeJohnson No - the random number is in eax; the mul command multiples it by itself and puts the high part in edx; the low part in eax is discarded. – anatolyg – 2015-03-22T13:03:04.573

11

Matlab/Octave, 27 bytes

I know there already is a Matlab/Octave answer, but I tried my own approach. I used the fact that the integral of 4/(1+x^2) between 0 and 1 is pi.

mean(4./(1+rand(1,1e5).^2))

flawr

Posted 2015-03-14T15:46:32.610

Reputation: 40 560

A different algorithm is always great! Also, more efficient! – anatolyg – 2015-03-16T09:44:33.223

7

R, 40 (or 28 or 24 using other methods)

mean(4*replicate(1e5,sum(runif(2)^2)<1))

mean(4*sqrt(1-runif(1e7)^2))

mean(4/(1+runif(1e7)^2))

Python 2, 56

Another Python one, if numpy is allowed, but pretty similar to Matlab/Octave:

import numpy;sum(sum(numpy.random.rand(2,8e5)**2)<1)/2e5

Matt

Posted 2015-03-14T15:46:32.610

Reputation: 71

6

CJam, 27 23 22 or 20 bytes

4rd__{{1dmr}2*mhi-}*//

2 bytes saved thanks to Runner112, 1 byte saved thanks to Sp3000

It takes the iteration count from STDIN as an input.

This is as straight forward as it gets. These are the major steps involved:

  • Read the input and run the Monte Carlo iterations that many times
  • In each iteration, get sum of square of two random floats from 0 to 1 and see if it is less than 1
  • Get the ratio of how many times we got less than 1 by total iterations and multiply it by 4 to get PI

Code expansion:

4rd                     "Put 4 on stack, read input and convert it to a double";
   __{            }*    "Take two copies, one of them determines the iteration"
                        "count for this code block";
      {1dmr}2*          "Generate 2 random doubles from 0 to 1 and put them on stack";
              mh        "Take hypot (sqrt(x^2 + y^2)) where x & y are the above two numbers";
                i       "Convert the hypot to 0 if its less than 1, 1 otherwise";
                 -      "Subtract it from the total sum of input (the first copy of input)";
                    //  "This is essentially taking the ratio of iterations where hypot";
                        "is less than 1 by total iterations and then multiplying by 4";

Try it online here


If average value of 1/(1+x^2) is also considered as Monte Carlo, then this can be done in 20 bytes:

Urd:K{4Xdmr_*)/+}*K/

Try it here

Optimizer

Posted 2015-03-14T15:46:32.610

Reputation: 25 836

2I tried a CJam answer as well, and managed to come in 2 bytes under your score. But my code came out so similarly to yours, I'd feel dirty posting it as a separate answer. Everything was the same except for the variable choice and these two optimizations: get a random number from 0 to 1 with 1dmr instead of KmrK/, and check if the sum of the squares is greater than 1 with i instead of 1> (I thought this one was particularly clever). – Runer112 – 2015-03-14T21:27:36.013

@Runer112 Thanks. the i trick is really neat! And damn the lack of documentation for 1dmr – Optimizer – 2015-03-14T21:35:32.813

6

Mathematica, 42 40 39 bytes (or 31/29?)

I've got three solutions all at 42 bytes:

4Count[1~RandomReal~{#,2},p_/;Norm@p<1]/#&
4Tr@Ceiling[1-Norm/@1~RandomReal~{#,2}]/#&
4Tr@Round[1.5-Norm/@1~RandomReal~{#,2}]/#&

They are all unnamed functions that take the number of samples n andd return a rational approximating π. First they all generate n points in the unit square in the positive quadrant. Then they determine the number of those samples that lie within the unit circle, and then they divide by the number of samples and multiply by 4. The only difference is in how they determine the number of sampples inside the unit circle:

  • The first one uses Count with the condition that Norm[p] < 1.
  • The second one subtracts the norm of each point from 1 and then rounds up. This turns numbers inside the unit circle to 1 and those outside to 0. Afterwards I just sum them all up with Tr.
  • The third one does essentially the same, but subtracts the from 1.5, so I can use Round instead of Ceiling.

Aaaaaand while writing this up, it occurred to me that there is indeed a shorter solution, if I just subtract from 2 and then use Floor:

4Tr@Floor[2-Norm/@1~RandomReal~{#,2}]/#&

or saving another byte by using the Unicode flooring or ceiling operators:

4Tr@⌊2-Norm/@1~RandomReal~{#,2}⌋/#&
4Tr@⌈1-Norm/@1~RandomReal~{#,2}⌉/#&

Note that the three rounding-based solutions can also be written with Mean instead of Tr and without the /#, again for the same bytes.


If other Monte Carlo based approaches are fine (specifically, the one Peter has chosen), I can do 31 bytes by estimating the integral of √(1-x2) or 29 using the integral of 1/(1+x2), this time given as a floating point number:

4Mean@Sqrt[1-1~RandomReal~#^2]&
Mean[4/(1+1~RandomReal~#^2)]&

Martin Ender

Posted 2015-03-14T15:46:32.610

Reputation: 184 808

9You've got three solutions to life, universe and everything and you decide to ruin it? Heresy. – seequ – 2015-03-14T21:59:00.887

2

@Sieg And I did it knowing full well what I was doing. ;)

– Martin Ender – 2015-03-14T21:59:46.217

5

Python 2, 77 75 bytes

from random import*;r=random;a=0;exec"a+=r()**2+r()**2<1;"*4000;print a/1e3

Uses 4000 samples to save bytes with 1e3.

Sp3000

Posted 2015-03-14T15:46:32.610

Reputation: 58 729

5You could get a little more accuracy at no cost with ...*8000;print a/2e3. – Logic Knight – 2015-03-15T06:32:06.843

5

Commodore 64 Basic, 45 bytes

1F┌I=1TO1E3:C=C-(R/(1)↑2+R/(1)↑2<1):N─:?C/250

PETSCII substitutions: = SHIFT+E, / = SHIFT+N, = SHIFT+O

Generates 1000 points in the first quadrant; for each, adds the truthness of "x^2+y^2<1" to a running count, then divides the count by 250 to get pi. (The presence of a minus sign is because on the C64, "true" = -1.)

Mark

Posted 2015-03-14T15:46:32.610

Reputation: 2 099

What does (1) do? – echristopherson – 2015-03-16T17:25:51.167

@echristopherson, you're misreading it. / isn't the division symbol, it's the character produced by typing SHIFT+N on a Commodore 64 keyboard. R/(1) is the shortcut form for RND(1), ie. "produce a random number between 0 and 1 using the current RNG seed". – Mark – 2015-03-16T19:45:17.080

Oh, you're right! Good old PETSCII graphics characters. – echristopherson – 2015-03-16T20:02:15.883

5

J, 17 bytes

Computes the mean value of 40000 sample values of the function 4*sqrt(1-sqr(x)) in the range [0,1].

Handily 0 o.x returns sqrt(1-sqr(x)).

   1e4%~+/0 o.?4e4$0
3.14915

randomra

Posted 2015-03-14T15:46:32.610

Reputation: 19 909

4

Java, 108 bytes

double π(){double π=0,x,i=0;for(;i++<4e5;)π+=(x=Math.random())*x+(x=Math.random())*x<1?1e-5:0;return π;}

Four thousand iterations, adding 0.001 each time the point is inside the unit circle. Pretty basic stuff.

Note: Yes, I know I can shed four bytes by changing π to a single-byte character. I like it this way.

Geobits

Posted 2015-03-14T15:46:32.610

Reputation: 19 061

why not 9999 iterations ? – Optimizer – 2015-03-14T22:28:59.427

1@Optimizer It makes the sum shorter. For 9999 iterations, I'd have to add a more precise number each time instead, which costs me digits. – Geobits – 2015-03-14T22:34:13.757

1You could save another byte and improve precision by using "4e5" and "1e-5" for the numbers. – Vilmantas Baranauskas – 2015-03-16T09:12:03.717

@VilmantasBaranauskas Thanks! I always forget about that :) It's tempting to use 4e9 and 1e-9 instead, but that takes quite a while... – Geobits – 2015-03-16T13:38:25.367

Protip: when golfing, you should actually reduce the bytes, not artificially increase them – Destructible Lemon – 2016-10-28T02:13:02.717

4

Matlab or Octave 29 bytes (thanks to flawr!)

mean(sum(rand(2,4e6).^2)<1)*4

(I am no quite sure if <1 is OK. I read it should be <=1. But how big is the probability to draw exactly 1...)

Matlab or Octave 31 bytes

sum(sum(rand(2,4e3).^2)<=1)/1e3

Steffen

Posted 2015-03-14T15:46:32.610

Reputation: 221

1Very nice idea! You could save two additional bytes with mean(sum(rand(2,4e6).^2)<1)*4. – flawr – 2015-03-15T22:20:08.517

4

><> (Fish), 114 bytes

:00[2>d1[   01v
1-:?!vr:@>x|  >r
c]~$~< |+!/$2*^.3
 .41~/?:-1r
|]:*!r$:*+! \
r+)*: *:*8 8/v?:-1
;n*4, $-{:~ /\r10.

Now, ><> doesn't have a built-in random number generator. It does however have a function that sends the pointer in a random direction. The random number generator in my code:

______d1[   01v
1-:?!vr:@>x|  >r
_]~$~< |+!/$2*^__
 __________
___________ _
_____ ____ _______
_____ ____~ ______

It basically generates random bits that make up a binary number and then converts that random binary number to decimal.

The rest is just the regular points in the square approach.

Usage: when you run the code you must make sure to prepopulate the stack (-v in python interpreter) with the number of samples, for example

pi.fish -v 1000

returns

3.164

cirpis

Posted 2015-03-14T15:46:32.610

Reputation: 465

3

Javascript: 62 Bytes

for(r=Math.random,t=c=8e4;t--;c-=r()**2+r()**2|0);alert(c/2e4)

I used the previous (now deleted) javascript answer and shaved 5 bytes.

Guzman Tierno

Posted 2015-03-14T15:46:32.610

Reputation: 31

You could link to cfern's answer to properly give credit.

– Jonathan Frech – 2018-09-30T23:57:59.733

Your answer appears to be a snippet which is disallowed I/O. Please either fix or delete your post.

– Jonathan Frech – 2018-10-01T03:08:36.647

Sorry, I'm new I didn't know how to put the link to the previous solution which now appears have been deleted. Regarding the snippet: I completely agree, but that was the code of the previous javascript solution which I also think it was invalid that reason. I modified mine to be a program. – Guzman Tierno – 2018-10-02T12:35:17.857

Yes; the previous answer was deleted as it was invalid -- I saw your answer before I recommended deletion, thus the comment. +1 for submitting a valid answer; welcome to PPCG! – Jonathan Frech – 2018-10-02T15:54:30.670

2

Perl 6, 33 bytes

{4*sum((1>rand²+rand²)xx$_)/$_}

Try it online!

This is a function that takes the number of samples as an argument.

Sean

Posted 2015-03-14T15:46:32.610

Reputation: 4 136

2

Python 2, 90 85 81 bytes

from random import*;r=random;print sum(4.for i in[0]*9**7if r()**2+r()**2<1)/9**7

returns 3.14120037157 for example. The sample count is 4782969 (9^7). You can get a better pi with 9^9 but you will have to be patient.

Logic Knight

Posted 2015-03-14T15:46:32.610

Reputation: 6 622

You can save 3 by replacing range(9**7) with [0]*9**7 or something, since you don't use i. And the list isn't too long to run into memory issues. – Sp3000 – 2015-03-15T00:20:49.857

Thanks. I wanted to get rid of range() but I had completely forgotten that trick. – Logic Knight – 2015-03-15T06:26:38.690

I have a feeling [0]9**7 isn't valid syntax. – seequ – 2015-03-15T13:57:27.500

You are right. I have re-attached the lost asterix (it was under my desk). – Logic Knight – 2015-03-15T14:51:27.360

2

GolfScript (34 chars)

0{^3?^rand.*^.*+/+}2000:^*`1/('.'@

Online demo

This uses fixed point because GS doesn't really have floating point. It slightly abuses the use of fixed point, so if you want to change the iteration count make sure that it's twice a power of ten.

Credit to xnor for the particular Monte Carlo method employed.

Peter Taylor

Posted 2015-03-14T15:46:32.610

Reputation: 41 901

2

Ruby, 39 bytes

p (1..8e5).count{rand**2+rand**2<1}/2e5

One of the highlight is that this one is able to use 8e5 notation, which makes it extendable up to ~8e9 samples in the same program byte count.

GreyCat

Posted 2015-03-14T15:46:32.610

Reputation: 181

1

Fortran (GFortran), 84 83 bytes

CALL SRAND(0)
DO I=1,4E3
X=RAND()
Y=RAND()
IF(X*X+Y*Y<1)A=A+1E-3
ENDDO
PRINT*,A
END

Try it online!

This code is very bad wrote. It will fail if gfortran decide to initialize variable A with other value then 0 (which occurs 50% of the compilations, approximately) and, if A is initialized as 0, it will always generate the same random sequence for the given seed. Then, the same value for Pi is printed always.

This is a much better program:

Fortran (GFortran), 100 99 bytes

A=0
DO I=1,4E3
CALL RANDOM_NUMBER(X)
CALL RANDOM_NUMBER(Y)
IF(X*X+Y*Y<1)A=A+1E-3
ENDDO
PRINT*,A
END

Try it online!

(One byte saved in each version; thanks Penguino).

rafa11111

Posted 2015-03-14T15:46:32.610

Reputation: 310

1In each version you can save a byte by changing 'DO I=1,1E3' to 'DO I=1,4E3', changing 'A=A+1' to 'A=A+1E-3', and changing 'PRINT,A/250' to 'PRINT,A' – Penguino – 2018-04-02T22:14:57.410

Yes, you are sure! Thank for the suggestion! – rafa11111 – 2018-04-02T22:24:03.190

1

Japt, 26 or 18 bytes

o r_+ÂMhMr p +Mr p <1Ã*4/U

Try it online!

Analogous to Optimizer's answer, mainly just trying to learn Japt.
Takes the number of iterations to run for as the implicit input U.

o                           Take the input and turn it into a range [0, U),
                            essentially a cheap way to get a large array.
  r_                        Reduce it with the default initial value of 0.
    +Â                      On each iteration, add one if
      MhMr p +Mr p          the hypotenuse of a random [0,1)x[0,1) right triangle
                   <1       is smaller than one.
                     Ã*4/U  Multiply the whole result by four and divide by input.

If 1/(1+x^2) is allowed (instead of two separate randoms), then we can achieve 18 bytes with the same logic.

o r_Ä/(1+Mr pÃ*4/U

Nit

Posted 2015-03-14T15:46:32.610

Reputation: 2 667

1You can save a few bytes by letting Mh calculate the hypotenuse rather than doing it yourself ;-) Also, you can use x to take the sum of an array, rather than reducing by addition: o x@MhMr Mr)<1Ã*4/U – ETHproductions – 2018-04-06T14:32:18.123

@ETHproductions Neat, I didn't know you can use Mh like that, thanks! Your two-random answer is nearly as short as my answer with only one random, that's pretty cool. I'll keep x in mind, I tend to use reduction a lot when trying to golf stuff, so this will come in very handy. – Nit – 2018-04-06T14:44:43.073

1

F#, 149 bytes

open System;
let r=new Random()
let q()=
 let b=r.NextDouble()
 b*b
let m(s:float)=(s-Seq.sumBy(fun x->q()+q()|>Math.Sqrt|>Math.Floor)[1.0..s])*4.0/s

Try it online!

As far as I can make out, to do this kind of running total in F# it's shorter to create an array of numbers and use the Seq.sumBy method than use a for..to..do block.

What this code does it that it creates a collection of floating-point numbers from 1 to s, performs the function fun x->... for the number of elements in the collection, and sums the result. There are s elements in the collection, so the random test is done s times. The actual numbers in the collection are ignored (fun x->, but x is not used).

It also means that the application has to first create and fill the array, and then iterate over it. So it's probably twice as slow as a for..to..do loop. And with the array creation memory usage is in the region of O(f**k)!

For the actual test itself, instead of using an if then else statement what it does is it calculates the distance (q()+q()|>Math.Sqrt) and rounds it down with Math.Floor. If the distance is within the circle, it'll be rounded down to 0. If the distance is outside the circle it'll be rounded down to 1. The Seq.sumBy method will then total these results.

Note then that what Seq.sumBy has totalled is not the points inside the circle, but the points outside it. So for the result it takes s (our sample size) and subtracts the total from it.

It also appears that taking a sample size as a parameter is shorter than hard-coding the value. So I am cheating a little bit...

Ciaran_McCarthy

Posted 2015-03-14T15:46:32.610

Reputation: 689

1

Perl 5, 34 bytes

$_=$a/map$a+=4/(1+(rand)**2),1..$_

The number of samples is taken from stdin. Requires -p.

Works because:

Try it online!

primo

Posted 2015-03-14T15:46:32.610

Reputation: 30 891

1

MathGolf, 11 bytes

0♫ô4ƒ²)/+♫/

Try it online!

Explanation

0            Push 0 (used for the sum)
 ♫           Push 10000
  ô          Start block of length 6
   4         Push 4
    ƒ²       Push random float in range [0,1) and square
      )      Increment by 1
       /     Divide
        +    Add result to the total sum (last instruction of block)
         ♫/  Divide by 10000

I'll add an explanation tomorrow. It performs 10000 iterations using the same integral as many other languages.

Assuming number of iterations as input:

MathGolf, 10 bytes

ô4ƒ²)/+\/(

Try it online!

Explanation

ô           Start block of length 6
 4          Push 4
  ƒ²        Push random float in range [0,1) and square
    )       Increment by 1
     /      Divide
      +     Add result to the total sum (last instruction of block)
            The first iteration, this adds the result to the implicit input, meaning that if the input is 10000 and the result is 3.1, 10003.1 is pushed on the stack. The end result is 10000 too large.
       \    Swap the top two elements on the stack (pushes the implicit input to the top)
        /   Divide (Since the sum is wonky, this is around 4.14159...)
         (  Decrement by one, resulting in 3.14159...)

maxb

Posted 2015-03-14T15:46:32.610

Reputation: 5 754

1

APL(NARS), 79 chars, 158 bytes

r←q;f;i
   f←{1e8÷⍨?1e8}⋄i←r←0
A: i←i+1⋄r←r+1>(f*2)+f*2⋄→A×⍳i<1e5
   r←4×r÷1e5

%pi=3.1415926535897932385... test:

  q 
3.14284
  q
3.14256
  q
3.13832

RosLuP

Posted 2015-03-14T15:46:32.610

Reputation: 3 036

1

Scala, 87 77 66 bytes

def s=math.pow(math.random,2);Seq.fill(1000)(s+s).count(_<1)/250d

keegan

Posted 2015-03-14T15:46:32.610

Reputation: 369

If you replace 1000 with 8000 and 250d with 2e4 you both save a byte and increase the number of samples by a factor of 8. – Dave Swartz – 2015-03-15T13:35:26.800

1

dc, 59 characters (whitespace is ignored)

[? 2^ ? 2^ + 1>i]su
[lx 1+ sx]si
[lu x lm 1+ d sm ln>z]sz

5k
?sn
lzx
lx ln / 4* p
q

I tested this on Plan 9 and OpenBSD, so I imagine it will work on Linux (GNU?) dc.

Explanation by line:

  1. Stores code to [read and square two floats; execute register i if 1 is greater than the sum of their squares] in register u.
  2. Stores code to [increment register x by 1] in register i.
  3. Stores code to [execute register u, increment register m, and then execute register z if register m is greater than register n] in register z.
  4. Set the scale to 5 decimal points.

  5. Read the number of points to sample from the first line of input.
  6. Execute register z.
  7. Divide register x (the number of hits) by register n (the number of points), multiply the result by 4, and print.
  8. Quit.

However, I cheated:

The program needs a supply of random floats between 0 and 1.

/* frand.c */
#include <u.h>
#include <libc.h>

void
main(void)
{
    srand(time(0));

    for(;;)
        print("%f\n", frand());
}

Usage:

#!/bin/rc
# runpi <number of samples>

{ echo $1; frand } | dc pi.dc

Test run:

% runpi 10000
3.14840

Now with less cheating (100 bytes)

Someone pointed out that I could include a simple prng.
http://en.wikipedia.org/wiki/RANDU

[lrx2^lrx2^+1>i]su[lx1+sx]si[luxlm1+dsmln>z]sz[0kls65539*2 31^%dsslkk2 31^/]sr?sn5dksk1sslzxlxlm/4*p

Ungolfed

[
Registers:
u - routine : execute i if sum of squares less than 1
i - routine : increment register x
z - routine : iterator - execute u while n > m++
r - routine : RANDU PRNG
m - variable: number of samples
x - variable: number of samples inside circle
s - variable: seed for r
k - variable: scale for division
n - variable: number of iterations (user input)
]c
[lrx 2^ lrx 2^ + 1>i]su
[lx 1+ sx]si
[lu x lm 1+ d sm ln>z]sz
[0k ls 65539 * 2 31^ % d ss lkk 2 31 ^ /]sr
? sn
5dksk
1 ss
lzx
lx lm / 4*
p

Test run:

$ echo 10000 | dc pigolf.dc
3.13640

progrider42

Posted 2015-03-14T15:46:32.610

Reputation: 11

1

Joe, 20 19 bytes

Note: this answer is non-competing, because version 0.1.2, which added randomness, was released after this challenge.

Named function F:

:%$,(4*/+1>/+*,?2~;

Unnamed function:

%$,(4*/+1>/+*,?2~;)

These both take the sample count as an argument and return the result. How do they work?

%$,(4*/+1>/+*,?2~;)
   (4*/+1>/+*,?2~;) defines a chain, where functions are called right-to-left
               2~;  appends 2 to the argument, giving [x, 2]
              ?     create a table of random values from 0 to 1 with that shape
            *,      take square of every value
          /+         sum rows, giving a list of (x**2+y**2) values
        1>           check if a value is less than 1, per atom
      /+             sum the results
    4*               multiply by four
%$,                  divide the result by the original parameter

Example runs:

   :%$,(4*/+1>/+*,?2~;
   F400000
3.14154
   F400000
3.14302

seequ

Posted 2015-03-14T15:46:32.610

Reputation: 1 714

1

Pure Bash, 65 bytes

for((;i++<$1*4;a+=RANDOM**2+RANDOM**2<32767**2));{ :;}
echo $a/$1

Takes a single command-line parameter which is multiplied by 4 to give the number of samples. Bash arithmetic is integer-only, so a rational is output. This may be piped to bc -l for the final division:

$ ./montepi.sh 10000
31477/10000
$ ./montepi.sh 10000|bc -l
3.13410000000000000000
$ 

Digital Trauma

Posted 2015-03-14T15:46:32.610

Reputation: 64 644

1

Pyth, 19

c*4sm<sm^OQ2 2*QQQQ

Give the desired number of iterations as input.

Demonstration

Since Pyth doesn't have a "Random floating number" function, I had to improvise. The program choose two random positive integers less than the input, squares, sums, and compared to the input squared. This performed a number of times equal to the input, then the result is multiplied by 4 and divided by the input.

In related news, I will be adding a random floating point number operation to Pyth shortly. This program does not use that feature, however.


If we interpret "The result may be returned or printed as a floating point, fixed point or rational number." liberally, then printing the numerator and denominator of the resulting fraction should be sufficient. In that case:

Pyth, 18

*4sm<sm^OQ2 2*QQQQ

This is an identical program, with the floating point division operation (c) removed.

isaacg

Posted 2015-03-14T15:46:32.610

Reputation: 39 268

1

Julia, 37 bytes

4mean(1-floor(sum(rand(4^8,2).^2,2)))

The number of samples is 65536 (=4^8).

A sligthly longer variant: a function with number of samples s as the only argument:

s->4mean(1-floor(sum(rand(s,2).^2,2)))

pawel.boczarski

Posted 2015-03-14T15:46:32.610

Reputation: 1 243

1

C, 130 bytes

#include<stdlib.h>f(){double x,y,c=0;for(int i=0;i<8e6;++i)x=rand(),y=rand(),c+=x*x+y*y<1.0*RAND_MAX*RAND_MAX;printf("%f",c/2e6);}

Ungolfed:

#include <stdlib.h>
f(){
 double x,y,c=0;
 for(int i=0; i<8e6; ++i) x=rand(), y=rand(), c+=x*x+y*y<1.0*RAND_MAX*RAND_MAX;
 printf("%f",c/2e6);
}

Karl Napf

Posted 2015-03-14T15:46:32.610

Reputation: 4 131

of course, you should still probably post the version without the whitespace (keep the current version with the header "ungolfed/with whitespace" or something) – Destructible Lemon – 2016-10-28T00:46:16.933

@DestructibleWatermelon done! – Karl Napf – 2016-10-28T01:33:52.030

101 bytes – ceilingcat – 2019-03-21T16:59:27.540

1

Racket 63 bytes

Using method of R language answer by @Matt :

(/(for/sum((i n))(define a(/(random 11)10))(/ 4(+ 1(* a a))))n)

Ungolfed:

(define(f n)
   (/
    (for/sum ((i n))
      (define a (/(random 11)10))
      (/ 4(+ 1(* a a))))
    n))

Testing:

(f 10000)

Output (fraction):

3 31491308966059784/243801776017028125

As decimal:

(exact->inexact(f 10000))

3.13583200307849

rnso

Posted 2015-03-14T15:46:32.610

Reputation: 1 635

1

Haskell, 116 114 110 96 bytes

d=8^9
g[a,b]=sum[4|a*a+b*b<d*d]
p n=(sum.take(floor n)$g<$>iterate((\x->mod(9*x+1)d)<$>)[0,6])/n

Because dealing with import System.Random; r=randoms(mkStdGen 2) would take too many precious bytes, I generate an infinite list of random numbers with the linear congruential generator that some say is almost cryptographically strong: x↦x*9+1 mod 8^9, which by the Hull-Dobell Theorem has the full period of 8^9.

g yields 4 if the random number point is inside the circle for pairs of random numbers in [0..8^9-1] because this eliminates a multiplication in the formula used.

Usage:

> p 100000
3.14208

Try it online!

Angs

Posted 2015-03-14T15:46:32.610

Reputation: 4 825

1

Actually, 14 bytes (non-competing)

`G²G²+1>`nkæ4*

Try it online!

This solution is non-competing because the language post-dates the challenge. The number of samples is given as input (rather than hard-coded).

Explanation:

`G²G²+1>`nkæ4*
`G²G²+1>`n      do the following N times:
 G²G²+            rand()**2 + rand()**2
      1>          is 1 greater?
          kæ    mean of results
            4*  multiply by 4

Mego

Posted 2015-03-14T15:46:32.610

Reputation: 32 998

2Why the downvote? – Destructible Lemon – 2016-12-06T07:12:49.823

0

Pyt, 22 bytes

Đ0⇹`⇹ṛ²ṛ²+1≤+⇹⁻łŕ⇹ᵮ/4*

Try it online!

Explanation:

          Implicit input [the number of random points to be sampled]
Đ         Duplicate input
0         Push zero
⇹         Swap the top two items on the stack
`...(ł)   Do ... (while the top of the stack is not 0)
⇹         Swap the top two items on the stack
ṛ²ṛ²+     Add the squares of two random floats (between 0 and 1)
1≤        Is the sum less than or equal to 1?
+         Add the top two items on the stack [auto-converts boolean to int]
⇹         Swap the top two items on the stack
⁻         Decrement the top of the stack by 1
(`)...ł   (Do ...) while the top of the stack is not 0
ŕ         Remove the top of the stack
⇹         Swap the top two items on the stack
ᵮ         Cast the top of the stack to a float
/         Divide
4*        Multiply by 4
          Implicit output

mudkip201

Posted 2015-03-14T15:46:32.610

Reputation: 833

0

Go, 130 116 bytes

import."math/rand";func p(){r,c,i:=Float64,0,1e6;for;i>0;i--{a,b:=r(),r();if a*a+b*b<1{c+=4}};print(float64(c)/1e6)}

No real tricks here, other than aliasing rand.Float64 and float64 to save a few bytes.

Run it here: http://play.golang.org/p/F5YniIncor

Please note that random on play.golang.org cannot be seeded by time (since the date is always the same) so you need to change the seed manually.

1e6 is used since the run time is too long for play.golang.org if I set it higher.

Edit: No longer takes an input, outputs the computed value itself.

Kristoffer Sall-Storgaard

Posted 2015-03-14T15:46:32.610

Reputation: 489

0

Python 3, 69 bytes

Apparently shorter than the other python entries, save one that uses sympy numpy (misremembered)

from random import*
print(eval(('+(1>('+2*'+random()**2)')*2000)/500)

Try it online!

Wow, it's been a while since I posted a multiline answer on this site... I've been using Turtlèd too much for that

Explanation:

from random import*    We can use random.random now as random
print(                 Print the result of the following
      eval(            evaluate the value of the expression in the string
           ('+(1>('+2*'+random()**2)')*2000    the string construction
                                           )/500) divide by 500 and print

Explanation of the string expression:

                             *2000  repeat this 2000 times
    '+(1>('                         have each section joined by a +,
                                    and the first item have the unary +. (nop, essentially)
                                    check if the section is less than 1, if so,
                                    evaluate to 1, else 0
           +2*'+random()**2)'        sum two random numbers squared, close both parens.

                                   [Evaluate the sum]

This is about the max accuracy, because 3000 samples gives a recursion error.

(I'll improve this explanation real soon actually.)

Destructible Lemon

Posted 2015-03-14T15:46:32.610

Reputation: 5 908

https://docs.python.org/3/library/sys.html#sys.setrecursionlimit – ASCII-only – 2017-04-11T01:30:38.703

many bytes for that! – Destructible Lemon – 2017-04-11T01:31:08.787

Yeah, just saying it isn't the max accuracy – ASCII-only – 2017-04-11T01:31:32.270

There seems to be a discrepancy between your TIO link's source and your post's source -- namely parentheses around the print. – Jonathan Frech – 2018-10-01T03:12:02.023