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