I found the answer from the book Numerical Recipes in C, but unfortunately the code in that book is copyrighted. So, I re-derived a similar code that is slightly different but does the same thing.
The idea is that we select a random number from distribution $g(x)$ that has the property that $f(x) < c g(x)$ always with a finite constant $c$, where $f(x)$ is our Poisson distribution consisting of boxes of width 1.
Now, the selected $g(x)$ is $g(x) = \frac{1}{\pi \gamma}\frac{\gamma^2}{(x-x_0)^2+\gamma^2}$ which is the Cauchy distribution. The CDF is $y = F(x) = \frac{1}{\pi}\arctan(\frac{x-x_0}{\gamma}) + \frac{1}{2}$ and the inverse CDF is $x = x_0 + \gamma\tan(\pi(y-\frac{1}{2}))$. Thus, we generate $y$ randomly from uniform distribution between 0.0 and 1.0, and then calculate $x$. The parameters we select are $x_0 = \lambda$ and $\gamma = \sqrt{\lambda}$ where $\lambda$ is the parameter (mean value) of the Poisson distribution.
This distribution has negative values as well, so every time a negative value is obtained, the $y$ and $x$ need to be recalculated.
For this choice of distribution, it is true that $f(\lfloor x \rfloor)$ is always smaller than $2.4g(x)$ given any value of $\lambda$. So, we calculate the ratio $\frac{f(\lfloor x \rfloor)}{2.4g(x)}$ and reject if a uniformly distributed random variable $U$ between 0.0 and 1.0 is $U > \frac{f(\lfloor x \rfloor)}{2.4g(x)}$.
To calculate $f(\lfloor x \rfloor) = f(m) = \exp(-\lambda)\frac{\lambda^m}{m!}$, we calculate $\exp(m\log\lambda - \lambda - \textrm{lgamma}(m+1))$. The function $\textrm{lgamma}$ has a series representation.
Thus, the C code follows. I have tested that the C code gives me integers that have very accurate mean and also very accurate standard deviation. Thus, I believe the code is correct. The break-even point 60 was empirically determined so that the two algorithms given this point are equally fast.
The code is here:
double lgamma(double xx)
{
double pi = 3.14159265358979;
double xx2 = xx*xx;
double xx3 = xx2*xx;
double xx5 = xx3*xx2;
double xx7 = xx5*xx2;
double xx9 = xx7*xx2;
double xx11 = xx9*xx2;
return xx*log(xx) - xx - 0.5*log(xx/(2*pi)) +
1/(12*xx) - 1/(360*xx3) + 1/(1260*xx5) - 1/(1680*xx7) +
1/(1188*xx9) - 691/(360360*xx11);
}
int poissrnd_small(double mean)
{
double L = exp(-mean);
double p = 1;
int result = 0;
do {
result++;
p *= drand48();
} while (p > L);
result--;
return result;
}
int poissrnd_large(double mean)
{
double r;
double x, m;
double pi = 3.14159265358979;
double sqrt_mean = sqrt(mean);
double log_mean = log(mean);
double g_x;
double f_m;
do {
do {
x = mean + sqrt_mean*tan(pi*(drand48()-1/2.0));
} while (x < 0);
g_x = sqrt_mean/(pi*((x-mean)*(x-mean) + mean));
m = floor(x);
f_m = exp(m*log_mean - mean - lgamma(m + 1));
r = f_m / g_x / 2.4;
} while (drand48() > r);
return (int)m;
}
int poissrnd(double mean)
{
if (mean < 60)
{
return poissrnd_small(mean);
}
else
{
return poissrnd_large(mean);
}
}
Edit: I hereby place the code under public domain. Thus, you are free to use it however you want to, no need to attribute anything. The code has been entirely written by me.