xref: /aosp_15_r20/external/eigen/test/random_without_cast_overflow.h (revision bf2c37156dfe67e5dfebd6d394bad8b2ab5804d4)
1*bf2c3715SXin Li // This file is part of Eigen, a lightweight C++ template library
2*bf2c3715SXin Li // for linear algebra.
3*bf2c3715SXin Li //
4*bf2c3715SXin Li // Copyright (C) 2020 C. Antonio Sanchez <[email protected]>
5*bf2c3715SXin Li //
6*bf2c3715SXin Li // This Source Code Form is subject to the terms of the Mozilla
7*bf2c3715SXin Li // Public License v. 2.0. If a copy of the MPL was not distributed
8*bf2c3715SXin Li // with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
9*bf2c3715SXin Li 
10*bf2c3715SXin Li // Utilities for generating random numbers without overflows, which might
11*bf2c3715SXin Li // otherwise result in undefined behavior.
12*bf2c3715SXin Li 
13*bf2c3715SXin Li namespace Eigen {
14*bf2c3715SXin Li namespace internal {
15*bf2c3715SXin Li 
16*bf2c3715SXin Li // Default implementation assuming SrcScalar fits into TgtScalar.
17*bf2c3715SXin Li template <typename SrcScalar, typename TgtScalar, typename EnableIf = void>
18*bf2c3715SXin Li struct random_without_cast_overflow {
valuerandom_without_cast_overflow19*bf2c3715SXin Li   static SrcScalar value() { return internal::random<SrcScalar>(); }
20*bf2c3715SXin Li };
21*bf2c3715SXin Li 
22*bf2c3715SXin Li // Signed to unsigned integer widening cast.
23*bf2c3715SXin Li template <typename SrcScalar, typename TgtScalar>
24*bf2c3715SXin Li struct random_without_cast_overflow<
25*bf2c3715SXin Li     SrcScalar, TgtScalar,
26*bf2c3715SXin Li     typename internal::enable_if<NumTraits<SrcScalar>::IsInteger && NumTraits<TgtScalar>::IsInteger &&
27*bf2c3715SXin Li                                  !NumTraits<TgtScalar>::IsSigned &&
28*bf2c3715SXin Li                                  (std::numeric_limits<SrcScalar>::digits < std::numeric_limits<TgtScalar>::digits ||
29*bf2c3715SXin Li                                   (std::numeric_limits<SrcScalar>::digits == std::numeric_limits<TgtScalar>::digits &&
30*bf2c3715SXin Li                                    NumTraits<SrcScalar>::IsSigned))>::type> {
31*bf2c3715SXin Li   static SrcScalar value() {
32*bf2c3715SXin Li     SrcScalar a = internal::random<SrcScalar>();
33*bf2c3715SXin Li     return a < SrcScalar(0) ? -(a + 1) : a;
34*bf2c3715SXin Li   }
35*bf2c3715SXin Li };
36*bf2c3715SXin Li 
37*bf2c3715SXin Li // Integer to unsigned narrowing cast.
38*bf2c3715SXin Li template <typename SrcScalar, typename TgtScalar>
39*bf2c3715SXin Li struct random_without_cast_overflow<
40*bf2c3715SXin Li     SrcScalar, TgtScalar,
41*bf2c3715SXin Li     typename internal::enable_if<
42*bf2c3715SXin Li         NumTraits<SrcScalar>::IsInteger && NumTraits<TgtScalar>::IsInteger && !NumTraits<SrcScalar>::IsSigned &&
43*bf2c3715SXin Li         (std::numeric_limits<SrcScalar>::digits > std::numeric_limits<TgtScalar>::digits)>::type> {
44*bf2c3715SXin Li   static SrcScalar value() {
45*bf2c3715SXin Li     TgtScalar b = internal::random<TgtScalar>();
46*bf2c3715SXin Li     return static_cast<SrcScalar>(b < TgtScalar(0) ? -(b + 1) : b);
47*bf2c3715SXin Li   }
48*bf2c3715SXin Li };
49*bf2c3715SXin Li 
50*bf2c3715SXin Li // Integer to signed narrowing cast.
51*bf2c3715SXin Li template <typename SrcScalar, typename TgtScalar>
52*bf2c3715SXin Li struct random_without_cast_overflow<
53*bf2c3715SXin Li     SrcScalar, TgtScalar,
54*bf2c3715SXin Li     typename internal::enable_if<
55*bf2c3715SXin Li         NumTraits<SrcScalar>::IsInteger && NumTraits<TgtScalar>::IsInteger && NumTraits<SrcScalar>::IsSigned &&
56*bf2c3715SXin Li         (std::numeric_limits<SrcScalar>::digits > std::numeric_limits<TgtScalar>::digits)>::type> {
57*bf2c3715SXin Li   static SrcScalar value() { return static_cast<SrcScalar>(internal::random<TgtScalar>()); }
58*bf2c3715SXin Li };
59*bf2c3715SXin Li 
60*bf2c3715SXin Li // Unsigned to signed integer narrowing cast.
61*bf2c3715SXin Li template <typename SrcScalar, typename TgtScalar>
62*bf2c3715SXin Li struct random_without_cast_overflow<
63*bf2c3715SXin Li     SrcScalar, TgtScalar,
64*bf2c3715SXin Li     typename internal::enable_if<NumTraits<SrcScalar>::IsInteger && NumTraits<TgtScalar>::IsInteger &&
65*bf2c3715SXin Li                                  !NumTraits<SrcScalar>::IsSigned && NumTraits<TgtScalar>::IsSigned &&
66*bf2c3715SXin Li                                  (std::numeric_limits<SrcScalar>::digits ==
67*bf2c3715SXin Li                                   std::numeric_limits<TgtScalar>::digits)>::type> {
68*bf2c3715SXin Li   static SrcScalar value() { return internal::random<SrcScalar>() / 2; }
69*bf2c3715SXin Li };
70*bf2c3715SXin Li 
71*bf2c3715SXin Li // Floating-point to integer, full precision.
72*bf2c3715SXin Li template <typename SrcScalar, typename TgtScalar>
73*bf2c3715SXin Li struct random_without_cast_overflow<
74*bf2c3715SXin Li     SrcScalar, TgtScalar,
75*bf2c3715SXin Li     typename internal::enable_if<
76*bf2c3715SXin Li         !NumTraits<SrcScalar>::IsInteger && !NumTraits<SrcScalar>::IsComplex && NumTraits<TgtScalar>::IsInteger &&
77*bf2c3715SXin Li         (std::numeric_limits<TgtScalar>::digits <= std::numeric_limits<SrcScalar>::digits)>::type> {
78*bf2c3715SXin Li   static SrcScalar value() { return static_cast<SrcScalar>(internal::random<TgtScalar>()); }
79*bf2c3715SXin Li };
80*bf2c3715SXin Li 
81*bf2c3715SXin Li // Floating-point to integer, narrowing precision.
82*bf2c3715SXin Li template <typename SrcScalar, typename TgtScalar>
83*bf2c3715SXin Li struct random_without_cast_overflow<
84*bf2c3715SXin Li     SrcScalar, TgtScalar,
85*bf2c3715SXin Li     typename internal::enable_if<
86*bf2c3715SXin Li         !NumTraits<SrcScalar>::IsInteger && !NumTraits<SrcScalar>::IsComplex && NumTraits<TgtScalar>::IsInteger &&
87*bf2c3715SXin Li         (std::numeric_limits<TgtScalar>::digits > std::numeric_limits<SrcScalar>::digits)>::type> {
88*bf2c3715SXin Li   static SrcScalar value() {
89*bf2c3715SXin Li     // NOTE: internal::random<T>() is limited by RAND_MAX, so random<int64_t> is always within that range.
90*bf2c3715SXin Li     // This prevents us from simply shifting bits, which would result in only 0 or -1.
91*bf2c3715SXin Li     // Instead, keep least-significant K bits and sign.
92*bf2c3715SXin Li     static const TgtScalar KeepMask = (static_cast<TgtScalar>(1) << std::numeric_limits<SrcScalar>::digits) - 1;
93*bf2c3715SXin Li     const TgtScalar a = internal::random<TgtScalar>();
94*bf2c3715SXin Li     return static_cast<SrcScalar>(a > TgtScalar(0) ? (a & KeepMask) : -(a & KeepMask));
95*bf2c3715SXin Li   }
96*bf2c3715SXin Li };
97*bf2c3715SXin Li 
98*bf2c3715SXin Li // Integer to floating-point, re-use above logic.
99*bf2c3715SXin Li template <typename SrcScalar, typename TgtScalar>
100*bf2c3715SXin Li struct random_without_cast_overflow<
101*bf2c3715SXin Li     SrcScalar, TgtScalar,
102*bf2c3715SXin Li     typename internal::enable_if<NumTraits<SrcScalar>::IsInteger && !NumTraits<TgtScalar>::IsInteger &&
103*bf2c3715SXin Li                                  !NumTraits<TgtScalar>::IsComplex>::type> {
104*bf2c3715SXin Li   static SrcScalar value() {
105*bf2c3715SXin Li     return static_cast<SrcScalar>(random_without_cast_overflow<TgtScalar, SrcScalar>::value());
106*bf2c3715SXin Li   }
107*bf2c3715SXin Li };
108*bf2c3715SXin Li 
109*bf2c3715SXin Li // Floating-point narrowing conversion.
110*bf2c3715SXin Li template <typename SrcScalar, typename TgtScalar>
111*bf2c3715SXin Li struct random_without_cast_overflow<
112*bf2c3715SXin Li     SrcScalar, TgtScalar,
113*bf2c3715SXin Li     typename internal::enable_if<!NumTraits<SrcScalar>::IsInteger && !NumTraits<SrcScalar>::IsComplex &&
114*bf2c3715SXin Li                                  !NumTraits<TgtScalar>::IsInteger && !NumTraits<TgtScalar>::IsComplex &&
115*bf2c3715SXin Li                                  (std::numeric_limits<SrcScalar>::digits >
116*bf2c3715SXin Li                                   std::numeric_limits<TgtScalar>::digits)>::type> {
117*bf2c3715SXin Li   static SrcScalar value() { return static_cast<SrcScalar>(internal::random<TgtScalar>()); }
118*bf2c3715SXin Li };
119*bf2c3715SXin Li 
120*bf2c3715SXin Li // Complex to non-complex.
121*bf2c3715SXin Li template <typename SrcScalar, typename TgtScalar>
122*bf2c3715SXin Li struct random_without_cast_overflow<
123*bf2c3715SXin Li     SrcScalar, TgtScalar,
124*bf2c3715SXin Li     typename internal::enable_if<NumTraits<SrcScalar>::IsComplex && !NumTraits<TgtScalar>::IsComplex>::type> {
125*bf2c3715SXin Li   typedef typename NumTraits<SrcScalar>::Real SrcReal;
126*bf2c3715SXin Li   static SrcScalar value() { return SrcScalar(random_without_cast_overflow<SrcReal, TgtScalar>::value(), 0); }
127*bf2c3715SXin Li };
128*bf2c3715SXin Li 
129*bf2c3715SXin Li // Non-complex to complex.
130*bf2c3715SXin Li template <typename SrcScalar, typename TgtScalar>
131*bf2c3715SXin Li struct random_without_cast_overflow<
132*bf2c3715SXin Li     SrcScalar, TgtScalar,
133*bf2c3715SXin Li     typename internal::enable_if<!NumTraits<SrcScalar>::IsComplex && NumTraits<TgtScalar>::IsComplex>::type> {
134*bf2c3715SXin Li   typedef typename NumTraits<TgtScalar>::Real TgtReal;
135*bf2c3715SXin Li   static SrcScalar value() { return random_without_cast_overflow<SrcScalar, TgtReal>::value(); }
136*bf2c3715SXin Li };
137*bf2c3715SXin Li 
138*bf2c3715SXin Li // Complex to complex.
139*bf2c3715SXin Li template <typename SrcScalar, typename TgtScalar>
140*bf2c3715SXin Li struct random_without_cast_overflow<
141*bf2c3715SXin Li     SrcScalar, TgtScalar,
142*bf2c3715SXin Li     typename internal::enable_if<NumTraits<SrcScalar>::IsComplex && NumTraits<TgtScalar>::IsComplex>::type> {
143*bf2c3715SXin Li   typedef typename NumTraits<SrcScalar>::Real SrcReal;
144*bf2c3715SXin Li   typedef typename NumTraits<TgtScalar>::Real TgtReal;
145*bf2c3715SXin Li   static SrcScalar value() {
146*bf2c3715SXin Li     return SrcScalar(random_without_cast_overflow<SrcReal, TgtReal>::value(),
147*bf2c3715SXin Li                      random_without_cast_overflow<SrcReal, TgtReal>::value());
148*bf2c3715SXin Li   }
149*bf2c3715SXin Li };
150*bf2c3715SXin Li 
151*bf2c3715SXin Li }  // namespace internal
152*bf2c3715SXin Li }  // namespace Eigen
153