#include <cmath>
#include <cstddef>
#include <iostream>
#include <limits>
#include <string>
#include "absl/base/macros.h"
#include "absl/random/gaussian_distribution.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace random_internal {
namespace {
template <typename T, size_t N>
void FormatArrayContents(std::ostream* os, T (&data)[N]) {
if (!std::numeric_limits<T>::is_exact) {
os->precision(std::numeric_limits<T>::max_digits10 + 2);
}
*os << " {";
std::string separator = "";
for (size_t i = 0; i < N; ++i) {
*os << separator << data[i];
if ((i + 1) % 3 != 0) {
separator = ", ";
} else {
separator = ",\n ";
}
}
*os << "}";
}
}
class TableGenerator : public gaussian_distribution_base {
public:
TableGenerator();
void Print(std::ostream* os);
using gaussian_distribution_base::kMask;
using gaussian_distribution_base::kR;
using gaussian_distribution_base::kV;
private:
Tables tables_;
};
TableGenerator::TableGenerator() {
static constexpr int kC = kMask + 1;
static_assert((ABSL_ARRAYSIZE(tables_.x) == kC + 1),
"xArray must be length kMask + 2");
static_assert((ABSL_ARRAYSIZE(tables_.x) == ABSL_ARRAYSIZE(tables_.f)),
"fx and x arrays must be identical length");
auto f = [](double x) { return std::exp(-0.5 * x * x); };
auto f_inv = [](double x) { return std::sqrt(-2.0 * std::log(x)); };
tables_.x[0] = kV / f(kR);
tables_.f[0] = f(tables_.x[0]);
tables_.x[1] = kR;
tables_.f[1] = f(tables_.x[1]);
tables_.x[kC] = 0.0;
tables_.f[kC] = f(tables_.x[kC]);
for (int i = 2; i < kC; i++) {
double v = (kV / tables_.x[i - 1]) + tables_.f[i - 1];
tables_.x[i] = f_inv(v);
tables_.f[i] = v;
}
}
void TableGenerator::Print(std::ostream* os) {
*os << "// BEGIN GENERATED CODE; DO NOT EDIT\n"
"// clang-format off\n"
"\n"
"#include \"absl/random/gaussian_distribution.h\"\n"
"\n"
"namespace absl {\n"
"ABSL_NAMESPACE_BEGIN\n"
"namespace random_internal {\n"
"\n"
"const gaussian_distribution_base::Tables\n"
" gaussian_distribution_base::zg_ = {\n";
FormatArrayContents(os, tables_.x);
*os << ",\n";
FormatArrayContents(os, tables_.f);
*os << "};\n"
"\n"
"} // namespace random_internal\n"
"ABSL_NAMESPACE_END\n"
"} // namespace absl\n"
"\n"
"// clang-format on\n"
"// END GENERATED CODE";
*os << std::endl;
}
}
ABSL_NAMESPACE_END
}
int main(int, char**) {
std::cerr << "\nCopy the output to gaussian_distribution.cc" << std::endl;
absl::random_internal::TableGenerator generator;
generator.Print(&std::cout);
return 0;
}