double normalized_diffusion_sample( const double u, const double l, const double s, const double eps, const size_t max_iterations) { assert(u >= 0.0); assert(u < 1.0); const double d = l / s; // Handle the case where u is greater than the value we consider 1 in our CDF. if (u >= nd_cdf_rmax) return NdCdfTableRmax * d; // Use the CDF to find an initial interval for the root of cdf(r, 1) - u = 0. const size_t i = sample_cdf(nd_cdf_table, nd_cdf_table + NdCdfTableSize, u); assert(i > 0); assert(nd_cdf_table[i - 1] <= u); assert(nd_cdf_table[i] > u); // Transform the cdf(r, 1) interval to cdf(r, d) using the fact that cdf(r, d) == cdf(r/d, 1). double rmin = fit<size_t, double>(i - 1, 0, NdCdfTableSize - 1, 0.0, NdCdfTableRmax) * d; double rmax = fit<size_t, double>(i, 0, NdCdfTableSize - 1, 0.0, NdCdfTableRmax) * d; assert(normalized_diffusion_cdf(rmin, d) <= u); assert(normalized_diffusion_cdf(rmax, d) > u); double r = (rmax + rmin) * 0.5; // Refine the root. for (size_t i = 0; i < max_iterations; ++i) { // Use bisection if we go out of bounds. if (r < rmin || r > rmax) r = (rmax + rmin) * 0.5; const double f = normalized_diffusion_cdf(r, d) - u; // Convergence test. if (abs(f) <= eps) break; // Update bounds. f < 0.0 ? rmin = r : rmax = r; // Newton step. const double df = normalized_diffusion_pdf(r, d); r -= f / df; } return r; }
double normalized_diffusion_cdf( const double r, const double l, const double s) { return normalized_diffusion_cdf(r, l / s); }
float normalized_diffusion_cdf( const float r, const float l, const float s) { return normalized_diffusion_cdf(r, l / s); }