exponential_biased_test.cc 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. // Copyright 2019 The Abseil Authors.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // https://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #include "absl/profiling/internal/exponential_biased.h"
  15. #include <stddef.h>
  16. #include <cmath>
  17. #include <cstdint>
  18. #include <vector>
  19. #include "gmock/gmock.h"
  20. #include "gtest/gtest.h"
  21. #include "absl/strings/str_cat.h"
  22. using ::testing::Ge;
  23. namespace absl {
  24. ABSL_NAMESPACE_BEGIN
  25. namespace profiling_internal {
  26. MATCHER_P2(IsBetween, a, b,
  27. absl::StrCat(std::string(negation ? "isn't" : "is"), " between ", a,
  28. " and ", b)) {
  29. return a <= arg && arg <= b;
  30. }
  31. // Tests of the quality of the random numbers generated
  32. // This uses the Anderson Darling test for uniformity.
  33. // See "Evaluating the Anderson-Darling Distribution" by Marsaglia
  34. // for details.
  35. // Short cut version of ADinf(z), z>0 (from Marsaglia)
  36. // This returns the p-value for Anderson Darling statistic in
  37. // the limit as n-> infinity. For finite n, apply the error fix below.
  38. double AndersonDarlingInf(double z) {
  39. if (z < 2) {
  40. return exp(-1.2337141 / z) / sqrt(z) *
  41. (2.00012 +
  42. (0.247105 -
  43. (0.0649821 - (0.0347962 - (0.011672 - 0.00168691 * z) * z) * z) *
  44. z) *
  45. z);
  46. }
  47. return exp(
  48. -exp(1.0776 -
  49. (2.30695 -
  50. (0.43424 - (0.082433 - (0.008056 - 0.0003146 * z) * z) * z) * z) *
  51. z));
  52. }
  53. // Corrects the approximation error in AndersonDarlingInf for small values of n
  54. // Add this to AndersonDarlingInf to get a better approximation
  55. // (from Marsaglia)
  56. double AndersonDarlingErrFix(int n, double x) {
  57. if (x > 0.8) {
  58. return (-130.2137 +
  59. (745.2337 -
  60. (1705.091 - (1950.646 - (1116.360 - 255.7844 * x) * x) * x) * x) *
  61. x) /
  62. n;
  63. }
  64. double cutoff = 0.01265 + 0.1757 / n;
  65. if (x < cutoff) {
  66. double t = x / cutoff;
  67. t = sqrt(t) * (1 - t) * (49 * t - 102);
  68. return t * (0.0037 / (n * n) + 0.00078 / n + 0.00006) / n;
  69. } else {
  70. double t = (x - cutoff) / (0.8 - cutoff);
  71. t = -0.00022633 +
  72. (6.54034 - (14.6538 - (14.458 - (8.259 - 1.91864 * t) * t) * t) * t) *
  73. t;
  74. return t * (0.04213 + 0.01365 / n) / n;
  75. }
  76. }
  77. // Returns the AndersonDarling p-value given n and the value of the statistic
  78. double AndersonDarlingPValue(int n, double z) {
  79. double ad = AndersonDarlingInf(z);
  80. double errfix = AndersonDarlingErrFix(n, ad);
  81. return ad + errfix;
  82. }
  83. double AndersonDarlingStatistic(const std::vector<double>& random_sample) {
  84. int n = random_sample.size();
  85. double ad_sum = 0;
  86. for (int i = 0; i < n; i++) {
  87. ad_sum += (2 * i + 1) *
  88. std::log(random_sample[i] * (1 - random_sample[n - 1 - i]));
  89. }
  90. double ad_statistic = -n - 1 / static_cast<double>(n) * ad_sum;
  91. return ad_statistic;
  92. }
  93. // Tests if the array of doubles is uniformly distributed.
  94. // Returns the p-value of the Anderson Darling Statistic
  95. // for the given set of sorted random doubles
  96. // See "Evaluating the Anderson-Darling Distribution" by
  97. // Marsaglia and Marsaglia for details.
  98. double AndersonDarlingTest(const std::vector<double>& random_sample) {
  99. double ad_statistic = AndersonDarlingStatistic(random_sample);
  100. double p = AndersonDarlingPValue(random_sample.size(), ad_statistic);
  101. return p;
  102. }
  103. TEST(ExponentialBiasedTest, CoinTossDemoWithGetSkipCount) {
  104. ExponentialBiased eb;
  105. for (int runs = 0; runs < 10; ++runs) {
  106. for (int flips = eb.GetSkipCount(1); flips > 0; --flips) {
  107. printf("head...");
  108. }
  109. printf("tail\n");
  110. }
  111. int heads = 0;
  112. for (int i = 0; i < 10000000; i += 1 + eb.GetSkipCount(1)) {
  113. ++heads;
  114. }
  115. printf("Heads = %d (%f%%)\n", heads, 100.0 * heads / 10000000);
  116. }
  117. TEST(ExponentialBiasedTest, SampleDemoWithStride) {
  118. ExponentialBiased eb;
  119. int stride = eb.GetStride(10);
  120. int samples = 0;
  121. for (int i = 0; i < 10000000; ++i) {
  122. if (--stride == 0) {
  123. ++samples;
  124. stride = eb.GetStride(10);
  125. }
  126. }
  127. printf("Samples = %d (%f%%)\n", samples, 100.0 * samples / 10000000);
  128. }
  129. // Testing that NextRandom generates uniform random numbers. Applies the
  130. // Anderson-Darling test for uniformity
  131. TEST(ExponentialBiasedTest, TestNextRandom) {
  132. for (auto n : std::vector<int>({
  133. 10, // Check short-range correlation
  134. 100, 1000,
  135. 10000 // Make sure there's no systemic error
  136. })) {
  137. uint64_t x = 1;
  138. // This assumes that the prng returns 48 bit numbers
  139. uint64_t max_prng_value = static_cast<uint64_t>(1) << 48;
  140. // Initialize.
  141. for (int i = 1; i <= 20; i++) {
  142. x = ExponentialBiased::NextRandom(x);
  143. }
  144. std::vector<uint64_t> int_random_sample(n);
  145. // Collect samples
  146. for (int i = 0; i < n; i++) {
  147. int_random_sample[i] = x;
  148. x = ExponentialBiased::NextRandom(x);
  149. }
  150. // First sort them...
  151. std::sort(int_random_sample.begin(), int_random_sample.end());
  152. std::vector<double> random_sample(n);
  153. // Convert them to uniform randoms (in the range [0,1])
  154. for (int i = 0; i < n; i++) {
  155. random_sample[i] =
  156. static_cast<double>(int_random_sample[i]) / max_prng_value;
  157. }
  158. // Now compute the Anderson-Darling statistic
  159. double ad_pvalue = AndersonDarlingTest(random_sample);
  160. EXPECT_GT(std::min(ad_pvalue, 1 - ad_pvalue), 0.0001)
  161. << "prng is not uniform: n = " << n << " p = " << ad_pvalue;
  162. }
  163. }
  164. // The generator needs to be available as a thread_local and as a static
  165. // variable.
  166. TEST(ExponentialBiasedTest, InitializationModes) {
  167. ABSL_CONST_INIT static ExponentialBiased eb_static;
  168. EXPECT_THAT(eb_static.GetSkipCount(2), Ge(0));
  169. #ifdef ABSL_HAVE_THREAD_LOCAL
  170. thread_local ExponentialBiased eb_thread;
  171. EXPECT_THAT(eb_thread.GetSkipCount(2), Ge(0));
  172. #endif
  173. ExponentialBiased eb_stack;
  174. EXPECT_THAT(eb_stack.GetSkipCount(2), Ge(0));
  175. }
  176. } // namespace profiling_internal
  177. ABSL_NAMESPACE_END
  178. } // namespace absl