[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 19:07:18 PDT 2024


================
@@ -30,28 +30,45 @@ template <unsigned long long __a,
           unsigned long long __c,
           unsigned long long __m,
           unsigned long long _Mp,
-          bool _MightOverflow = (__a != 0 && __m != 0 && __m - 1 > (_Mp - __c) / __a),
-          bool _OverflowOK    = ((__m & (__m - 1)) == 0ull),                  // m = 2^n
-          bool _SchrageOK     = (__a != 0 && __m != 0 && __m % __a <= __m / __a)> // r <= q
+          bool _HasOverflow = (__a != 0ull && (__m & (__m - 1ull)) != 0ull),      // a != 0, m != 0, m != 2^n
+          bool _Full        = (!_HasOverflow || __m - 1ull <= (_Mp - __c) / __a), // (a * x + c) % m works
+          bool _Part        = (!_HasOverflow || __m - 1ull <= _Mp / __a),         // (a * x) % m works
+          bool _Schrage     = (_HasOverflow && __m % __a <= __m / __a)>               // r <= q
 struct __lce_alg_picker {
-  static_assert(!_MightOverflow || _OverflowOK || _SchrageOK,
-                "The current values of a, c, and m cannot generate a number "
-                "within bounds of linear_congruential_engine.");
+  static _LIBCPP_CONSTEXPR const int __mode = _Full ? 0 : _Part ? 1 : _Schrage ? 2 : 3;
 
-  static _LIBCPP_CONSTEXPR const bool __use_schrage = _MightOverflow && !_OverflowOK && _SchrageOK;
+#ifdef _LIBCPP_HAS_NO_INT128
+  static_assert(_Mp != (unsigned long long)(~0) || _Full || _Part || _Schrage,
+                "The current values for a, c, and m are not currently supported on platforms without __int128");
+#endif
 };
 
 template <unsigned long long __a,
           unsigned long long __c,
           unsigned long long __m,
           unsigned long long _Mp,
-          bool _UseSchrage = __lce_alg_picker<__a, __c, __m, _Mp>::__use_schrage>
+          int _Mode = __lce_alg_picker<__a, __c, __m, _Mp>::__mode>
 struct __lce_ta;
 
 // 64
 
+#ifndef _LIBCPP_HAS_NO_INT128
----------------
LRFLEW wrote:

Ok, I got the multilib tests working. I went and commented out the `#ifndef _LIBCPP_HAS_NO_INT128` in assign.pass.cpp, and this is how `llvm_lit` reported the first compile error with clang++:

```
# | In file included from llvm-project/libcxx/test/std/numerics/rand/rand.eng/rand.eng.lcong/assign.pass.cpp:16:
# | In file included from llvm-project/build/include/c++/v1/random:1686:
# | In file included from llvm-project/build/include/c++/v1/__random/default_random_engine.h:13:
# | llvm-project/build/include/c++/v1/__random/linear_congruential_engine.h:52:17: error: static assertion failed due to requirement '18446744073709551615ULL != (unsigned long long)(~0) || false || false || false': The current values for a, c, and m are not currently supported on platforms without __int128
# |    52 |   static_assert(_Mp != (unsigned long long)(~0) || _Full || _Part || _Schrage,
# |       |                 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# | llvm-project/build/include/c++/v1/__random/linear_congruential_engine.h:61:34: note: in instantiation of template class 'std::__lce_alg_picker<18446744073709551613, 0, 18446744073709551615, 18446744073709551615>' requested here
# |    61 |           __lce_alg_type _Mode = __lce_alg_picker<__a, __c, __m, _Mp>::__mode>
# |       |                                  ^
# | llvm-project/build/include/c++/v1/__random/linear_congruential_engine.h:285:44: note: in instantiation of default argument for '__lce_ta<18446744073709551613ULL, 0ULL, 18446744073709551615ULL, 18446744073709551615ULL>' required here
# |   285 |     return __x_ = static_cast<result_type>(__lce_ta<__a, __c, __m, _Mp>::next(__x_));
# |       |                                            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
# | llvm-project/libcxx/test/std/numerics/rand/rand.eng/rand.eng.lcong/assign.pass.cpp:30:11: note: in instantiation of member function 'std::linear_congruential_engine<unsigned long long, 18446744073709551613, 0, 18446744073709551615>::operator()' requested here
# |    30 |     (void)e1();
# |       |           ^
# | llvm-project/libcxx/test/std/numerics/rand/rand.eng/rand.eng.lcong/assign.pass.cpp:71:3: note: in instantiation of function template specialization 'test1<unsigned long long, 18446744073709551613ULL, 0ULL, 18446744073709551615ULL>' requested here
# |    71 |   test1<T, M - 2, 0, M>();
# |       |   ^
# | llvm-project/libcxx/test/std/numerics/rand/rand.eng/rand.eng.lcong/assign.pass.cpp:90:5: note: in instantiation of function template specialization 'test_ext<unsigned long long>' requested here
# |    90 |     test_ext<unsigned long long>();
# |       |     ^
```

https://github.com/llvm/llvm-project/pull/81583


More information about the libcxx-commits mailing list