1eb1c5037SNikolas Klauser //===----------------------------------------------------------------------===// 2eb1c5037SNikolas Klauser // 3eb1c5037SNikolas Klauser // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4eb1c5037SNikolas Klauser // See https://llvm.org/LICENSE.txt for license information. 5eb1c5037SNikolas Klauser // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6eb1c5037SNikolas Klauser // 7eb1c5037SNikolas Klauser //===----------------------------------------------------------------------===// 8eb1c5037SNikolas Klauser // 9eb1c5037SNikolas Klauser // REQUIRES: long_tests 10eb1c5037SNikolas Klauser 11eb1c5037SNikolas Klauser // <random> 12eb1c5037SNikolas Klauser 13eb1c5037SNikolas Klauser // template<class IntType = int> 14eb1c5037SNikolas Klauser // class geometric_distribution 15eb1c5037SNikolas Klauser 16eb1c5037SNikolas Klauser // template<class _URNG> result_type operator()(_URNG& g); 17eb1c5037SNikolas Klauser 18*09e3a360SLouis Dionne #include <random> 19eb1c5037SNikolas Klauser #include <cassert> 20*09e3a360SLouis Dionne #include <cmath> 210a4aa8a1SNikolas Klauser #include <cstdint> 220a4aa8a1SNikolas Klauser #include <numeric> 230a4aa8a1SNikolas Klauser #include <vector> 24eb1c5037SNikolas Klauser 25eb1c5037SNikolas Klauser #include "test_macros.h" 26eb1c5037SNikolas Klauser 27eb1c5037SNikolas Klauser template <class T> 2807e984bcSLouis Dionne T sqr(T x) { 29eb1c5037SNikolas Klauser return x * x; 30eb1c5037SNikolas Klauser } 31eb1c5037SNikolas Klauser 32eb1c5037SNikolas Klauser void test_small_inputs() { 33eb1c5037SNikolas Klauser std::mt19937 engine; 34eb1c5037SNikolas Klauser std::geometric_distribution<std::int16_t> distribution(5.45361e-311); 35eb1c5037SNikolas Klauser typedef std::geometric_distribution<std::int16_t>::result_type result_type; 36eb1c5037SNikolas Klauser for (int i = 0; i < 1000; ++i) { 37eb1c5037SNikolas Klauser volatile result_type res = distribution(engine); 38eb1c5037SNikolas Klauser ((void)res); 39eb1c5037SNikolas Klauser } 40eb1c5037SNikolas Klauser } 41eb1c5037SNikolas Klauser 4207e984bcSLouis Dionne template <class T> 4307e984bcSLouis Dionne void test1() { 4407e984bcSLouis Dionne typedef std::geometric_distribution<T> D; 45eb1c5037SNikolas Klauser typedef std::mt19937 G; 46eb1c5037SNikolas Klauser G g; 47eb1c5037SNikolas Klauser D d(.03125); 48eb1c5037SNikolas Klauser const int N = 1000000; 4907e984bcSLouis Dionne std::vector<typename D::result_type> u; 50eb1c5037SNikolas Klauser for (int i = 0; i < N; ++i) 51eb1c5037SNikolas Klauser { 5207e984bcSLouis Dionne typename D::result_type v = d(g); 53eb1c5037SNikolas Klauser assert(d.min() <= v && v <= d.max()); 54eb1c5037SNikolas Klauser u.push_back(v); 55eb1c5037SNikolas Klauser } 56eb1c5037SNikolas Klauser double mean = std::accumulate(u.begin(), u.end(), 57eb1c5037SNikolas Klauser double(0)) / u.size(); 58eb1c5037SNikolas Klauser double var = 0; 59eb1c5037SNikolas Klauser double skew = 0; 60eb1c5037SNikolas Klauser double kurtosis = 0; 61eb1c5037SNikolas Klauser for (unsigned i = 0; i < u.size(); ++i) 62eb1c5037SNikolas Klauser { 63eb1c5037SNikolas Klauser double dbl = (u[i] - mean); 64eb1c5037SNikolas Klauser double d2 = sqr(dbl); 65eb1c5037SNikolas Klauser var += d2; 66eb1c5037SNikolas Klauser skew += dbl * d2; 67eb1c5037SNikolas Klauser kurtosis += d2 * d2; 68eb1c5037SNikolas Klauser } 69eb1c5037SNikolas Klauser var /= u.size(); 70eb1c5037SNikolas Klauser double dev = std::sqrt(var); 71eb1c5037SNikolas Klauser skew /= u.size() * dev * var; 72eb1c5037SNikolas Klauser kurtosis /= u.size() * var * var; 73eb1c5037SNikolas Klauser kurtosis -= 3; 74eb1c5037SNikolas Klauser double x_mean = (1 - d.p()) / d.p(); 75eb1c5037SNikolas Klauser double x_var = x_mean / d.p(); 76eb1c5037SNikolas Klauser double x_skew = (2 - d.p()) / std::sqrt((1 - d.p())); 77eb1c5037SNikolas Klauser double x_kurtosis = 6 + sqr(d.p()) / (1 - d.p()); 78eb1c5037SNikolas Klauser assert(std::abs((mean - x_mean) / x_mean) < 0.01); 79eb1c5037SNikolas Klauser assert(std::abs((var - x_var) / x_var) < 0.01); 80eb1c5037SNikolas Klauser assert(std::abs((skew - x_skew) / x_skew) < 0.01); 8176aa042dSMatt Stephanson assert(std::abs((kurtosis - x_kurtosis) / x_kurtosis) < 0.03); 82eb1c5037SNikolas Klauser } 83eb1c5037SNikolas Klauser 8407e984bcSLouis Dionne template <class T> 8507e984bcSLouis Dionne void test2() { 8607e984bcSLouis Dionne typedef std::geometric_distribution<T> D; 87eb1c5037SNikolas Klauser typedef std::mt19937 G; 88eb1c5037SNikolas Klauser G g; 89eb1c5037SNikolas Klauser D d(0.05); 90eb1c5037SNikolas Klauser const int N = 1000000; 9107e984bcSLouis Dionne std::vector<typename D::result_type> u; 92eb1c5037SNikolas Klauser for (int i = 0; i < N; ++i) 93eb1c5037SNikolas Klauser { 9407e984bcSLouis Dionne typename D::result_type v = d(g); 95eb1c5037SNikolas Klauser assert(d.min() <= v && v <= d.max()); 96eb1c5037SNikolas Klauser u.push_back(v); 97eb1c5037SNikolas Klauser } 98eb1c5037SNikolas Klauser double mean = std::accumulate(u.begin(), u.end(), 99eb1c5037SNikolas Klauser double(0)) / u.size(); 100eb1c5037SNikolas Klauser double var = 0; 101eb1c5037SNikolas Klauser double skew = 0; 102eb1c5037SNikolas Klauser double kurtosis = 0; 103eb1c5037SNikolas Klauser for (unsigned i = 0; i < u.size(); ++i) 104eb1c5037SNikolas Klauser { 105eb1c5037SNikolas Klauser double dbl = (u[i] - mean); 106eb1c5037SNikolas Klauser double d2 = sqr(dbl); 107eb1c5037SNikolas Klauser var += d2; 108eb1c5037SNikolas Klauser skew += dbl * d2; 109eb1c5037SNikolas Klauser kurtosis += d2 * d2; 110eb1c5037SNikolas Klauser } 111eb1c5037SNikolas Klauser var /= u.size(); 112eb1c5037SNikolas Klauser double dev = std::sqrt(var); 113eb1c5037SNikolas Klauser skew /= u.size() * dev * var; 114eb1c5037SNikolas Klauser kurtosis /= u.size() * var * var; 115eb1c5037SNikolas Klauser kurtosis -= 3; 116eb1c5037SNikolas Klauser double x_mean = (1 - d.p()) / d.p(); 117eb1c5037SNikolas Klauser double x_var = x_mean / d.p(); 118eb1c5037SNikolas Klauser double x_skew = (2 - d.p()) / std::sqrt((1 - d.p())); 119eb1c5037SNikolas Klauser double x_kurtosis = 6 + sqr(d.p()) / (1 - d.p()); 120eb1c5037SNikolas Klauser assert(std::abs((mean - x_mean) / x_mean) < 0.01); 121eb1c5037SNikolas Klauser assert(std::abs((var - x_var) / x_var) < 0.01); 122eb1c5037SNikolas Klauser assert(std::abs((skew - x_skew) / x_skew) < 0.01); 123eb1c5037SNikolas Klauser assert(std::abs((kurtosis - x_kurtosis) / x_kurtosis) < 0.03); 124eb1c5037SNikolas Klauser } 125eb1c5037SNikolas Klauser 12607e984bcSLouis Dionne template <class T> 12707e984bcSLouis Dionne void test3() { 12807e984bcSLouis Dionne typedef std::geometric_distribution<T> D; 129eb1c5037SNikolas Klauser typedef std::minstd_rand G; 130eb1c5037SNikolas Klauser G g; 131eb1c5037SNikolas Klauser D d(.25); 132eb1c5037SNikolas Klauser const int N = 1000000; 13307e984bcSLouis Dionne std::vector<typename D::result_type> u; 134eb1c5037SNikolas Klauser for (int i = 0; i < N; ++i) 135eb1c5037SNikolas Klauser { 13607e984bcSLouis Dionne typename D::result_type v = d(g); 137eb1c5037SNikolas Klauser assert(d.min() <= v && v <= d.max()); 138eb1c5037SNikolas Klauser u.push_back(v); 139eb1c5037SNikolas Klauser } 140eb1c5037SNikolas Klauser double mean = std::accumulate(u.begin(), u.end(), 141eb1c5037SNikolas Klauser double(0)) / u.size(); 142eb1c5037SNikolas Klauser double var = 0; 143eb1c5037SNikolas Klauser double skew = 0; 144eb1c5037SNikolas Klauser double kurtosis = 0; 145eb1c5037SNikolas Klauser for (unsigned i = 0; i < u.size(); ++i) 146eb1c5037SNikolas Klauser { 147eb1c5037SNikolas Klauser double dbl = (u[i] - mean); 148eb1c5037SNikolas Klauser double d2 = sqr(dbl); 149eb1c5037SNikolas Klauser var += d2; 150eb1c5037SNikolas Klauser skew += dbl * d2; 151eb1c5037SNikolas Klauser kurtosis += d2 * d2; 152eb1c5037SNikolas Klauser } 153eb1c5037SNikolas Klauser var /= u.size(); 154eb1c5037SNikolas Klauser double dev = std::sqrt(var); 155eb1c5037SNikolas Klauser skew /= u.size() * dev * var; 156eb1c5037SNikolas Klauser kurtosis /= u.size() * var * var; 157eb1c5037SNikolas Klauser kurtosis -= 3; 158eb1c5037SNikolas Klauser double x_mean = (1 - d.p()) / d.p(); 159eb1c5037SNikolas Klauser double x_var = x_mean / d.p(); 160eb1c5037SNikolas Klauser double x_skew = (2 - d.p()) / std::sqrt((1 - d.p())); 161eb1c5037SNikolas Klauser double x_kurtosis = 6 + sqr(d.p()) / (1 - d.p()); 162eb1c5037SNikolas Klauser assert(std::abs((mean - x_mean) / x_mean) < 0.01); 163eb1c5037SNikolas Klauser assert(std::abs((var - x_var) / x_var) < 0.01); 164eb1c5037SNikolas Klauser assert(std::abs((skew - x_skew) / x_skew) < 0.01); 16576aa042dSMatt Stephanson assert(std::abs((kurtosis - x_kurtosis) / x_kurtosis) < 0.03); 166eb1c5037SNikolas Klauser } 167eb1c5037SNikolas Klauser 16807e984bcSLouis Dionne template <class T> 16907e984bcSLouis Dionne void test4() { 17007e984bcSLouis Dionne typedef std::geometric_distribution<T> D; 171eb1c5037SNikolas Klauser typedef std::mt19937 G; 172eb1c5037SNikolas Klauser G g; 173eb1c5037SNikolas Klauser D d(0.5); 174eb1c5037SNikolas Klauser const int N = 1000000; 17507e984bcSLouis Dionne std::vector<typename D::result_type> u; 176eb1c5037SNikolas Klauser for (int i = 0; i < N; ++i) 177eb1c5037SNikolas Klauser { 17807e984bcSLouis Dionne typename D::result_type v = d(g); 179eb1c5037SNikolas Klauser assert(d.min() <= v && v <= d.max()); 180eb1c5037SNikolas Klauser u.push_back(v); 181eb1c5037SNikolas Klauser } 182eb1c5037SNikolas Klauser double mean = std::accumulate(u.begin(), u.end(), 183eb1c5037SNikolas Klauser double(0)) / u.size(); 184eb1c5037SNikolas Klauser double var = 0; 185eb1c5037SNikolas Klauser double skew = 0; 186eb1c5037SNikolas Klauser double kurtosis = 0; 187eb1c5037SNikolas Klauser for (unsigned i = 0; i < u.size(); ++i) 188eb1c5037SNikolas Klauser { 189eb1c5037SNikolas Klauser double dbl = (u[i] - mean); 190eb1c5037SNikolas Klauser double d2 = sqr(dbl); 191eb1c5037SNikolas Klauser var += d2; 192eb1c5037SNikolas Klauser skew += dbl * d2; 193eb1c5037SNikolas Klauser kurtosis += d2 * d2; 194eb1c5037SNikolas Klauser } 195eb1c5037SNikolas Klauser var /= u.size(); 196eb1c5037SNikolas Klauser double dev = std::sqrt(var); 197eb1c5037SNikolas Klauser skew /= u.size() * dev * var; 198eb1c5037SNikolas Klauser kurtosis /= u.size() * var * var; 199eb1c5037SNikolas Klauser kurtosis -= 3; 200eb1c5037SNikolas Klauser double x_mean = (1 - d.p()) / d.p(); 201eb1c5037SNikolas Klauser double x_var = x_mean / d.p(); 202eb1c5037SNikolas Klauser double x_skew = (2 - d.p()) / std::sqrt((1 - d.p())); 203eb1c5037SNikolas Klauser double x_kurtosis = 6 + sqr(d.p()) / (1 - d.p()); 204eb1c5037SNikolas Klauser assert(std::abs((mean - x_mean) / x_mean) < 0.01); 205eb1c5037SNikolas Klauser assert(std::abs((var - x_var) / x_var) < 0.01); 206eb1c5037SNikolas Klauser assert(std::abs((skew - x_skew) / x_skew) < 0.01); 20776aa042dSMatt Stephanson assert(std::abs((kurtosis - x_kurtosis) / x_kurtosis) < 0.03); 208eb1c5037SNikolas Klauser } 209eb1c5037SNikolas Klauser 21007e984bcSLouis Dionne template <class T> 21107e984bcSLouis Dionne void test5() { 21207e984bcSLouis Dionne typedef std::geometric_distribution<T> D; 213eb1c5037SNikolas Klauser typedef std::mt19937 G; 214eb1c5037SNikolas Klauser G g; 215eb1c5037SNikolas Klauser D d(0.75); 216eb1c5037SNikolas Klauser const int N = 1000000; 21707e984bcSLouis Dionne std::vector<typename D::result_type> u; 218eb1c5037SNikolas Klauser for (int i = 0; i < N; ++i) 219eb1c5037SNikolas Klauser { 22007e984bcSLouis Dionne typename D::result_type v = d(g); 221eb1c5037SNikolas Klauser assert(d.min() <= v && v <= d.max()); 222eb1c5037SNikolas Klauser u.push_back(v); 223eb1c5037SNikolas Klauser } 224eb1c5037SNikolas Klauser double mean = std::accumulate(u.begin(), u.end(), 225eb1c5037SNikolas Klauser double(0)) / u.size(); 226eb1c5037SNikolas Klauser double var = 0; 227eb1c5037SNikolas Klauser double skew = 0; 228eb1c5037SNikolas Klauser double kurtosis = 0; 229eb1c5037SNikolas Klauser for (unsigned i = 0; i < u.size(); ++i) 230eb1c5037SNikolas Klauser { 231eb1c5037SNikolas Klauser double dbl = (u[i] - mean); 232eb1c5037SNikolas Klauser double d2 = sqr(dbl); 233eb1c5037SNikolas Klauser var += d2; 234eb1c5037SNikolas Klauser skew += dbl * d2; 235eb1c5037SNikolas Klauser kurtosis += d2 * d2; 236eb1c5037SNikolas Klauser } 237eb1c5037SNikolas Klauser var /= u.size(); 238eb1c5037SNikolas Klauser double dev = std::sqrt(var); 239eb1c5037SNikolas Klauser skew /= u.size() * dev * var; 240eb1c5037SNikolas Klauser kurtosis /= u.size() * var * var; 241eb1c5037SNikolas Klauser kurtosis -= 3; 242eb1c5037SNikolas Klauser double x_mean = (1 - d.p()) / d.p(); 243eb1c5037SNikolas Klauser double x_var = x_mean / d.p(); 244eb1c5037SNikolas Klauser double x_skew = (2 - d.p()) / std::sqrt((1 - d.p())); 245eb1c5037SNikolas Klauser double x_kurtosis = 6 + sqr(d.p()) / (1 - d.p()); 246eb1c5037SNikolas Klauser assert(std::abs((mean - x_mean) / x_mean) < 0.01); 247eb1c5037SNikolas Klauser assert(std::abs((var - x_var) / x_var) < 0.01); 248eb1c5037SNikolas Klauser assert(std::abs((skew - x_skew) / x_skew) < 0.01); 24976aa042dSMatt Stephanson assert(std::abs((kurtosis - x_kurtosis) / x_kurtosis) < 0.03); 250eb1c5037SNikolas Klauser } 251eb1c5037SNikolas Klauser 25207e984bcSLouis Dionne template <class T> 25307e984bcSLouis Dionne void test6() { 25407e984bcSLouis Dionne typedef std::geometric_distribution<T> D; 255eb1c5037SNikolas Klauser typedef std::mt19937 G; 256eb1c5037SNikolas Klauser G g; 257eb1c5037SNikolas Klauser D d(0.96875); 258eb1c5037SNikolas Klauser const int N = 1000000; 25907e984bcSLouis Dionne std::vector<typename D::result_type> u; 260eb1c5037SNikolas Klauser for (int i = 0; i < N; ++i) 261eb1c5037SNikolas Klauser { 26207e984bcSLouis Dionne typename D::result_type v = d(g); 263eb1c5037SNikolas Klauser assert(d.min() <= v && v <= d.max()); 264eb1c5037SNikolas Klauser u.push_back(v); 265eb1c5037SNikolas Klauser } 266eb1c5037SNikolas Klauser double mean = std::accumulate(u.begin(), u.end(), 267eb1c5037SNikolas Klauser double(0)) / u.size(); 268eb1c5037SNikolas Klauser double var = 0; 269eb1c5037SNikolas Klauser double skew = 0; 270eb1c5037SNikolas Klauser double kurtosis = 0; 271eb1c5037SNikolas Klauser for (unsigned i = 0; i < u.size(); ++i) 272eb1c5037SNikolas Klauser { 273eb1c5037SNikolas Klauser double dbl = (u[i] - mean); 274eb1c5037SNikolas Klauser double d2 = sqr(dbl); 275eb1c5037SNikolas Klauser var += d2; 276eb1c5037SNikolas Klauser skew += dbl * d2; 277eb1c5037SNikolas Klauser kurtosis += d2 * d2; 278eb1c5037SNikolas Klauser } 279eb1c5037SNikolas Klauser var /= u.size(); 280eb1c5037SNikolas Klauser double dev = std::sqrt(var); 281eb1c5037SNikolas Klauser skew /= u.size() * dev * var; 282eb1c5037SNikolas Klauser kurtosis /= u.size() * var * var; 283eb1c5037SNikolas Klauser kurtosis -= 3; 284eb1c5037SNikolas Klauser double x_mean = (1 - d.p()) / d.p(); 285eb1c5037SNikolas Klauser double x_var = x_mean / d.p(); 286eb1c5037SNikolas Klauser double x_skew = (2 - d.p()) / std::sqrt((1 - d.p())); 287eb1c5037SNikolas Klauser double x_kurtosis = 6 + sqr(d.p()) / (1 - d.p()); 28876aa042dSMatt Stephanson assert(std::abs((mean - x_mean) / x_mean) < 0.02); 28976aa042dSMatt Stephanson assert(std::abs((var - x_var) / x_var) < 0.02); 290eb1c5037SNikolas Klauser assert(std::abs((skew - x_skew) / x_skew) < 0.01); 291eb1c5037SNikolas Klauser assert(std::abs((kurtosis - x_kurtosis) / x_kurtosis) < 0.02); 292eb1c5037SNikolas Klauser } 293eb1c5037SNikolas Klauser 29407e984bcSLouis Dionne template <class T> 29507e984bcSLouis Dionne void tests() { 29607e984bcSLouis Dionne test1<T>(); 29707e984bcSLouis Dionne test2<T>(); 29807e984bcSLouis Dionne test3<T>(); 29907e984bcSLouis Dionne test4<T>(); 30007e984bcSLouis Dionne test5<T>(); 30107e984bcSLouis Dionne test6<T>(); 30207e984bcSLouis Dionne } 30307e984bcSLouis Dionne 30407e984bcSLouis Dionne int main(int, char**) { 305eb1c5037SNikolas Klauser test_small_inputs(); 306eb1c5037SNikolas Klauser 30707e984bcSLouis Dionne tests<short>(); 30807e984bcSLouis Dionne tests<int>(); 30907e984bcSLouis Dionne tests<long>(); 31007e984bcSLouis Dionne tests<long long>(); 31107e984bcSLouis Dionne 31207e984bcSLouis Dionne tests<unsigned short>(); 31307e984bcSLouis Dionne tests<unsigned int>(); 31407e984bcSLouis Dionne tests<unsigned long>(); 31507e984bcSLouis Dionne tests<unsigned long long>(); 31607e984bcSLouis Dionne 31707e984bcSLouis Dionne #if defined(_LIBCPP_VERSION) // extension 31807e984bcSLouis Dionne // TODO: std::geometric_distribution currently doesn't work reliably with small types. 31907e984bcSLouis Dionne // tests<int8_t>(); 32007e984bcSLouis Dionne // tests<uint8_t>(); 32107e984bcSLouis Dionne #if !defined(TEST_HAS_NO_INT128) 32207e984bcSLouis Dionne tests<__int128_t>(); 32307e984bcSLouis Dionne tests<__uint128_t>(); 32407e984bcSLouis Dionne #endif 32507e984bcSLouis Dionne #endif 32607e984bcSLouis Dionne 327eb1c5037SNikolas Klauser return 0; 328eb1c5037SNikolas Klauser } 329