random_without_cast_overflow.h
Go to the documentation of this file.
1 // This file is part of Eigen, a lightweight C++ template library
2 // for linear algebra.
3 //
4 // Copyright (C) 2020 C. Antonio Sanchez <cantonios@google.com>
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>
19  static SrcScalar value() { return internal::random<SrcScalar>(); }
20 };
21 
22 // Signed to unsigned integer widening cast.
23 template <typename SrcScalar, typename TgtScalar>
25  SrcScalar, TgtScalar,
26  std::enable_if_t<NumTraits<SrcScalar>::IsInteger && NumTraits<SrcScalar>::IsSigned &&
27  NumTraits<TgtScalar>::IsInteger && !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))>> {
31  static SrcScalar value() {
32  SrcScalar a = internal::random<SrcScalar>();
33  return a < SrcScalar(0) ? -(a + 1) : a;
34  }
35 };
36 
37 // Signed to unsigned integer widening cast.
38 template <typename SrcScalar, typename TgtScalar>
40  SrcScalar, TgtScalar,
41  std::enable_if_t<NumTraits<SrcScalar>::IsInteger && !NumTraits<SrcScalar>::IsSigned &&
42  NumTraits<TgtScalar>::IsInteger && !NumTraits<TgtScalar>::IsSigned &&
43  (std::numeric_limits<SrcScalar>::digits < std::numeric_limits<TgtScalar>::digits ||
44  (std::numeric_limits<SrcScalar>::digits == std::numeric_limits<TgtScalar>::digits &&
45  NumTraits<SrcScalar>::IsSigned))>> {
46  static SrcScalar value() {
47  SrcScalar a = internal::random<SrcScalar>();
48  return a;
49  }
50 };
51 
52 // Integer to unsigned narrowing cast.
53 template <typename SrcScalar, typename TgtScalar>
55  SrcScalar, TgtScalar,
56  std::enable_if_t<NumTraits<SrcScalar>::IsInteger && NumTraits<TgtScalar>::IsInteger &&
57  NumTraits<TgtScalar>::IsSigned && !NumTraits<SrcScalar>::IsSigned &&
58  (std::numeric_limits<SrcScalar>::digits > std::numeric_limits<TgtScalar>::digits)>> {
59  static SrcScalar value() {
60  TgtScalar b = internal::random<TgtScalar>();
61  return static_cast<SrcScalar>(b < TgtScalar(0) ? -(b + 1) : b);
62  }
63 };
64 
65 // Integer to unsigned narrowing cast.
66 template <typename SrcScalar, typename TgtScalar>
68  SrcScalar, TgtScalar,
69  std::enable_if_t<NumTraits<SrcScalar>::IsInteger && NumTraits<TgtScalar>::IsInteger &&
70  !NumTraits<TgtScalar>::IsSigned && !NumTraits<SrcScalar>::IsSigned &&
71  (std::numeric_limits<SrcScalar>::digits > std::numeric_limits<TgtScalar>::digits)>> {
72  static SrcScalar value() {
73  TgtScalar b = internal::random<TgtScalar>();
74  return static_cast<SrcScalar>(b);
75  }
76 };
77 
78 // Integer to signed narrowing cast.
79 template <typename SrcScalar, typename TgtScalar>
81  SrcScalar, TgtScalar,
82  std::enable_if_t<NumTraits<SrcScalar>::IsInteger && NumTraits<TgtScalar>::IsInteger &&
83  NumTraits<SrcScalar>::IsSigned &&
84  (std::numeric_limits<SrcScalar>::digits > std::numeric_limits<TgtScalar>::digits)>> {
85  static SrcScalar value() { return static_cast<SrcScalar>(internal::random<TgtScalar>()); }
86 };
87 
88 // Unsigned to signed integer narrowing cast.
89 template <typename SrcScalar, typename TgtScalar>
91  SrcScalar, TgtScalar,
92  std::enable_if_t<NumTraits<SrcScalar>::IsInteger && NumTraits<TgtScalar>::IsInteger &&
93  !NumTraits<SrcScalar>::IsSigned && NumTraits<TgtScalar>::IsSigned &&
94  (std::numeric_limits<SrcScalar>::digits == std::numeric_limits<TgtScalar>::digits)>> {
95  static SrcScalar value() { return internal::random<SrcScalar>() / 2; }
96 };
97 
98 // Floating-point to integer, full precision.
99 template <typename SrcScalar, typename TgtScalar>
101  SrcScalar, TgtScalar,
102  std::enable_if_t<!NumTraits<SrcScalar>::IsInteger && !NumTraits<SrcScalar>::IsComplex &&
103  NumTraits<TgtScalar>::IsInteger &&
104  (std::numeric_limits<TgtScalar>::digits <= std::numeric_limits<SrcScalar>::digits)>> {
105  static SrcScalar value() { return static_cast<SrcScalar>(internal::random<TgtScalar>()); }
106 };
107 
108 // Floating-point to integer, narrowing precision.
109 template <typename SrcScalar, typename TgtScalar>
111  SrcScalar, TgtScalar,
112  std::enable_if_t<!NumTraits<SrcScalar>::IsInteger && !NumTraits<SrcScalar>::IsComplex &&
113  NumTraits<TgtScalar>::IsInteger && NumTraits<TgtScalar>::IsSigned &&
114  (std::numeric_limits<TgtScalar>::digits > std::numeric_limits<SrcScalar>::digits)>> {
115  static SrcScalar value() {
116  // NOTE: internal::random<T>() is limited by RAND_MAX, so random<int64_t> is always within that range.
117  // This prevents us from simply shifting bits, which would result in only 0 or -1.
118  // Instead, keep least-significant K bits and sign.
119  static const TgtScalar KeepMask = (static_cast<TgtScalar>(1) << std::numeric_limits<SrcScalar>::digits) - 1;
120  const TgtScalar a = internal::random<TgtScalar>();
121  return static_cast<SrcScalar>(a > TgtScalar(0) ? (a & KeepMask) : -(a & KeepMask));
122  }
123 };
124 
125 template <typename SrcScalar, typename TgtScalar>
127  SrcScalar, TgtScalar,
128  std::enable_if_t<!NumTraits<SrcScalar>::IsInteger && !NumTraits<SrcScalar>::IsComplex &&
129  NumTraits<TgtScalar>::IsInteger && !NumTraits<TgtScalar>::IsSigned &&
130  (std::numeric_limits<TgtScalar>::digits > std::numeric_limits<SrcScalar>::digits)>> {
131  static SrcScalar value() {
132  // NOTE: internal::random<T>() is limited by RAND_MAX, so random<int64_t> is always within that range.
133  // This prevents us from simply shifting bits, which would result in only 0 or -1.
134  // Instead, keep least-significant K bits and sign.
135  static const TgtScalar KeepMask = (static_cast<TgtScalar>(1) << std::numeric_limits<SrcScalar>::digits) - 1;
136  const TgtScalar a = internal::random<TgtScalar>();
137  return static_cast<SrcScalar>(a & KeepMask);
138  }
139 };
140 
141 // Integer to floating-point, re-use above logic.
142 template <typename SrcScalar, typename TgtScalar>
144  SrcScalar, TgtScalar,
145  std::enable_if_t<NumTraits<SrcScalar>::IsInteger && !NumTraits<TgtScalar>::IsInteger &&
146  !NumTraits<TgtScalar>::IsComplex>> {
147  static SrcScalar value() {
148  return static_cast<SrcScalar>(random_without_cast_overflow<TgtScalar, SrcScalar>::value());
149  }
150 };
151 
152 // Floating-point narrowing conversion.
153 template <typename SrcScalar, typename TgtScalar>
155  SrcScalar, TgtScalar,
156  std::enable_if_t<!NumTraits<SrcScalar>::IsInteger && !NumTraits<SrcScalar>::IsComplex &&
157  !NumTraits<TgtScalar>::IsInteger && !NumTraits<TgtScalar>::IsComplex &&
158  (std::numeric_limits<SrcScalar>::digits > std::numeric_limits<TgtScalar>::digits)>> {
159  static SrcScalar value() { return static_cast<SrcScalar>(internal::random<TgtScalar>()); }
160 };
161 
162 // Complex to non-complex.
163 template <typename SrcScalar, typename TgtScalar>
165  SrcScalar, TgtScalar, std::enable_if_t<NumTraits<SrcScalar>::IsComplex && !NumTraits<TgtScalar>::IsComplex>> {
167  static SrcScalar value() { return SrcScalar(random_without_cast_overflow<SrcReal, TgtScalar>::value(), 0); }
168 };
169 
170 // Non-complex to complex.
171 template <typename SrcScalar, typename TgtScalar>
173  SrcScalar, TgtScalar, std::enable_if_t<!NumTraits<SrcScalar>::IsComplex && NumTraits<TgtScalar>::IsComplex>> {
176 };
177 
178 // Complex to complex.
179 template <typename SrcScalar, typename TgtScalar>
181  SrcScalar, TgtScalar, std::enable_if_t<NumTraits<SrcScalar>::IsComplex && NumTraits<TgtScalar>::IsComplex>> {
184  static SrcScalar value() {
187  }
188 };
189 
190 } // namespace internal
191 } // namespace Eigen
Scalar * b
Definition: benchVecAdd.cpp:17
const Scalar * a
Definition: level2_cplx_impl.h:32
Namespace containing all symbols from the Eigen library.
Definition: bench_norm.cpp:70
Definition: Eigen_Colamd.h:49
T Real
Definition: NumTraits.h:183
Definition: random_without_cast_overflow.h:18
static SrcScalar value()
Definition: random_without_cast_overflow.h:19