3

So, I saw this on Hacker News the other day: http://web.mit.edu/tee/www/bertrand/problem.html

It basically says what's the probability that a random chord on a circle with radius of 1 has a length greater than the square root of 3.

Looking at it, it seems obvious that the answer is 1/3, but comments on HN have people who are smarter than me debating this. https://news.ycombinator.com/item?id=10000926

I didn't want to debate, but I did want to make sure I wasn't crazy. So I coded what I thought would prove it to be P = 1/3, but I end up getting P ~ .36. So, something's got to be wrong with my code.

Can I get a sanity check?

    package com.jonas.betrand;

    import java.awt.geom.Point2D;
    import java.util.Random;

    public class Paradox {
        final static double ROOT_THREE = Math.sqrt(3);

        public static void main(String[] args) {
            int greater = 0;
            int less = 0;
            for (int i = 0; i < 1000000; i++) {
                Point2D.Double a = getRandomPoint();
                Point2D.Double b = getRandomPoint();

                //pythagorean
                if (Math.sqrt(Math.pow((a.x - b.x), 2) + Math.pow((a.y - b.y), 2)) > ROOT_THREE) {
                    greater++;
                } else {
                    less++;
                }   
            }
            System.out.println("Probability Observerd: " + (double)greater/(greater+less));
        }

        public static Point2D.Double getRandomPoint() {
            //get an x such that -1 < x < 1
            double x = Math.random();
            boolean xsign = new Random().nextBoolean();
            if (!xsign) {
                x *= -1;
            }

            //formula for a circle centered on origin with radius 1: x^2 + y^2 = 1
            double y = Math.sqrt(1 - (Math.pow(x, 2)));
            boolean ysign = new Random().nextBoolean();
            if (!ysign) {
                y *= -1;
            }

            Point2D.Double point = new Point2D.Double(x, y);
            return point;
        }
    }

EDIT: Thanks to a bunch of people setting me straight, I found that my method of finding a random point wasn't indeed so random. Here is a fix for that function which returns about 1/3.

        public static Point2D.Double getRandomPoint() {
            //get an x such that -1 < x < 1
            double x = Math.random();
            Random r = new Random();
            if (!r.nextBoolean()) {
                x *= -1;
            }

            //circle centered on origin: x^2 + y^2 = r^2. r is 1. 
            double y = Math.sqrt(1 - (Math.pow(x, 2)));
            if (!r.nextBoolean()) {
                y *= -1;
            }

            if (r.nextBoolean()) {
                return new Point2D.Double(x, y);
            } else {
                return new Point2D.Double(y, x);
            }
        }
