User Izumi Kawashima at StackOverflow pointed me to EasyCalculation.com's JavaScript algorithm (below). This made my job super easy.
His question is to find an even faster algorithm, so if you can think of one, I'm sure he'd appreciate it.
Posted here for posterity.
function positiveCube(s){
var d3 = 1 / 3.0;
return (s < 0) ? -Math.pow(-s, d3) : Math.pow(s, d3);
}
var p = [2,3,4,5]; // f(x) = 2 + 3x + 4x^2 + 5x^3
var roots = []; // found real roots will be pushed
var a = p[3];
var b = p[2] / a;
var c = p[1] / a;
var d = p[0] / a;
var b2 = b * b;
var q = (3.0 * c - b2) / 9.0;
var r = (-27.0 * d + b * (9.0 * c - 2.0 * b2)) / 54.0;
var q3 = q * q * q;
var discrim = q3 + r * r;
var term1 = b / 3.0;
if (discrim > 0) {
// One real, two complex roots
var s, t;
var discrimsq = Math.sqrt(discrim);
s = r + discrimsq;
t = r - discrimsq;
s = positiveCube(s);
t = positiveCube(t);
roots.push(-term1 + s + t);
}else if (discrim === 0) {
// Three real, two of them equal
var r13 = positiveCube(r);
roots.push(-term1 + r13 * 2.0);
roots.push(-r13 - term1);
roots.sort();
}else {
q = -q;
q3 = -q3;
var dum1 = Math.acos(r / Math.sqrt(q3));
var r13 = 2.0 * Math.sqrt(q);
roots.push(-term1 + r13 * Math.cos(dum1 / 3));
roots.push(-term1 + r13 * Math.cos((dum1 + 2 * Math.PI) / 3));
roots.push(-term1 + r13 * Math.cos((dum1 + 4 * Math.PI) / 3));
roots.sort();
}