| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119 |
- //
- // random_test.cpp
- // shared_random_generator-test
- //
- // Created by Sam Jaffe on 8/14/20.
- // Copyright © 2020 Sam Jaffe. All rights reserved.
- //
- #include "random/random.h"
- #include "random/device.h"
- #include "xcode_gtest_helper.h"
- using testing::DoubleNear;
- struct MockDevice : engine::random::Device {
- MOCK_METHOD2(s_inclusive, int32_t(int32_t, int32_t));
- MOCK_METHOD2(u_inclusive, uint32_t(uint32_t, uint32_t));
- MOCK_METHOD2(exclusive, double(double, double));
- int32_t inclusive(int32_t min, int32_t max) { return s_inclusive(min, max); }
- uint32_t inclusive(uint32_t min, uint32_t max) {
- return u_inclusive(min, max);
- }
- };
- TEST(RandomTest, ExclusiveIntegerPassedAsInclusive) {
- auto mock = std::make_shared<MockDevice>();
- engine::random::Random generator{mock};
- EXPECT_CALL(*mock, s_inclusive(-10, 9)).Times(1);
- generator.exclusive(-10, 10);
- }
- TEST(RandomTest, ExclusiveUIntegerPassedAsInclusive) {
- auto mock = std::make_shared<MockDevice>();
- engine::random::Random generator{mock};
- EXPECT_CALL(*mock, u_inclusive(0, 9)).Times(1);
- generator.exclusive(0u, 10u);
- }
- TEST(RandomTest, PassesThroughExclusiveDoubleCall) {
- auto mock = std::make_shared<MockDevice>();
- engine::random::Random generator{mock};
- EXPECT_CALL(*mock, exclusive(1.0, 10.0)).Times(1);
- generator.exclusive(1.0, 10.0);
- }
- TEST(RandomTest, DoctorsInclusiveDoubleCall) {
- auto mock = std::make_shared<MockDevice>();
- engine::random::Random generator{mock};
- EXPECT_CALL(*mock, exclusive(1.0, DoubleNear(10.0, 1e-7))).Times(1);
- generator.inclusive(1.0, 10.0);
- }
- class kahan_summation {
- private:
- double sum_{0.0};
- double carry_{0.0};
- public:
- kahan_summation() = default;
- kahan_summation & operator+=(double d);
- explicit operator double() const { return sum_; }
- };
- kahan_summation & kahan_summation::operator+=(double num) {
- double const yield = num - carry_;
- double const total = sum_ + yield;
- carry_ = (total - sum_) - yield;
- sum_ = total;
- return *this;
- }
- TEST(DefaultRandomTest, RandomDistributionIntIsUniform) {
- engine::random::Random generator{};
- kahan_summation sum{};
- size_t const iters = 2000000;
- for (size_t i = 0; i < iters; ++i) {
- // All values from 0 - 100 are allowable
- sum += generator.inclusive(0, 100);
- }
- // Expected result is (0+99)/2 +/- 0.1%
- EXPECT_THAT(double(sum) / iters, DoubleNear(50, 0.05));
- }
- TEST(DefaultRandomTest, RandomDistributionDblIsUniform) {
- engine::random::Random generator{};
- kahan_summation sum{};
- size_t const iters = 2000000;
- for (size_t i = 0; i < iters; ++i) {
- // All values from 0 - 99 are allowable
- sum += generator.exclusive(0.0, 100.0);
- }
- // Expected result is [0.0, 100.0) +/- 0.1%
- EXPECT_THAT(double(sum) / iters, DoubleNear(50, 0.05));
- }
- TEST(DefaultRandomTest, InclusiveRangeMayIncludeValue) {
- engine::random::Random generator{};
- EXPECT_THAT(generator.inclusive(1.0, 1.0), DoubleNear(1.0, 1E-6));
- }
- TEST(DefaultRandomTest, RandomDistributionDblInclIsUniform) {
- engine::random::Random generator{};
- kahan_summation sum{};
- size_t const iters = 2000000;
- for (size_t i = 0; i < iters; ++i) {
- // All values in [0.0, 100.0] are allowable
- sum += generator.inclusive(0.0, 100.0);
- }
- // Expected result is (0+100)/2 +/- 0.1%
- EXPECT_THAT(double(sum) / iters, DoubleNear(50, 0.05));
- }
|