Jonas Schreiber
  • 447
  • 4
  • 13
  • A note on the three different 'answers' (`1/2`, `1/3` and `1/4`) on the linked page: The question only talks about a 'random chord', but doesn't say anything about the probability distribution for 'randomly' placing the chord. The three answers are for three different probability distributions. – das-g Aug 05 '15 at 19:43
  • Your definition of "random" doesn't match any of the three definitions under the link. Naturally, the outcome will be different. Have you analyzed your particular case? – Marko Topolnik Aug 05 '15 at 19:44
  • .36 is pretty close to 1/3. Try increasing the upper limit on `i`. The [Law of Large numbers](https://en.wikipedia.org/wiki/Law_of_large_numbers) might help you out here. – Jeffrey Aug 05 '15 at 19:46
  • It doesn't look like the OP's approach gives 1/3. I've tried it several times and I consistently get 0.36... The OP's approach to choosing a random chord is so complex that I reckon it's going to be pretty hard to do the maths, but I could be wrong. – Paul Boddington Aug 05 '15 at 19:50
  • @PaulBoddington It looks like OP is trying to implement the [random endpoints method](https://en.wikipedia.org/wiki/Bertrand_paradox_(probability)#Bertrand.27s_formulation_of_the_problem) (#1). Which theoretically produces P = 1/3. There is a bug in his code if it doesn't. – Jeffrey Aug 05 '15 at 19:52
  • I ran it up to 10M times so it's consistent. Sorry about the complexity of choosing points. My method was - find an x between -1 and 1, and then you know there will be two corresponding y points +/- (or 1 in the case where x = 0). Choose one and return it. I think the bug could be that Math.random() gives you x such that 0 <= x < 1. So I don't think it could give you 1. – Jonas Schreiber Aug 05 '15 at 19:53
  • @Jeffrey No it isn't. The random endpoints method is to choose two points by picking two random angles in the interval [0, 2pi] uniformly. The OP's method is to choose two random x-coordinates uniformly from [-1, 1]. It's totally different. – Paul Boddington Aug 05 '15 at 19:54
  • @Jeffrey It is not random endpoints. OP chooses the x coordinate randomly instead of a random _angular_ coordinate. – Marko Topolnik Aug 05 '15 at 19:54
  • Reaaallly? Wow. How's that throwing off my probability though - it says give me a random point on this circle. – Jonas Schreiber Aug 05 '15 at 19:57
  • 1
    You need a lesson on probability densities, it would seem. Your probability distribution in the polar coordinate space is _very_ non-uniform. It even touches zero for -1 and 1. – Marko Topolnik Aug 05 '15 at 19:59
  • Do this: calculate the actual angle of your "randomly chosen" points. Approximate their probability distribution by keeping a number of brackets (angle intervals) and incrementing a counter each time you hit a bracket. Plot the result. – Marko Topolnik Aug 05 '15 at 20:03
  • As I said, Math.random() gives you 1>x >= 0. I realized that the probability of getting 1 is 0. You think if I fix that so that 1>=x>=0 I'll get the right answer? I will look at the distribution of angle intervals. Thanks – Jonas Schreiber Aug 05 '15 at 20:05
  • No, that's irrelevant. The probability _approaches_ 0 as angle approaches 0 and π, and it does so even assuming a perfectly uniform random distribution of your x values. – Marko Topolnik Aug 05 '15 at 20:08
  • Ahhh okay. This fixes it. If I randomly assign x, y (so that the point is (x, y) or (y, x) I get the correct answer. – Jonas Schreiber Aug 05 '15 at 20:11
  • Allergic to the trig functions? :-) – BaseZen Aug 05 '15 at 20:20
  • If anyone's interested, I've computed the theoretical probability for the OP's method, and found it to be `1/4 + pi/(16 sqrt(3)) = 0.363362...`. – Paul Boddington Aug 05 '15 at 22:42
  • Not allergic. My answer yields what I wanted it to, so I'm done. Ensuring one's own sanity isn't typically something one takes pride in. – Jonas Schreiber Aug 06 '15 at 01:07
  • @PaulBoddington I'd love the Calculus refresher that computes that! I suppose it's a finite integral of some kind? – BaseZen Aug 06 '15 at 05:16

3 Answers3

5

I believe you need to assume one fixed point say at (0, 1) and then choose a random amount of rotation in [0, 2*pi] around the circle for the location of the second point of the chord.

Just for the hell of it I wrote your incorrect version in Swift (learn Swift!):

    struct P {
        let x, y: Double
        init() {
            x = (Double(arc4random()) / 0xFFFFFFFF) * 2 - 1
            y = sqrt(1 - x * x) * (arc4random() % 2 == 0 ? 1 : -1)
        }
        func dist(other: P) -> Double {
            return sqrt((x - other.x) * (x - other.x) + (y - other.y) * (y - other.y))
        }
    }
    let root3 = sqrt(3.0)
    let total = 100_000_000
    var samples = 0
    for var i = 0; i < total; i++ {
        if P().dist(P()) > root3 {
            samples++
        }
    }
    println(Double(samples) / Double(total))

And the answer is indeed 0.36. As the comments have been explaining, a random X value is more likely to choose the "flattened area" around pi/2 and highly unlikely to choose the "vertically squeezed" area around 0 and pi.

It is easily fixed however in the constructor for P: (Double(arc4random()) / 0xFFFFFFFF is fancy-speak for random floating point number in [0, 1))

        let angle = Double(arc4random()) / 0xFFFFFFFF * M_PI * 2
        x = cos(angle)
        y = sin(angle)
        // outputs 0.33334509
BaseZen
  • 8,650
  • 3
  • 35
  • 47
  • Thanks man! I've been meaning to learn Swift, but I read that its execution environment is primarily iOS? That can't be right can it? By the way, what is the notation [x, y). Got an 800 on Math SAT, took up to multivariable calculus at Rutgers, graduated only a year and a half ago, and still, I can't remember having seen that until recently. – Jonas Schreiber Aug 06 '15 at 01:05
  • It is limited to Mac OS X and iOS, yes, but Apple has announced that it will be Open Sourced so that it will at least run on Linux within a few months. The [x, y) is just real-number set notation, meaning "all values t such that x <= t < y" – BaseZen Aug 06 '15 at 05:15
2

Bertrand's paradox is exactly that: a paradox. The answer can be argued to be 1/3 or 1/2 depending on how the problem is interpreted. It seems you took the random chord approach where one side of the line is fixed and then you draw a random chord to any part of the circle. Using this method, the chances of drawing a chord that is longer than sqrt(3) is indeed 1/3.

But if you use a different approach, I'll call it the random radius approach, you'll see that it can be 1/2! The random radius is this, you draw a radius in the circle, and then you take a random chord that this radius bisects. At this point, a random chord will be longer than sqrt(3) 1/2 of the time.

Lastly, the random midpoint method. Choose a random point in the circle, and then draw a chord with this random point as the midpoint of the chord. If this point falls within a concentric circle of radius 1/2, then the chord is shorter than sqrt(3). If it falls outside the concentric circle, it is longer than sqrt(3). A circle of radius 1/2 has 1/4 the area of a circle with radius 1, so the chance of a chord smaller than sqrt(3) is 1/4.

As for your code, I haven't had time to look at it yet, but hope this clarifies the paradox (which is just an incomplete question not actually a paradox) :D

Lewis James
  • 33
  • 10
  • Oh, I get the argument for all three answers, though I think the 1/2 is a bit naive. (Basically adds a constraint that you can only have your chords be parallel). But I still wanted to prove to myself that over many random tests the probability would converge on 1/3... – Jonas Schreiber Aug 05 '15 at 19:46
  • Parallel chords are just a small step away from all possible chords (you just apply rotational symmetry). – Marko Topolnik Aug 05 '15 at 19:52
1

I would argue that the Bertrand paradox is less a paradox and more a cautionary lesson in probability. It's really asking the question: What do you mean by random?

Bertrand argued that there are three natural but different methods for randomly choosing a chord, giving three distinct answers. But of course, there are other random methods, but these methods are arguably not the most natural ones (that is, not the first that come to mind). For example, we could randomly position the two chord endpoints in a non-uniform manner. Or we position the chord midpoint according to some non-uniform density, like a truncated bi-variate normal.

To simulate the three methods with a programming language, you need to be able to generate uniform random variables on the unit interval, which is what all standard (pseudo)-random number generators should do. For one of the methods/solutions (the random midpoint one), you then have to take the square root of one of the uniform random variables. You then multiple the random variables by a suitable factor (or rescale). Then for each simulation method (or solution), some geometry gives the expressions for the two endpoints.

For more details, I have written a post about this problem. I recommend the links and books I have cited at the end of that post, under the section Further reading. For example, see Section 1.3 in this new set of published lecture notes. The Bertrand paradox is also in The Pleasures of Probability by Isaac. It’s covered in a non-mathematical way in the book Paradoxes from A to Z by Clark.

I have also uploaded some simulation code in MATLAB, R and Python, which can be found here.

For example, in Python (with NumPy):

import numpy as np; #NumPy package for arrays, random number generation, etc
import matplotlib.pyplot as plt #for plotting
from matplotlib import collections  as mc #for plotting line chords      

###START Parameters START###
#Simulation disk dimensions
xx0=0; yy0=0; #center of disk
r=1; #disk radius
numbLines=10**2;#number of lines
###END Parameters END###

###START Simulate three solutions on a disk START###
#Solution A
thetaA1=2*np.pi*np.random.uniform(0,1,numbLines); #choose angular component uniformly
thetaA2=2*np.pi*np.random.uniform(0,1,numbLines); #choose angular component uniformly

#calculate chord endpoints
xxA1=xx0+r*np.cos(thetaA1);
yyA1=yy0+r*np.sin(thetaA1);
xxA2=xx0+r*np.cos(thetaA2);
yyA2=yy0+r*np.sin(thetaA2);
#calculate midpoints of chords
xxA0=(xxA1+xxA2)/2; yyA0=(yyA1+yyA2)/2;

#Solution B
thetaB=2*np.pi*np.random.uniform(0,1,numbLines); #choose angular component uniformly
pB=r*np.random.uniform(0,1,numbLines); #choose radial component uniformly
qB=np.sqrt(r**2-pB**2); #distance to circle edge (alonge line)

#calculate trig values
sin_thetaB=np.sin(thetaB);
cos_thetaB=np.cos(thetaB);

#calculate chord endpoints
xxB1=xx0+pB*cos_thetaB+qB*sin_thetaB;
yyB1=yy0+pB*sin_thetaB-qB*cos_thetaB;
xxB2=xx0+pB*cos_thetaB-qB*sin_thetaB;
yyB2=yy0+pB*sin_thetaB+qB*cos_thetaB;
#calculate midpoints of chords
xxB0=(xxB1+xxB2)/2; yyB0=(yyB1+yyB2)/2;

#Solution C
#choose a point uniformly in the disk
thetaC=2*np.pi*np.random.uniform(0,1,numbLines); #choose angular component uniformly
pC=r*np.sqrt(np.random.uniform(0,1,numbLines)); #choose radial component
qC=np.sqrt(r**2-pC**2); #distance to circle edge (alonge line)

#calculate trig values
sin_thetaC=np.sin(thetaC);
cos_thetaC=np.cos(thetaC);

#calculate chord endpoints
xxC1=xx0+pC*cos_thetaC+qC*sin_thetaC;
yyC1=yy0+pC*sin_thetaC-qC*cos_thetaC;
xxC2=xx0+pC*cos_thetaC-qC*sin_thetaC;
yyC2=yy0+pC*sin_thetaC+qC*cos_thetaC;
#calculate midpoints of chords
xxC0=(xxC1+xxC2)/2; yyC0=(yyC1+yyC2)/2;
###END Simulate three solutions on a disk END###
Keeler
  • 151
  • 2