Skip to content

Commit 6bfe581

Browse files
authored
Merge pull request #987 from mborland/18511
Fix for scipy issues 18506 and 18511
2 parents 0a222f6 + ba36dbe commit 6bfe581

File tree

8 files changed

+121
-66
lines changed

8 files changed

+121
-66
lines changed

doc/distributions/hypergeometric.qbk

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,11 @@
1515
typedef RealType value_type;
1616
typedef Policy policy_type;
1717
// Construct:
18-
hypergeometric_distribution(unsigned r, unsigned n, unsigned N); // r=defective/failures/success, n=trials/draws, N=total population.
18+
hypergeometric_distribution(uint64_t r, uint64_t n, uint64_t N); // r=defective/failures/success, n=trials/draws, N=total population.
1919
// Accessors:
20-
unsigned total()const;
21-
unsigned defective()const;
22-
unsigned sample_count()const;
20+
uint64_t total()const;
21+
uint64_t defective()const;
22+
uint64_t sample_count()const;
2323
};
2424

2525
typedef hypergeometric_distribution<> hypergeometric;
@@ -56,20 +56,20 @@ then we obtain basically the same graphs:
5656

5757
[h4 Member Functions]
5858

59-
hypergeometric_distribution(unsigned r, unsigned n, unsigned N);
59+
hypergeometric_distribution(uint64_t r, uint64_t n, uint64_t N);
6060

6161
Constructs a hypergeometric distribution with a population of /N/ objects,
6262
of which /r/ are defective, and from which /n/ are sampled.
6363

64-
unsigned total()const;
64+
uint64_t total()const;
6565

6666
Returns the total number of objects /N/.
6767

68-
unsigned defective()const;
68+
uint64_t defective()const;
6969

7070
Returns the number of objects /r/ in population /N/ which are defective.
7171

72-
unsigned sample_count()const;
72+
uint64_t sample_count()const;
7373

7474
Returns the number of objects /n/ which are sampled from the population /N/.
7575

@@ -87,7 +87,7 @@ and Python
8787
All the [link math_toolkit.dist_ref.nmp usual non-member accessor functions]
8888
that are generic to all distributions are supported: __usual_accessors.
8989

90-
The domain of the random variable is the unsigned integers in the range
90+
The domain of the random variable are the 64-bit unsigned integers in the range
9191
\[max(0, n + r - N), min(n, r)\]. A __domain_error is raised if the
9292
random variable is outside this range, or is not an integral value.
9393

include/boost/math/distributions/detail/hypergeometric_cdf.hpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,12 @@
1010

1111
#include <boost/math/policies/error_handling.hpp>
1212
#include <boost/math/distributions/detail/hypergeometric_pdf.hpp>
13+
#include <cstdint>
1314

