Opened 8 years ago

Last modified 8 years ago

#10110 new Bugs

boost::random::negative_binomial_distribution unnecessary restriction to IntType for parameter k

Reported by: Maximilian Kleinert <kleinert.max@…> Owned by: No-Maintainer
Milestone: To Be Determined Component: random
Version: Boost 1.55.0 Severity: Problem
Keywords: random, negative binomial distribution Cc:

Description

Hi.

In the implementation of boost::random::negative_binomial_distribution there is an unnecessary restriction to IntType for parameter k.

A double parameter k will be casted to integer resulting in a different distribution than desired. If one compiles with -Wconversion a warning is given: warning: conversion to ‘int’ from ‘double’ may alter its value [-Wconversion] see attached example_file. This can lead to unwanted realization of a negative binomial distribution for non integer parameters k.

Further there are no assertion checks on the parameters in instantiating a boost::random::negative_binomial_distribution object. These assertions are checked during the sampling process via boost::random::gamma_distribution. There (and in general for negative binomial distribution) the parameter k must be strictly greater than zero and not as mentioned in the documentation "Requires: k >=0".

This can easily be extended by changing IntType to RealType in 5 occurrences regarding the parameter k.

Thank you, Max

P.S.: I compiled the example file with: g++ -Wconversion -o negbin_test -std=c++11 negbin_test.cpp

Attachments (4)

negbin_test.cpp (2.1 KB ) - added by Maximilian Kleinert <kleinert.max@…> 8 years ago.
Example of double to int conversion in negative_binomial_distribution
test.cpp (3.2 KB ) - added by Maximilian Kleinert <kleinert.max@…> 8 years ago.
Test paramter assertions
test.2.cpp (3.2 KB ) - added by Maximilian Kleinert <kleinert.max@…> 8 years ago.
Test paramter assertions
comparison.txt (1.4 KB ) - added by Maximilian Kleinert <kleinert.max@…> 8 years ago.
Comparison of assertion tests

Download all attachments as: .zip

Change History (10)

by Maximilian Kleinert <kleinert.max@…>, 8 years ago

Attachment: negbin_test.cpp added

Example of double to int conversion in negative_binomial_distribution

comment:1 by Steven Watanabe, 8 years ago

I'm on the fence about this. This generalization is reasonable, but it is not consistent with std::negative_binomial_distribution and the difference is subtle enough that it could result in non-obvious bugs if someone were to try replacing boost::random with std.

by Maximilian Kleinert <kleinert.max@…>, 8 years ago

Attachment: test.cpp added

Test paramter assertions

by Maximilian Kleinert <kleinert.max@…>, 8 years ago

Attachment: test.2.cpp added

Test paramter assertions

by Maximilian Kleinert <kleinert.max@…>, 8 years ago

Attachment: comparison.txt added

Comparison of assertion tests

comment:2 by Maximilian Kleinert <kleinert.max@…>, 8 years ago

Hi Steven,

thanks for your reply. I think that this implicit cast can lead to non-obvious bugs as well, since it changes the distribution in case for non integer parameter k. The standard only describes the negative binomial distribution for trials, e.g. integer parameters. So the behavior for a non integer value is unspecified by the standard. In practice, e.g. claim number modeling, real positive parameters are widely used. To avoid the implicit cast bug it would be possible to delete the constructor for non integer types. Then still no real parameters are usable (in fact they are not proper right now) but the compiler will reject it if someone tries.

Regarding the issue about the assertions. I did some tests comparing std::negative_binomial_distribution and the one from boost. Summarizing, the parameter checks are not very satisfying either, see the attached comparison.txt.

In my opinion it makes no sense that a negative_binomial_distribution with invalid parameters can be constructed and then may or may not fail during the sampling process. Especially in the case k=0 were -231 is produced which can happen if someone calculates with the (in principal) valid parameter k = 0.99.

I produced these results with g++-4.9.real (Ubuntu 4.9.1-16ubuntu6) 4.9.1 and compiled the attached example with: g++ -D_GLIBCXX_DEBUG -std=c++11 -o test test.cpp and without the _GLIBCXX_DEBUG flag.

It would be great if both implementations of the negative binomial distribution will improve.

Thank you, Max

in reply to:  2 ; comment:3 by Steven Watanabe, 8 years ago

Replying to Maximilian Kleinert <kleinert.max@…>:

The standard only describes the negative binomial distribution for trials, e.g. integer parameters. So the behavior for a non integer value is unspecified by the standard.

Not correct. The standard specifies that it takes an integer parameter. It also states that a floating point number can be converted to an integer. Therefore the behavior when passing a floating point number is specified even if it isn't useful.

comment:4 by Steven Watanabe, 8 years ago

k = 0 and p = 1 are degenerate cases which should be supported.

in reply to:  3 comment:5 by Maximilian Kleinert <kleinert.max@…>, 8 years ago

Replying to steven_watanabe:

Replying to Maximilian Kleinert <kleinert.max@…>:

The standard only describes the negative binomial distribution for trials, e.g. integer parameters. So the behavior for a non integer value is unspecified by the standard.

Not correct. The standard specifies that it takes an integer parameter. It also states that a floating point number can be converted to an integer. Therefore the behavior when passing a floating point number is specified even if it isn't useful.

Ok. So the only possibility would be to add an extra distribution, e.g. Polya distribution, which is essentially the same except that it allows a real positive parameter k?

in reply to:  4 comment:6 by Maximilian Kleinert <kleinert.max@…>, 8 years ago

Replying to steven_watanabe:

k = 0 and p = 1 are degenerate cases which should be supported.

The case p = 1 (regardless of k) is not supported by the boost version: The gamma distribution fails because the parameter beta = (1-p)/p is not greater than zero. The standard version fails if compiled with -D_GLIBCXX_DEBUG using g++.

The working draft standard (N4926) page 965 requires: 0 < p <= 1 and 0 < k.

Boost and standard version (except compiled with -D_GLIBCXX_DEBUG) return in the case p = 0 the sample -2147483648 which is not very useful.

Note: See TracTickets for help on using tickets.