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