The 538 Riddler: Free Throw Grannies

Hello, and welcome to this week’s look at the 538 Riddler. Last week concerned optimal strategy for a (very) simple game show, and happily my answer was correct. This week’s Riddler concerns free throws again.

Consider the following simplified model of free throws. Imagine the rim to be a circle (which we’ll call C) that has a radius of 1, and is centered at the origin (the point (0,0)). Let V be a random point in the plane, with coordinates X and Y, and where X and Y are independent normal random variables, with means equal to zero and each having equal variance — think of this as the point where your free throw winds up, in the rim’s plane. If V is in the circle, your shot goes in. Finally, suppose that the variance is chosen such that the probability that V is in C is exactly 75 percent (roughly the NBA free-throw average).

But suppose you switch it up, and go granny-style, which in this universe eliminates any possible left-right error in your free throws. What’s the probability you make your shot now? (Put another way, calculate the probability that |Y| < 1.)

So I’ve been doing all these Riddler exercises in C++ but this week I thought I’d mix it up and give the Go language a shot. I’ve never written anything in Go but a friend of mine sent me this text a while back:

text_from_sean

As you can see, I have an exciting social life. So anyway I’ve been wanting to try it out for a while and I figured this blog would be a good opportunity. I’ve been doing the Go tutorials that you can find here.

Another benefit of doing the code (when possible) in Go is that I can link to a version of my code that you can run yourself in the browser, and then make changes to see the impact of those changes. I’m not sure that anyone was copying my C++ code into a compiler, creating a project, building, then running it. But this way running the code is literally just a click away.

Okay, so I thought this week’s Riddler was pretty straightforward from a “getting an answer” point of view. (Which probably means I’m totally wrong.) If I simulate a normalized random distribution of 2D points with some variance such that 75% of those points fall inside a circle with radius 1, then what would be the probability of falling in the circle if the x-component was always 0?

Luckily, Go has a really nice NormFloat64 function that generates normalized random numbers with a standard deviation of 1. With such variance, about 40% of random points will be inside the circle, using the good old Pythagorean Theorem. If I understand the problem correctly all I need to do is find the standard deviation that will result in 75% of points falling inside the circle. Then, I can calculate the magnitude of points where the x-component is 0, and find how frequently they fall in the circle.

So the big task here was to find the right value for the deviation factor. I did this with trial and error and came up with 0.60054. I’m sure there’s a math way to find this value (or a better value) and I look forward to seeing it (Attn: Alex!). Once you start generating x- and y-components, find their magnitude using Sqrt(x*x + y*y) and see if it is below 1. If it is, then that’s a made shot. Also, check to see what would happen if the x-component is 0. You can do that as Sqrt(0*0 + y*y) or Sqrt(y*y) or Abs(y).

Here’s the code in Go:

// 538 Riddler: Should You Shoot Free Throws Underhand?
// http://fivethirtyeight.com/features/should-you-shoot-free-throws-underhand/
// Jon Wiesman, somedisagree.com
package main

import (
	"fmt"
	"math"
	"math/rand"
)

func main() {

	overhand := 0
	granny := 0

	trials := 1000000
	r := rand.New(rand.NewSource(int64(538)))

	dev := 0.60054
	
	for i := 0; i < trials; i++ {
		x := r.NormFloat64() * dev
		y := r.NormFloat64() * dev

		d := math.Sqrt(x*x + y*y)
		g := math.Abs(y)

		if d < 1 {
			overhand++
		}
		if g < 1 {
			granny++
		}
	}

	fmt.Printf("Overhand = %f%%\n", float64(overhand)*100.0/float64(trials))
	fmt.Printf("Granny = %f%%\n", float64(granny)*100.0/float64(trials))
}

 

And here’s a link that will take you to a Go playground where you can run that code and see these results:

Overhand = 75.000800%
Granny = 90.439500%

Try it! You can also play around with different random seed values (I used 538, natch) and see what happens. I think the actual make percentage for Granny-style is more like 90.41%, depending on random seed and number of trials.

Thanks for reading!

Author: Wiesman

Husband, father, video game developer, liberal, and perpetual Underdog.

10 thoughts on “The 538 Riddler: Free Throw Grannies”

  1. Your standard deviation is close. The actual value is 0.5/sqrt(ln(2))=0.6005612044…

    The easiest way that I know to find the standard deviation is to know that if X and Y are independent normal variables with mean 0 and the same standard deviation, then the distance from the origin (0,0) to the point (X,Y) [ie, sqrt(X^2+Y^2)] follows a Rayleigh distribution with parameter equal to the standard deviation of X and Y. The Rayleigh distribution has a simple cumulative distribution function, and plugging in the constraints and some simple algebra gets you to the correct standard deviation. Then you need to use a normal distribution calculator to find the probability of making the granny shot. It ends up being 0.9041090758…

    Here is some Python simulation code I made to verify the answer:

    from random import gauss
    import math

    simtotal = 10000000
    normcount = 0
    grannycount = 0
    mu = 0
    sigma = 0.5/math.sqrt(math.log(2))
    for i in range(simtotal):
    x = gauss(mu, sigma)
    y = gauss(mu, sigma)
    if (math.sqrt(x**2+y**2)<1):
    normcount = normcount +1
    if (abs(y)<1):
    grannycount = grannycount +1
    print('Normal shot percent: '+str(100*normcount/simtotal)+'\n'+'Granny shot percent: '+str(100*grannycount/simtotal))

  2. Whoops, looks like the code didn’t format correctly. Python requires indentation, so if you want to run that code, you need to indent the if and for statements.

      1. This week’s riddle almost didn’t feel fair to me. Only a trained statistician or physicist would have heard of the Rayleigh distribution, and this riddle will be easy for anyone who knows about it.

      2. Actually, the direct integration isn’t too bad. Once you realize that the integrand has nothing to do with *theta*, you can just multiply by 2*pi* and eliminate that integral. The remaining integral – in terms of radius – is the Rayleigh distribution you were referring to, but because of the structure, you can use a u-substitution to integrate quite nicely. Even without knowing what the Rayleigh distribution is, the actual integration only took about a minute.

  3. I am not a trained statistician and have never heard of the Rayleigh distribution but I was able to get to the answer using the Chi-squared distribution. I had never heard of that either before but I knew that I needed the distribution for the sum of the squares of two normally distributed independent variables and googling that got me to the Chi-square wiki page which had an incredibly easy equation for “a sum of the squares of k independent standard normal random variables” – sounds perfect except that x and y aren’t standard. Standardizing them wasn’t horribly difficult (just divided by the variance) plug it all in excel’s built in function and I got the same standard deviation you did….

  4. I soon found that the granny shot puzzle required math which I simply didn’t know, which was frustrating. I was pressed this week so I didn’t even attempt to solve it, so well done those who did.
    This week’s riddle is much more satisfying in my mind. I think I’ve cracked it, although I won’t spoil it for you.

    1. Thanks Alex. Yeah, I haven’t had a chance to do any work on it yet but I’ve got an idea in my head about how to go about it. Look for a post about a minute after the deadline Sunday night.

Disagree?

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s