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