1415
namespace boost{ namespace math{ namespace detail{
1516

1617
template <class T, class Policy>
17-
T hypergeometric_cdf_imp(unsigned x, unsigned r, unsigned n, unsigned N, bool invert, const Policy& pol)
18+
T hypergeometric_cdf_imp(std::uint64_t x, std::uint64_t r, std::uint64_t n, std::uint64_t N, bool invert, const Policy& pol)
1819
{
1920
#ifdef _MSC_VER
2021
# pragma warning(push)
@@ -27,7 +28,7 @@ namespace boost{ namespace math{ namespace detail{
2728
{
2829
result = hypergeometric_pdf<T>(x, r, n, N, pol);
2930
T diff = result;
30-
unsigned lower_limit = static_cast<unsigned>((std::max)(0, static_cast<int>(n + r) - static_cast<int>(N)));
31+
const auto lower_limit = static_cast<std::uint64_t>((std::max)(INT64_C(0), static_cast<std::int64_t>(n + r) - static_cast<std::int64_t>(N)));
3132
while(diff > (invert ? T(1) : result) * tools::epsilon<T>())
3233
{
3334
diff = T(x) * T((N + x) - n - r) * diff / (T(1 + n - x) * T(1 + r - x));
@@ -43,7 +44,7 @@ namespace boost{ namespace math{ namespace detail{
4344
else
4445
{
4546
invert = !invert;
46-
unsigned upper_limit = (std::min)(r, n);
47+
const auto upper_limit = (std::min)(r, n);
4748
if(x != upper_limit)
4849
{
4950
++x;
@@ -69,7 +70,7 @@ namespace boost{ namespace math{ namespace detail{
6970
}
7071

7172
template <class T, class Policy>
72-
inline T hypergeometric_cdf(unsigned x, unsigned r, unsigned n, unsigned N, bool invert, const Policy&)
73+
inline T hypergeometric_cdf(std::uint64_t x, std::uint64_t r, std::uint64_t n, std::uint64_t N, bool invert, const Policy&)
7374
{
7475
BOOST_FPU_EXCEPTION_GUARD
7576
typedef typename tools::promote_args<T>::type result_type;

include/boost/math/distributions/detail/hypergeometric_pdf.hpp

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
#include <boost/math/special_functions/pow.hpp>
1616
#include <boost/math/special_functions/prime.hpp>
1717
#include <boost/math/policies/error_handling.hpp>
18+
#include <algorithm>
19+
#include <cstdint>
1820

1921
#ifdef BOOST_MATH_INSTRUMENT
2022
#include <typeinfo>
@@ -40,7 +42,7 @@ template <class T>
4042
struct sort_functor
4143
{
4244
sort_functor(const T* exponents) : m_exponents(exponents){}
43-
bool operator()(int i, int j)
45+
bool operator()(std::size_t i, std::size_t j)
4446
{
4547
return m_exponents[i] > m_exponents[j];
4648
}
@@ -49,7 +51,7 @@ struct sort_functor
4951
};
5052

5153
template <class T, class Lanczos, class Policy>
52-
T hypergeometric_pdf_lanczos_imp(T /*dummy*/, unsigned x, unsigned r, unsigned n, unsigned N, const Lanczos&, const Policy&)
54+
T hypergeometric_pdf_lanczos_imp(T /*dummy*/, std::uint64_t x, std::uint64_t r, std::uint64_t n, std::uint64_t N, const Lanczos&, const Policy&)
5355
{
5456
BOOST_MATH_STD_USING
5557

@@ -137,7 +139,7 @@ T hypergeometric_pdf_lanczos_imp(T /*dummy*/, unsigned x, unsigned r, unsigned n
137139
//
138140
// Combine equal powers:
139141
//
140-
int j = 8;
142+
std::size_t j = 8;
141143
while(exponents[sorted_indexes[j]] == 0) --j;
142144
while(j)
143145
{
@@ -184,7 +186,7 @@ T hypergeometric_pdf_lanczos_imp(T /*dummy*/, unsigned x, unsigned r, unsigned n
184186
result = pow(bases[sorted_indexes[0]] * exp(static_cast<T>(base_e_factors[sorted_indexes[0]])), exponents[sorted_indexes[0]]);
185187
}
186188
BOOST_MATH_INSTRUMENT_VARIABLE(result);
187-
for(unsigned i = 1; (i < 9) && (exponents[sorted_indexes[i]] > 0); ++i)
189+
for(std::size_t i = 1; (i < 9) && (exponents[sorted_indexes[i]] > 0); ++i)
188190
{
189191
BOOST_FPU_EXCEPTION_GUARD
190192
if(result < tools::min_value<T>())
@@ -215,7 +217,7 @@ T hypergeometric_pdf_lanczos_imp(T /*dummy*/, unsigned x, unsigned r, unsigned n
215217
}
216218

217219
template <class T, class Policy>
218-
T hypergeometric_pdf_lanczos_imp(T /*dummy*/, unsigned x, unsigned r, unsigned n, unsigned N, const boost::math::lanczos::undefined_lanczos&, const Policy& pol)
220+
T hypergeometric_pdf_lanczos_imp(T /*dummy*/, std::uint64_t x, std::uint64_t r, std::uint64_t n, std::uint64_t N, const boost::math::lanczos::undefined_lanczos&, const Policy& pol)
219221
{
220222
BOOST_MATH_STD_USING
221223
return exp(
@@ -277,12 +279,12 @@ struct hypergeometric_pdf_prime_loop_result_entry
277279

278280
struct hypergeometric_pdf_prime_loop_data
279281
{
280-
const unsigned x;
281-
const unsigned r;
282-
const unsigned n;
283-
const unsigned N;
284-
unsigned prime_index;
285-
unsigned current_prime;
282+
const std::uint64_t x;
283+
const std::uint64_t r;
284+
const std::uint64_t n;
285+
const std::uint64_t N;
286+
std::size_t prime_index;
287+
std::uint64_t current_prime;
286288
};
287289

288290
#ifdef _MSC_VER
@@ -294,8 +296,8 @@ T hypergeometric_pdf_prime_loop_imp(hypergeometric_pdf_prime_loop_data& data, hy
294296
{
295297
while(data.current_prime <= data.N)
296298
{
297-
unsigned base = data.current_prime;
298-
int prime_powers = 0;
299+
std::uint64_t base = data.current_prime;
300+
std::int64_t prime_powers = 0;
299301
while(base <= data.N)
300302
{
301303
prime_powers += data.n / base;
@@ -381,15 +383,15 @@ T hypergeometric_pdf_prime_loop_imp(hypergeometric_pdf_prime_loop_data& data, hy
381383
}
382384

383385
template <class T, class Policy>
384-
inline T hypergeometric_pdf_prime_imp(unsigned x, unsigned r, unsigned n, unsigned N, const Policy&)
386+
inline T hypergeometric_pdf_prime_imp(std::uint64_t x, std::uint64_t r, std::uint64_t n, std::uint64_t N, const Policy&)
385387
{
386388
hypergeometric_pdf_prime_loop_result_entry<T> result = { 1, 0 };
387389
hypergeometric_pdf_prime_loop_data data = { x, r, n, N, 0, prime(0) };
388390
return hypergeometric_pdf_prime_loop_imp<T>(data, result);
389391
}
390392

391393
template <class T, class Policy>
392-
T hypergeometric_pdf_factorial_imp(unsigned x, unsigned r, unsigned n, unsigned N, const Policy&)
394+
T hypergeometric_pdf_factorial_imp(std::uint64_t x, std::uint64_t r, std::uint64_t n, std::uint64_t N, const Policy&)
393395
{
394396
BOOST_MATH_STD_USING
395397
BOOST_MATH_ASSERT(N <= boost::math::max_factorial<T>::value);
@@ -406,8 +408,8 @@ T hypergeometric_pdf_factorial_imp(unsigned x, unsigned r, unsigned n, unsigned
406408
boost::math::unchecked_factorial<T>(r - x),
407409
boost::math::unchecked_factorial<T>(N - n - r + x)
408410
};
409-
int i = 0;
410-
int j = 0;
411+
std::size_t i = 0;
412+
std::size_t j = 0;
411413
while((i < 3) || (j < 5))
412414
{
413415
while((j < 5) && ((result >= 1) || (i >= 3)))
@@ -427,7 +429,7 @@ T hypergeometric_pdf_factorial_imp(unsigned x, unsigned r, unsigned n, unsigned
427429

428430
template <class T, class Policy>
429431
inline typename tools::promote_args<T>::type
430-
hypergeometric_pdf(unsigned x, unsigned r, unsigned n, unsigned N, const Policy&)
432+
hypergeometric_pdf(std::uint64_t x, std::uint64_t r, std::uint64_t n, std::uint64_t N, const Policy&)
431433
{
432434
BOOST_FPU_EXCEPTION_GUARD
433435
typedef typename tools::promote_args<T>::type result_type;

include/boost/math/distributions/hypergeometric.hpp

Lines changed: 35 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include <boost/math/distributions/detail/hypergeometric_cdf.hpp>
1717
#include <boost/math/distributions/detail/hypergeometric_quantile.hpp>
1818
#include <boost/math/special_functions/fpclassify.hpp>
19+
#include <cstdint>
1920

2021
namespace boost { namespace math {
2122

@@ -26,25 +27,25 @@ namespace boost { namespace math {
2627
typedef RealType value_type;
2728
typedef Policy policy_type;
2829

29-
hypergeometric_distribution(unsigned r, unsigned n, unsigned N) // Constructor. r=defective/failures/success, n=trials/draws, N=total population.
30+
hypergeometric_distribution(std::uint64_t r, std::uint64_t n, std::uint64_t N) // Constructor. r=defective/failures/success, n=trials/draws, N=total population.
3031
: m_n(n), m_N(N), m_r(r)
3132
{
3233
static const char* function = "boost::math::hypergeometric_distribution<%1%>::hypergeometric_distribution";
3334
RealType ret;
3435
check_params(function, &ret);
3536
}
3637
// Accessor functions.
37-
unsigned total()const
38+
std::uint64_t total() const
3839
{
3940
return m_N;
4041
}
4142

42-
unsigned defective()const // successes/failures/events
43+
std::uint64_t defective() const // successes/failures/events
4344
{
4445
return m_r;
4546
}
4647

47-
unsigned sample_count()const
48+
std::uint64_t sample_count()const
4849
{
4950
return m_n;
5051
}
@@ -65,9 +66,9 @@ namespace boost { namespace math {
6566
}
6667
return true;
6768
}
68-
bool check_x(unsigned x, const char* function, RealType* result)const
69+
bool check_x(std::uint64_t x, const char* function, RealType* result)const
6970
{
70-
if(x < static_cast<unsigned>((std::max)(0, static_cast<int>(m_n + m_r) - static_cast<int>(m_N))))
71+
if(x < static_cast<std::uint64_t>((std::max)(INT64_C(0), static_cast<std::int64_t>(m_n + m_r) - static_cast<std::int64_t>(m_N))))
7172
{
7273
*result = boost::math::policies::raise_domain_error<RealType>(
7374
function, "Random variable out of range: must be > 0 and > m + r - N but got %1%", static_cast<RealType>(x), Policy());
@@ -84,40 +85,40 @@ namespace boost { namespace math {
8485

8586
private:
8687
// Data members:
87-
unsigned m_n; // number of items picked or drawn.
88-
unsigned m_N; // number of "total" items.
89-
unsigned m_r; // number of "defective/successes/failures/events items.
88+
std::uint64_t m_n; // number of items picked or drawn.
89+
std::uint64_t m_N; // number of "total" items.
90+
std::uint64_t m_r; // number of "defective/successes/failures/events items.
9091

9192
}; // class hypergeometric_distribution
9293

9394
typedef hypergeometric_distribution<double> hypergeometric;
9495

9596
template <class RealType, class Policy>
96-
inline const std::pair<unsigned, unsigned> range(const hypergeometric_distribution<RealType, Policy>& dist)
97+
inline const std::pair<std::uint64_t, std::uint64_t> range(const hypergeometric_distribution<RealType, Policy>& dist)
9798
{ // Range of permissible values for random variable x.
9899
#ifdef _MSC_VER
99100
# pragma warning(push)
100101
# pragma warning(disable:4267)
101102
#endif
102-
unsigned r = dist.defective();
103-
unsigned n = dist.sample_count();
104-
unsigned N = dist.total();
105-
unsigned l = static_cast<unsigned>((std::max)(0, static_cast<int>(n + r) - static_cast<int>(N)));
106-
unsigned u = (std::min)(r, n);
107-
return std::pair<unsigned, unsigned>(l, u);
103+
const auto r = dist.defective();
104+
const auto n = dist.sample_count();
105+
const auto N = dist.total();
106+
const auto l = static_cast<std::uint64_t>((std::max)(INT64_C(0), static_cast<std::int64_t>(n + r) - static_cast<std::int64_t>(N)));
107+
const auto u = (std::min)(r, n);
108+
return std::make_pair(l, u);
108109
#ifdef _MSC_VER
109110
# pragma warning(pop)
110111
#endif
111112
}
112113

113114
template <class RealType, class Policy>
114-
inline const std::pair<unsigned, unsigned> support(const hypergeometric_distribution<RealType, Policy>& d)
115+
inline const std::pair<std::uint64_t, std::uint64_t> support(const hypergeometric_distribution<RealType, Policy>& d)
115116
{
116117
return range(d);
117118
}
118119

119120
template <class RealType, class Policy>
120-
inline RealType pdf(const hypergeometric_distribution<RealType, Policy>& dist, const unsigned& x)
121+
inline RealType pdf(const hypergeometric_distribution<RealType, Policy>& dist, const std::uint64_t& x)
121122
{
122123
static const char* function = "boost::math::pdf(const hypergeometric_distribution<%1%>&, const %1%&)";
123124
RealType result = 0;
@@ -136,7 +137,7 @@ namespace boost { namespace math {
136137
BOOST_MATH_STD_USING
137138
static const char* function = "boost::math::pdf(const hypergeometric_distribution<%1%>&, const %1%&)";
138139
RealType r = static_cast<RealType>(x);
139-
unsigned u = itrunc(r, typename policies::normalise<Policy, policies::rounding_error<policies::ignore_error> >::type());
140+
auto u = static_cast<std::uint64_t>(lltrunc(r, typename policies::normalise<Policy, policies::rounding_error<policies::ignore_error> >::type()));
140141
if(u != r)
141142
{
142143
return boost::math::policies::raise_domain_error<RealType>(
@@ -146,7 +147,7 @@ namespace boost { namespace math {
146147
}
147148

148149
template <class RealType, class Policy>
149-
inline RealType cdf(const hypergeometric_distribution<RealType, Policy>& dist, const unsigned& x)
150+
inline RealType cdf(const hypergeometric_distribution<RealType, Policy>& dist, const std::uint64_t& x)
150151
{
151152
static const char* function = "boost::math::cdf(const hypergeometric_distribution<%1%>&, const %1%&)";
152153
RealType result = 0;
@@ -165,7 +166,7 @@ namespace boost { namespace math {
165166
BOOST_MATH_STD_USING
166167
static const char* function = "boost::math::cdf(const hypergeometric_distribution<%1%>&, const %1%&)";
167168
RealType r = static_cast<RealType>(x);
168-
unsigned u = itrunc(r, typename policies::normalise<Policy, policies::rounding_error<policies::ignore_error> >::type());
169+
auto u = static_cast<std::uint64_t>(lltrunc(r, typename policies::normalise<Policy, policies::rounding_error<policies::ignore_error> >::type()));
169170
if(u != r)
170171
{
171172
return boost::math::policies::raise_domain_error<RealType>(
@@ -175,7 +176,7 @@ namespace boost { namespace math {
175176
}
176177

177178
template <class RealType, class Policy>
178-
inline RealType cdf(const complemented2_type<hypergeometric_distribution<RealType, Policy>, unsigned>& c)
179+
inline RealType cdf(const complemented2_type<hypergeometric_distribution<RealType, Policy>, std::uint64_t>& c)
179180
{
180181
static const char* function = "boost::math::cdf(const hypergeometric_distribution<%1%>&, const %1%&)";
181182
RealType result = 0;
@@ -194,7 +195,7 @@ namespace boost { namespace math {
194195
BOOST_MATH_STD_USING
195196
static const char* function = "boost::math::cdf(const hypergeometric_distribution<%1%>&, const %1%&)";
196197
RealType r = static_cast<RealType>(c.param);
197-
unsigned u = itrunc(r, typename policies::normalise<Policy, policies::rounding_error<policies::ignore_error> >::type());
198+
auto u = static_cast<std::uint64_t>(lltrunc(r, typename policies::normalise<Policy, policies::rounding_error<policies::ignore_error> >::type()));
198199
if(u != r)
199200
{
200201
return boost::math::policies::raise_domain_error<RealType>(
@@ -208,11 +209,14 @@ namespace boost { namespace math {
208209
{
209210
BOOST_MATH_STD_USING // for ADL of std functions
210211

211-
// Checking function argument
212-
RealType result = 0;
212+
// Checking function argument
213+
RealType result = 0;
213214
const char* function = "boost::math::quantile(const hypergeometric_distribution<%1%>&, %1%)";
214-
if (false == dist.check_params(function, &result)) return result;
215-
if(false == detail::check_probability(function, p, &result, Policy())) return result;
215+
if (false == dist.check_params(function, &result))
216+
return result;
217+
218+
if(false == detail::check_probability(function, p, &result, Policy()))
219+
return result;
216220

217221
return static_cast<RealType>(detail::hypergeometric_quantile(p, RealType(1 - p), dist.defective(), dist.sample_count(), dist.total(), Policy()));
218222
} // quantile
@@ -225,8 +229,10 @@ namespace boost { namespace math {
225229
// Checking function argument
226230
RealType result = 0;
227231
const char* function = "quantile(const complemented2_type<hypergeometric_distribution<%1%>, %1%>&)";
228-
if (false == c.dist.check_params(function, &result)) return result;
229-
if(false == detail::check_probability(function, c.param, &result, Policy())) return result;
232+
if (false == c.dist.check_params(function, &result))
233+
return result;
234+
if (false == detail::check_probability(function, c.param, &result, Policy()))
235+
return result;
230236

231237
return static_cast<RealType>(detail::hypergeometric_quantile(RealType(1 - c.param), c.param, c.dist.defective(), c.dist.sample_count(), c.dist.total(), Policy()));
232238
} // quantile

0 commit comments

Comments
 (0)