| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| |
| |
| |
| |
| #include "absl/random/gaussian_distribution.h" |
|
|
| #include <cmath> |
| #include <cstddef> |
| #include <iostream> |
| #include <limits> |
| #include <string> |
|
|
| #include "absl/base/macros.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; |
| } |
|
|