gcc/libstdc++-v3/testsuite/util/testsuite_random.h

216 lines
4.6 KiB
C
Raw Normal View History

// -*- C++ -*-
2024-01-03 12:19:35 +01:00
// Copyright (C) 2011-2024 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the terms
// of the GNU General Public License as published by the Free Software
// Foundation; either version 3, or (at your option) any later
// version.
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
// You should have received a copy of the GNU General Public License along
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
/**
* @file testsuite_random.h
*/
#ifndef _GLIBCXX_TESTSUITE_RANDOM_H
#define _GLIBCXX_TESTSUITE_RANDOM_H
#include <cmath>
#include <initializer_list>
#include <system_error>
#include <testsuite_hooks.h>
namespace __gnu_test
{
// Adapted for libstdc++ from GNU gsl-1.14/randist/test.c
// Copyright (C) 1996, 1997, 1998, 1999, 2000, 2007, 2010
// James Theiler, Brian Gough
template<unsigned long BINS = 100,
unsigned long N = 100000,
typename Distribution, typename Pdf>
void
testDiscreteDist(Distribution& f, Pdf pdf)
{
double count[BINS], p[BINS];
for (unsigned long i = 0; i < BINS; i++)
count[i] = 0;
for (unsigned long i = 0; i < N; i++)
{
auto r = f();
if (r >= 0 && (unsigned long)r < BINS)
count[r]++;
}
for (unsigned long i = 0; i < BINS; i++)
p[i] = pdf(i);
for (unsigned long i = 0; i < BINS; i++)
{
bool status_i;
double d = std::abs(count[i] - N * p[i]);
if (p[i] != 0)
{
double s = d / std::sqrt(N * p[i]);
status_i = (s > 5) && (d > 1);
}
else
status_i = (count[i] != 0);
VERIFY( !status_i );
}
}
inline double
bernoulli_pdf(int k, double p)
{
if (k == 0)
return 1 - p;
else if (k == 1)
return p;
else
return 0.0;
}
libstdc++: Stop using _GLIBCXX_USE_C99_MATH_TR1 in <cmath> Similar to the three commits r14-908, r14-909 and r14-910, the _GLIBCXX_USE_C99_MATH_TR1 macro is misleading when it is also used for <cmath>, not only for <tr1/cmath> headers. It is also wrong, because the configure checks for TR1 use -std=c++98 and a target might define the C99 features for C++11 but not for C++98. Add separate configure checks for the <math.h> functions using -std=c++11 for the checks. Use the new macro defined by those checks in the C++11-specific parts of <cmath>, and in <complex>, <random> etc. The check that defines _GLIBCXX_NO_C99_ROUNDING_FUNCS is only needed for the C++11 <cmath> checks, so remove that from GLIBCXX_CHECK_C99_TR1 and only do it for GLIBCXX_ENABLE_C99. libstdc++-v3/ChangeLog: * acinclude.m4 (GLIBCXX_ENABLE_C99): Add checks for C99 math functions and define _GLIBCXX_USE_C99_MATH_FUNCS. Move checks for C99 rounding functions to here. (GLIBCXX_CHECK_C99_TR1): Remove checks for C99 rounding functions from here. * config.h.in: Regenerate. * configure: Regenerate. * include/bits/random.h: Use _GLIBCXX_USE_C99_MATH_FUNCS instead of _GLIBCXX_USE_C99_MATH_TR1. * include/bits/random.tcc: Likewise. * include/c_compatibility/math.h: Likewise. * include/c_global/cmath: Likewise. * include/ext/random: Likewise. * include/ext/random.tcc: Likewise. * include/std/complex: Likewise. * testsuite/20_util/from_chars/4.cc: Likewise. * testsuite/20_util/from_chars/8.cc: Likewise. * testsuite/26_numerics/complex/proj.cc: Likewise. * testsuite/26_numerics/headers/cmath/60401.cc: Likewise. * testsuite/26_numerics/headers/cmath/types_std_c++0x.cc: Likewise. * testsuite/lib/libstdc++.exp (check_v3_target_cstdint): Likewise. * testsuite/util/testsuite_random.h: Likewise.
2023-05-13 00:57:15 +01:00
#ifdef _GLIBCXX_USE_C99_MATH_FUNCS
inline double
binomial_pdf(int k, int n, double p)
{
if (k < 0 || k > n)
return 0.0;
else
{
double q;
if (p == 0.0)
q = (k == 0) ? 1.0 : 0.0;
else if (p == 1.0)
q = (k == n) ? 1.0 : 0.0;
else
{
double ln_Cnk = (std::lgamma(n + 1.0) - std::lgamma(k + 1.0)
- std::lgamma(n - k + 1.0));
q = ln_Cnk + k * std::log(p) + (n - k) * std::log1p(-p);
q = std::exp(q);
}
return q;
}
}
#endif
inline double
discrete_pdf(int k, std::initializer_list<double> wl)
{
if (!wl.size())
{
static std::initializer_list<double> one = { 1.0 };
wl = one;
}
if (k < 0 || (std::size_t)k >= wl.size())
return 0.0;
else
{
double sum = 0.0;
for (auto it = wl.begin(); it != wl.end(); ++it)
sum += *it;
return wl.begin()[k] / sum;
}
}
inline double
geometric_pdf(int k, double p)
{
if (k < 0)
return 0.0;
else if (k == 0)
return p;
else
return p * std::pow(1 - p, k);
}
libstdc++: Stop using _GLIBCXX_USE_C99_MATH_TR1 in <cmath> Similar to the three commits r14-908, r14-909 and r14-910, the _GLIBCXX_USE_C99_MATH_TR1 macro is misleading when it is also used for <cmath>, not only for <tr1/cmath> headers. It is also wrong, because the configure checks for TR1 use -std=c++98 and a target might define the C99 features for C++11 but not for C++98. Add separate configure checks for the <math.h> functions using -std=c++11 for the checks. Use the new macro defined by those checks in the C++11-specific parts of <cmath>, and in <complex>, <random> etc. The check that defines _GLIBCXX_NO_C99_ROUNDING_FUNCS is only needed for the C++11 <cmath> checks, so remove that from GLIBCXX_CHECK_C99_TR1 and only do it for GLIBCXX_ENABLE_C99. libstdc++-v3/ChangeLog: * acinclude.m4 (GLIBCXX_ENABLE_C99): Add checks for C99 math functions and define _GLIBCXX_USE_C99_MATH_FUNCS. Move checks for C99 rounding functions to here. (GLIBCXX_CHECK_C99_TR1): Remove checks for C99 rounding functions from here. * config.h.in: Regenerate. * configure: Regenerate. * include/bits/random.h: Use _GLIBCXX_USE_C99_MATH_FUNCS instead of _GLIBCXX_USE_C99_MATH_TR1. * include/bits/random.tcc: Likewise. * include/c_compatibility/math.h: Likewise. * include/c_global/cmath: Likewise. * include/ext/random: Likewise. * include/ext/random.tcc: Likewise. * include/std/complex: Likewise. * testsuite/20_util/from_chars/4.cc: Likewise. * testsuite/20_util/from_chars/8.cc: Likewise. * testsuite/26_numerics/complex/proj.cc: Likewise. * testsuite/26_numerics/headers/cmath/60401.cc: Likewise. * testsuite/26_numerics/headers/cmath/types_std_c++0x.cc: Likewise. * testsuite/lib/libstdc++.exp (check_v3_target_cstdint): Likewise. * testsuite/util/testsuite_random.h: Likewise.
2023-05-13 00:57:15 +01:00
#ifdef _GLIBCXX_USE_C99_MATH_FUNCS
inline double
negative_binomial_pdf(int k, int n, double p)
{
if (k < 0)
return 0.0;
else
{
double f = std::lgamma(k + (double)n);
double a = std::lgamma(n);
double b = std::lgamma(k + 1.0);
return std::exp(f - a - b) * std::pow(p, n) * std::pow(1 - p, k);
}
}
inline double
poisson_pdf(int k, double mu)
{
if (k < 0)
return 0.0;
else
{
double lf = std::lgamma(k + 1.0);
return std::exp(std::log(mu) * k - lf - mu);
}
}
#endif
inline double
uniform_int_pdf(int k, int a, int b)
{
if (k < 0 || k < a || k > b)
return 0.0;
else
return 1.0 / (b - a + 1.0);
}
libstdc++: Stop using _GLIBCXX_USE_C99_MATH_TR1 in <cmath> Similar to the three commits r14-908, r14-909 and r14-910, the _GLIBCXX_USE_C99_MATH_TR1 macro is misleading when it is also used for <cmath>, not only for <tr1/cmath> headers. It is also wrong, because the configure checks for TR1 use -std=c++98 and a target might define the C99 features for C++11 but not for C++98. Add separate configure checks for the <math.h> functions using -std=c++11 for the checks. Use the new macro defined by those checks in the C++11-specific parts of <cmath>, and in <complex>, <random> etc. The check that defines _GLIBCXX_NO_C99_ROUNDING_FUNCS is only needed for the C++11 <cmath> checks, so remove that from GLIBCXX_CHECK_C99_TR1 and only do it for GLIBCXX_ENABLE_C99. libstdc++-v3/ChangeLog: * acinclude.m4 (GLIBCXX_ENABLE_C99): Add checks for C99 math functions and define _GLIBCXX_USE_C99_MATH_FUNCS. Move checks for C99 rounding functions to here. (GLIBCXX_CHECK_C99_TR1): Remove checks for C99 rounding functions from here. * config.h.in: Regenerate. * configure: Regenerate. * include/bits/random.h: Use _GLIBCXX_USE_C99_MATH_FUNCS instead of _GLIBCXX_USE_C99_MATH_TR1. * include/bits/random.tcc: Likewise. * include/c_compatibility/math.h: Likewise. * include/c_global/cmath: Likewise. * include/ext/random: Likewise. * include/ext/random.tcc: Likewise. * include/std/complex: Likewise. * testsuite/20_util/from_chars/4.cc: Likewise. * testsuite/20_util/from_chars/8.cc: Likewise. * testsuite/26_numerics/complex/proj.cc: Likewise. * testsuite/26_numerics/headers/cmath/60401.cc: Likewise. * testsuite/26_numerics/headers/cmath/types_std_c++0x.cc: Likewise. * testsuite/lib/libstdc++.exp (check_v3_target_cstdint): Likewise. * testsuite/util/testsuite_random.h: Likewise.
2023-05-13 00:57:15 +01:00
#ifdef _GLIBCXX_USE_C99_MATH_FUNCS
inline double
lbincoef(int n, int k)
{
return std::lgamma(double(1 + n))
- std::lgamma(double(1 + k))
- std::lgamma(double(1 + n - k));
}
inline double
hypergeometric_pdf(int k, int N, int K, int n)
{
if (k < 0 || k < std::max(0, n - (N - K)) || k > std::min(K, n))
return 0.0;
else
return lbincoef(K, k) + lbincoef(N - K, n - k) - lbincoef(N, n);
}
#endif
libstdc++: Add PRNG fallback to std::random_device This makes std::random_device usable on VxWorks when running on older x86 hardware. Since the r10-728 fix for PR libstdc++/85494 the library will use the new code unconditionally on x86, but the cpuid checks for RDSEED and RDRAND can fail at runtime, depending on the hardware where the code is executing. If the OS does not provide /dev/urandom then this means the std::random_device constructor always fails. In previous releases if /dev/urandom is unavailable then std::mt19937 was used unconditionally. This patch adds a fallback for the case where the runtime cpuid checks for x86 hardware instructions fail, and no /dev/urandom is available. When this happens a std::linear_congruential_engine object will be used, with a seed based on hashing the engine's address and the current time. Distinct std::random_device objects will use different seeds, unless an object is created and destroyed and a new object created at the same memory location within the clock tick. This is not great, but is better than always throwing from the constructor, and better than always using std::mt19937 with the same seed (as GCC 9 and earlier do). libstdc++-v3/ChangeLog: * src/c++11/random.cc (USE_LCG): Define when a pseudo-random fallback is needed. [USE_LCG] (bad_seed, construct_lcg_at, destroy_lcg_at, __lcg): New helper functions and callback. (random_device::_M_init): Add 'prng' and 'all' enumerators. Replace switch with fallthrough with a series of 'if' statements. [USE_LCG]: Construct an lcg_type engine and use __lcg when cpuid checks fail. (random_device::_M_init_pretr1) [USE_MT19937]: Accept "prng" token. (random_device::_M_getval): Check for callback unconditionally and always pass _M_file pointer. * testsuite/26_numerics/random/random_device/85494.cc: Remove effective-target check. Use new random_device_available helper. * testsuite/26_numerics/random/random_device/94087.cc: Likewise. * testsuite/26_numerics/random/random_device/cons/default-cow.cc: Remove effective-target check. * testsuite/26_numerics/random/random_device/cons/default.cc: Likewise. * testsuite/26_numerics/random/random_device/cons/token.cc: Use new random_device_available helper. Test "prng" token. * testsuite/util/testsuite_random.h (random_device_available): New helper function.
2021-03-26 18:39:49 +00:00
// Check whether TOKEN can construct a std::random_device successfully.
inline bool
random_device_available(const std::string& token) noexcept
{
try {
std::random_device dev(token);
return true;
} catch (const std::system_error& /* See PR libstdc++/105081 */) {
libstdc++: Add PRNG fallback to std::random_device This makes std::random_device usable on VxWorks when running on older x86 hardware. Since the r10-728 fix for PR libstdc++/85494 the library will use the new code unconditionally on x86, but the cpuid checks for RDSEED and RDRAND can fail at runtime, depending on the hardware where the code is executing. If the OS does not provide /dev/urandom then this means the std::random_device constructor always fails. In previous releases if /dev/urandom is unavailable then std::mt19937 was used unconditionally. This patch adds a fallback for the case where the runtime cpuid checks for x86 hardware instructions fail, and no /dev/urandom is available. When this happens a std::linear_congruential_engine object will be used, with a seed based on hashing the engine's address and the current time. Distinct std::random_device objects will use different seeds, unless an object is created and destroyed and a new object created at the same memory location within the clock tick. This is not great, but is better than always throwing from the constructor, and better than always using std::mt19937 with the same seed (as GCC 9 and earlier do). libstdc++-v3/ChangeLog: * src/c++11/random.cc (USE_LCG): Define when a pseudo-random fallback is needed. [USE_LCG] (bad_seed, construct_lcg_at, destroy_lcg_at, __lcg): New helper functions and callback. (random_device::_M_init): Add 'prng' and 'all' enumerators. Replace switch with fallthrough with a series of 'if' statements. [USE_LCG]: Construct an lcg_type engine and use __lcg when cpuid checks fail. (random_device::_M_init_pretr1) [USE_MT19937]: Accept "prng" token. (random_device::_M_getval): Check for callback unconditionally and always pass _M_file pointer. * testsuite/26_numerics/random/random_device/85494.cc: Remove effective-target check. Use new random_device_available helper. * testsuite/26_numerics/random/random_device/94087.cc: Likewise. * testsuite/26_numerics/random/random_device/cons/default-cow.cc: Remove effective-target check. * testsuite/26_numerics/random/random_device/cons/default.cc: Likewise. * testsuite/26_numerics/random/random_device/cons/token.cc: Use new random_device_available helper. Test "prng" token. * testsuite/util/testsuite_random.h (random_device_available): New helper function.
2021-03-26 18:39:49 +00:00
return false;
}
}
} // namespace __gnu_test
#endif // #ifndef _GLIBCXX_TESTSUITE_RANDOM_H