329 lines · cpp
1//===----------------------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// REQUIRES: long_tests10 11// <random>12 13// template<class IntType = int>14// class geometric_distribution15 16// template<class _URNG> result_type operator()(_URNG& g);17 18#include <random>19#include <cassert>20#include <cmath>21#include <cstdint>22#include <numeric>23#include <vector>24 25#include "test_macros.h"26 27template <class T>28T sqr(T x) {29 return x * x;30}31 32void test_small_inputs() {33 std::mt19937 engine;34 std::geometric_distribution<std::int16_t> distribution(5.45361e-311);35 typedef std::geometric_distribution<std::int16_t>::result_type result_type;36 for (int i = 0; i < 1000; ++i) {37 volatile result_type res = distribution(engine);38 ((void)res);39 }40}41 42template <class T>43void test1() {44 typedef std::geometric_distribution<T> D;45 typedef std::mt19937 G;46 G g;47 D d(.03125);48 const int N = 1000000;49 std::vector<typename D::result_type> u;50 for (int i = 0; i < N; ++i)51 {52 typename D::result_type v = d(g);53 assert(d.min() <= v && v <= d.max());54 u.push_back(v);55 }56 double mean = std::accumulate(u.begin(), u.end(),57 double(0)) / u.size();58 double var = 0;59 double skew = 0;60 double kurtosis = 0;61 for (unsigned i = 0; i < u.size(); ++i)62 {63 double dbl = (u[i] - mean);64 double d2 = sqr(dbl);65 var += d2;66 skew += dbl * d2;67 kurtosis += d2 * d2;68 }69 var /= u.size();70 double dev = std::sqrt(var);71 skew /= u.size() * dev * var;72 kurtosis /= u.size() * var * var;73 kurtosis -= 3;74 double x_mean = (1 - d.p()) / d.p();75 double x_var = x_mean / d.p();76 double x_skew = (2 - d.p()) / std::sqrt((1 - d.p()));77 double x_kurtosis = 6 + sqr(d.p()) / (1 - d.p());78 assert(std::abs((mean - x_mean) / x_mean) < 0.01);79 assert(std::abs((var - x_var) / x_var) < 0.01);80 assert(std::abs((skew - x_skew) / x_skew) < 0.01);81 assert(std::abs((kurtosis - x_kurtosis) / x_kurtosis) < 0.03);82}83 84template <class T>85void test2() {86 typedef std::geometric_distribution<T> D;87 typedef std::mt19937 G;88 G g;89 D d(0.05);90 const int N = 1000000;91 std::vector<typename D::result_type> u;92 for (int i = 0; i < N; ++i)93 {94 typename D::result_type v = d(g);95 assert(d.min() <= v && v <= d.max());96 u.push_back(v);97 }98 double mean = std::accumulate(u.begin(), u.end(),99 double(0)) / u.size();100 double var = 0;101 double skew = 0;102 double kurtosis = 0;103 for (unsigned i = 0; i < u.size(); ++i)104 {105 double dbl = (u[i] - mean);106 double d2 = sqr(dbl);107 var += d2;108 skew += dbl * d2;109 kurtosis += d2 * d2;110 }111 var /= u.size();112 double dev = std::sqrt(var);113 skew /= u.size() * dev * var;114 kurtosis /= u.size() * var * var;115 kurtosis -= 3;116 double x_mean = (1 - d.p()) / d.p();117 double x_var = x_mean / d.p();118 double x_skew = (2 - d.p()) / std::sqrt((1 - d.p()));119 double x_kurtosis = 6 + sqr(d.p()) / (1 - d.p());120 assert(std::abs((mean - x_mean) / x_mean) < 0.01);121 assert(std::abs((var - x_var) / x_var) < 0.01);122 assert(std::abs((skew - x_skew) / x_skew) < 0.01);123 assert(std::abs((kurtosis - x_kurtosis) / x_kurtosis) < 0.03);124}125 126template <class T>127void test3() {128 typedef std::geometric_distribution<T> D;129 typedef std::minstd_rand G;130 G g;131 D d(.25);132 const int N = 1000000;133 std::vector<typename D::result_type> u;134 for (int i = 0; i < N; ++i)135 {136 typename D::result_type v = d(g);137 assert(d.min() <= v && v <= d.max());138 u.push_back(v);139 }140 double mean = std::accumulate(u.begin(), u.end(),141 double(0)) / u.size();142 double var = 0;143 double skew = 0;144 double kurtosis = 0;145 for (unsigned i = 0; i < u.size(); ++i)146 {147 double dbl = (u[i] - mean);148 double d2 = sqr(dbl);149 var += d2;150 skew += dbl * d2;151 kurtosis += d2 * d2;152 }153 var /= u.size();154 double dev = std::sqrt(var);155 skew /= u.size() * dev * var;156 kurtosis /= u.size() * var * var;157 kurtosis -= 3;158 double x_mean = (1 - d.p()) / d.p();159 double x_var = x_mean / d.p();160 double x_skew = (2 - d.p()) / std::sqrt((1 - d.p()));161 double x_kurtosis = 6 + sqr(d.p()) / (1 - d.p());162 assert(std::abs((mean - x_mean) / x_mean) < 0.01);163 assert(std::abs((var - x_var) / x_var) < 0.01);164 assert(std::abs((skew - x_skew) / x_skew) < 0.01);165 assert(std::abs((kurtosis - x_kurtosis) / x_kurtosis) < 0.03);166}167 168template <class T>169void test4() {170 typedef std::geometric_distribution<T> D;171 typedef std::mt19937 G;172 G g;173 D d(0.5);174 const int N = 1000000;175 std::vector<typename D::result_type> u;176 for (int i = 0; i < N; ++i)177 {178 typename D::result_type v = d(g);179 assert(d.min() <= v && v <= d.max());180 u.push_back(v);181 }182 double mean = std::accumulate(u.begin(), u.end(),183 double(0)) / u.size();184 double var = 0;185 double skew = 0;186 double kurtosis = 0;187 for (unsigned i = 0; i < u.size(); ++i)188 {189 double dbl = (u[i] - mean);190 double d2 = sqr(dbl);191 var += d2;192 skew += dbl * d2;193 kurtosis += d2 * d2;194 }195 var /= u.size();196 double dev = std::sqrt(var);197 skew /= u.size() * dev * var;198 kurtosis /= u.size() * var * var;199 kurtosis -= 3;200 double x_mean = (1 - d.p()) / d.p();201 double x_var = x_mean / d.p();202 double x_skew = (2 - d.p()) / std::sqrt((1 - d.p()));203 double x_kurtosis = 6 + sqr(d.p()) / (1 - d.p());204 assert(std::abs((mean - x_mean) / x_mean) < 0.01);205 assert(std::abs((var - x_var) / x_var) < 0.01);206 assert(std::abs((skew - x_skew) / x_skew) < 0.01);207 assert(std::abs((kurtosis - x_kurtosis) / x_kurtosis) < 0.03);208}209 210template <class T>211void test5() {212 typedef std::geometric_distribution<T> D;213 typedef std::mt19937 G;214 G g;215 D d(0.75);216 const int N = 1000000;217 std::vector<typename D::result_type> u;218 for (int i = 0; i < N; ++i)219 {220 typename D::result_type v = d(g);221 assert(d.min() <= v && v <= d.max());222 u.push_back(v);223 }224 double mean = std::accumulate(u.begin(), u.end(),225 double(0)) / u.size();226 double var = 0;227 double skew = 0;228 double kurtosis = 0;229 for (unsigned i = 0; i < u.size(); ++i)230 {231 double dbl = (u[i] - mean);232 double d2 = sqr(dbl);233 var += d2;234 skew += dbl * d2;235 kurtosis += d2 * d2;236 }237 var /= u.size();238 double dev = std::sqrt(var);239 skew /= u.size() * dev * var;240 kurtosis /= u.size() * var * var;241 kurtosis -= 3;242 double x_mean = (1 - d.p()) / d.p();243 double x_var = x_mean / d.p();244 double x_skew = (2 - d.p()) / std::sqrt((1 - d.p()));245 double x_kurtosis = 6 + sqr(d.p()) / (1 - d.p());246 assert(std::abs((mean - x_mean) / x_mean) < 0.01);247 assert(std::abs((var - x_var) / x_var) < 0.01);248 assert(std::abs((skew - x_skew) / x_skew) < 0.01);249 assert(std::abs((kurtosis - x_kurtosis) / x_kurtosis) < 0.03);250}251 252template <class T>253void test6() {254 typedef std::geometric_distribution<T> D;255 typedef std::mt19937 G;256 G g;257 D d(0.96875);258 const int N = 1000000;259 std::vector<typename D::result_type> u;260 for (int i = 0; i < N; ++i)261 {262 typename D::result_type v = d(g);263 assert(d.min() <= v && v <= d.max());264 u.push_back(v);265 }266 double mean = std::accumulate(u.begin(), u.end(),267 double(0)) / u.size();268 double var = 0;269 double skew = 0;270 double kurtosis = 0;271 for (unsigned i = 0; i < u.size(); ++i)272 {273 double dbl = (u[i] - mean);274 double d2 = sqr(dbl);275 var += d2;276 skew += dbl * d2;277 kurtosis += d2 * d2;278 }279 var /= u.size();280 double dev = std::sqrt(var);281 skew /= u.size() * dev * var;282 kurtosis /= u.size() * var * var;283 kurtosis -= 3;284 double x_mean = (1 - d.p()) / d.p();285 double x_var = x_mean / d.p();286 double x_skew = (2 - d.p()) / std::sqrt((1 - d.p()));287 double x_kurtosis = 6 + sqr(d.p()) / (1 - d.p());288 assert(std::abs((mean - x_mean) / x_mean) < 0.02);289 assert(std::abs((var - x_var) / x_var) < 0.02);290 assert(std::abs((skew - x_skew) / x_skew) < 0.01);291 assert(std::abs((kurtosis - x_kurtosis) / x_kurtosis) < 0.02);292}293 294template <class T>295void tests() {296 test1<T>();297 test2<T>();298 test3<T>();299 test4<T>();300 test5<T>();301 test6<T>();302}303 304int main(int, char**) {305 test_small_inputs();306 307 tests<short>();308 tests<int>();309 tests<long>();310 tests<long long>();311 312 tests<unsigned short>();313 tests<unsigned int>();314 tests<unsigned long>();315 tests<unsigned long long>();316 317#if defined(_LIBCPP_VERSION) // extension318 // TODO: std::geometric_distribution currently doesn't work reliably with small types.319 // tests<int8_t>();320 // tests<uint8_t>();321#if !defined(TEST_HAS_NO_INT128)322 tests<__int128_t>();323 tests<__uint128_t>();324#endif325#endif326 327 return 0;328}329