<random>: Replace inaccurate _XLgamma() with UCRT lgamma()
#5891
+13
−59
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Fixes #5577.
Overview
To implement
<random>'spoisson_distributionandbinomial_distribution, the STL had a "log gamma" function for historical reasons. As the UCRT provides C99lgamma(), we should just call that. This will increase accuracy and reduce the amount of code we need to maintain.Accuracy
I used Boost.Math's test coverage to compare UCRT
lgamma()to STL_XLgamma(). Boost.Math's own implementation is the best (0 failures). UCRTlgamma()has minor accuracy issues (7 failures). STL_XLgamma()was extremely inaccurate (648 failures); @statementreply observed on Discord that this inaccuracy was around +/- 10^-9, which is millions of ULPs fordouble. Woof. 🐶Click to expand the details of my hacked-up accuracy testing:
I used
boost_1_89_0\libs\math\test\test_gamma.cppandtest_gamma.hpp. At the end oftest_gamma.cpp, to make it header-only, I followed the docs and added:In
test_gamma.hppI added:Results:
Changes
<random>Don't declare
_XLgamma()anymore. (The all-important_CRTIMP2_PUREwill be preserved on the definitions.)Call
_STD lgamma(), which is similarly overloaded forfloat/double/long double.xlgamma.cppTransfer
_CRTIMP2_PUREto the definitions, which will keep them dllexported. This replaces a silly pattern of "declare with_CRTIMP2_PUREbut define without".Mark them as preserved for bincompat.
Replace their guts with calls to
_STD lgamma(), which preserves the interface but improves the behavior.