random_test.cxx 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. //
  2. // random_test.cpp
  3. // shared_random_generator-test
  4. //
  5. // Created by Sam Jaffe on 8/14/20.
  6. // Copyright © 2020 Sam Jaffe. All rights reserved.
  7. //
  8. #include "random/random.h"
  9. #include "random/device.h"
  10. #include "xcode_gtest_helper.h"
  11. using testing::DoubleNear;
  12. struct MockDevice : engine::random::Device {
  13. MOCK_METHOD2(s_inclusive, int32_t(int32_t, int32_t));
  14. MOCK_METHOD2(u_inclusive, uint32_t(uint32_t, uint32_t));
  15. MOCK_METHOD2(exclusive, double(double, double));
  16. int32_t inclusive(int32_t min, int32_t max) { return s_inclusive(min, max); }
  17. uint32_t inclusive(uint32_t min, uint32_t max) {
  18. return u_inclusive(min, max);
  19. }
  20. };
  21. TEST(RandomTest, ExclusiveIntegerPassedAsInclusive) {
  22. auto mock = std::make_shared<MockDevice>();
  23. engine::random::Random generator{mock};
  24. EXPECT_CALL(*mock, s_inclusive(-10, 9)).Times(1);
  25. generator.exclusive(-10, 10);
  26. }
  27. TEST(RandomTest, ExclusiveUIntegerPassedAsInclusive) {
  28. auto mock = std::make_shared<MockDevice>();
  29. engine::random::Random generator{mock};
  30. EXPECT_CALL(*mock, u_inclusive(0, 9)).Times(1);
  31. generator.exclusive(0u, 10u);
  32. }
  33. TEST(RandomTest, PassesThroughExclusiveDoubleCall) {
  34. auto mock = std::make_shared<MockDevice>();
  35. engine::random::Random generator{mock};
  36. EXPECT_CALL(*mock, exclusive(1.0, 10.0)).Times(1);
  37. generator.exclusive(1.0, 10.0);
  38. }
  39. TEST(RandomTest, DoctorsInclusiveDoubleCall) {
  40. auto mock = std::make_shared<MockDevice>();
  41. engine::random::Random generator{mock};
  42. EXPECT_CALL(*mock, exclusive(1.0, DoubleNear(10.0, 1e-7))).Times(1);
  43. generator.inclusive(1.0, 10.0);
  44. }
  45. class kahan_summation {
  46. private:
  47. double sum_{0.0};
  48. double carry_{0.0};
  49. public:
  50. kahan_summation() = default;
  51. kahan_summation & operator+=(double d);
  52. explicit operator double() const { return sum_; }
  53. };
  54. kahan_summation & kahan_summation::operator+=(double num) {
  55. double const yield = num - carry_;
  56. double const total = sum_ + yield;
  57. carry_ = (total - sum_) - yield;
  58. sum_ = total;
  59. return *this;
  60. }
  61. TEST(DefaultRandomTest, RandomDistributionIntIsUniform) {
  62. engine::random::Random generator{};
  63. kahan_summation sum{};
  64. size_t const iters = 2000000;
  65. for (size_t i = 0; i < iters; ++i) {
  66. // All values from 0 - 100 are allowable
  67. sum += generator.inclusive(0, 100);
  68. }
  69. // Expected result is (0+99)/2 +/- 0.1%
  70. EXPECT_THAT(double(sum) / iters, DoubleNear(50, 0.05));
  71. }
  72. TEST(DefaultRandomTest, RandomDistributionDblIsUniform) {
  73. engine::random::Random generator{};
  74. kahan_summation sum{};
  75. size_t const iters = 2000000;
  76. for (size_t i = 0; i < iters; ++i) {
  77. // All values from 0 - 99 are allowable
  78. sum += generator.exclusive(0.0, 100.0);
  79. }
  80. // Expected result is [0.0, 100.0) +/- 0.1%
  81. EXPECT_THAT(double(sum) / iters, DoubleNear(50, 0.05));
  82. }
  83. TEST(DefaultRandomTest, InclusiveRangeMayIncludeValue) {
  84. engine::random::Random generator{};
  85. EXPECT_THAT(generator.inclusive(1.0, 1.0), DoubleNear(1.0, 1E-6));
  86. }
  87. TEST(DefaultRandomTest, RandomDistributionDblInclIsUniform) {
  88. engine::random::Random generator{};
  89. kahan_summation sum{};
  90. size_t const iters = 2000000;
  91. for (size_t i = 0; i < iters; ++i) {
  92. // All values in [0.0, 100.0] are allowable
  93. sum += generator.inclusive(0.0, 100.0);
  94. }
  95. // Expected result is (0+100)/2 +/- 0.1%
  96. EXPECT_THAT(double(sum) / iters, DoubleNear(50, 0.05));
  97. }