[libcxx-commits] [libcxx] linear_congruential_engine: add using more precision to prevent overflow (PR #81583)
via libcxx-commits
libcxx-commits at lists.llvm.org
Sat Apr 13 16:59:25 PDT 2024
================
@@ -80,21 +97,40 @@ struct __lce_ta<__a, 0, __m, (unsigned long long)(~0), true> {
};
template <unsigned long long __a, unsigned long long __c, unsigned long long __m>
-struct __lce_ta<__a, __c, __m, (unsigned long long)(~0), false> {
+struct __lce_ta<__a, __c, __m, (unsigned long long)(~0), 1> {
+ typedef unsigned long long result_type;
+ _LIBCPP_HIDE_FROM_ABI static result_type next(result_type __x) {
+ // Use (((a*x) % m) + c) % m
+ __x = (__a * __x) % __m;
+ __x += __c - (__x >= __m - __c) * __m;
+ return __x;
+ }
+};
+
+template <unsigned long long __a, unsigned long long __c, unsigned long long __m>
+struct __lce_ta<__a, __c, __m, (unsigned long long)(~0), 0> {
typedef unsigned long long result_type;
_LIBCPP_HIDE_FROM_ABI static result_type next(result_type __x) { return (__a * __x + __c) % __m; }
};
template <unsigned long long __a, unsigned long long __c>
-struct __lce_ta<__a, __c, 0, (unsigned long long)(~0), false> {
+struct __lce_ta<__a, __c, 0ull, (unsigned long long)(~0), 0> {
typedef unsigned long long result_type;
_LIBCPP_HIDE_FROM_ABI static result_type next(result_type __x) { return __a * __x + __c; }
};
// 32
+template <unsigned long long __a, unsigned long long __c, unsigned long long __m>
+struct __lce_ta<__a, __c, __m, unsigned(~0), 3> {
+ typedef unsigned result_type;
+ _LIBCPP_HIDE_FROM_ABI static result_type next(result_type __x) {
+ return static_cast<result_type>(__lce_ta<__a, __c, __m, (unsigned long long)(~0)>::next(__x));
----------------
LRFLEW wrote:
I was thinking this looked weird, but this is what was there before. I agree it looks wrong (even if it technically isn't), though. My issue with this change is that it can't *quite* be applied universally. Even if I changed this in all of the specializations of `__lce_ta`, the definition of `linear_congruential_engine::_Mp` would still have that issue, as it's currently defined as `result_type(~0)`.
Personally, I'd rather change this line to `~(unsigned long long)(0)`, as I think it's clearer what the intent is, and is less prone to mistakes from using the wrong suffix.
https://github.com/llvm/llvm-project/pull/81583
More information about the libcxx-commits
mailing list