random_without_cast_overflow.h 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  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. // Utilities for generating random numbers without overflows, which might
  10. // otherwise result in undefined behavior.
  11. namespace Eigen {
  12. namespace internal {
  13. // Default implementation assuming SrcScalar fits into TgtScalar.
  14. template <typename SrcScalar, typename TgtScalar, typename EnableIf = void>
  15. struct random_without_cast_overflow {
  16. static SrcScalar value() { return internal::random<SrcScalar>(); }
  17. };
  18. // Signed to unsigned integer widening cast.
  19. template <typename SrcScalar, typename TgtScalar>
  20. struct random_without_cast_overflow<
  21. SrcScalar, TgtScalar,
  22. typename internal::enable_if<NumTraits<SrcScalar>::IsInteger && NumTraits<TgtScalar>::IsInteger &&
  23. !NumTraits<TgtScalar>::IsSigned &&
  24. (std::numeric_limits<SrcScalar>::digits < std::numeric_limits<TgtScalar>::digits ||
  25. (std::numeric_limits<SrcScalar>::digits == std::numeric_limits<TgtScalar>::digits &&
  26. NumTraits<SrcScalar>::IsSigned))>::type> {
  27. static SrcScalar value() {
  28. SrcScalar a = internal::random<SrcScalar>();
  29. return a < SrcScalar(0) ? -(a + 1) : a;
  30. }
  31. };
  32. // Integer to unsigned narrowing cast.
  33. template <typename SrcScalar, typename TgtScalar>
  34. struct random_without_cast_overflow<
  35. SrcScalar, TgtScalar,
  36. typename internal::enable_if<
  37. NumTraits<SrcScalar>::IsInteger && NumTraits<TgtScalar>::IsInteger && !NumTraits<SrcScalar>::IsSigned &&
  38. (std::numeric_limits<SrcScalar>::digits > std::numeric_limits<TgtScalar>::digits)>::type> {
  39. static SrcScalar value() {
  40. TgtScalar b = internal::random<TgtScalar>();
  41. return static_cast<SrcScalar>(b < TgtScalar(0) ? -(b + 1) : b);
  42. }
  43. };
  44. // Integer to signed narrowing cast.
  45. template <typename SrcScalar, typename TgtScalar>
  46. struct random_without_cast_overflow<
  47. SrcScalar, TgtScalar,
  48. typename internal::enable_if<
  49. NumTraits<SrcScalar>::IsInteger && NumTraits<TgtScalar>::IsInteger && NumTraits<SrcScalar>::IsSigned &&
  50. (std::numeric_limits<SrcScalar>::digits > std::numeric_limits<TgtScalar>::digits)>::type> {
  51. static SrcScalar value() { return static_cast<SrcScalar>(internal::random<TgtScalar>()); }
  52. };
  53. // Unsigned to signed integer narrowing cast.
  54. template <typename SrcScalar, typename TgtScalar>
  55. struct random_without_cast_overflow<
  56. SrcScalar, TgtScalar,
  57. typename internal::enable_if<NumTraits<SrcScalar>::IsInteger && NumTraits<TgtScalar>::IsInteger &&
  58. !NumTraits<SrcScalar>::IsSigned && NumTraits<TgtScalar>::IsSigned &&
  59. (std::numeric_limits<SrcScalar>::digits ==
  60. std::numeric_limits<TgtScalar>::digits)>::type> {
  61. static SrcScalar value() { return internal::random<SrcScalar>() / 2; }
  62. };
  63. // Floating-point to integer, full precision.
  64. template <typename SrcScalar, typename TgtScalar>
  65. struct random_without_cast_overflow<
  66. SrcScalar, TgtScalar,
  67. typename internal::enable_if<
  68. !NumTraits<SrcScalar>::IsInteger && !NumTraits<SrcScalar>::IsComplex && NumTraits<TgtScalar>::IsInteger &&
  69. (std::numeric_limits<TgtScalar>::digits <= std::numeric_limits<SrcScalar>::digits)>::type> {
  70. static SrcScalar value() { return static_cast<SrcScalar>(internal::random<TgtScalar>()); }
  71. };
  72. // Floating-point to integer, narrowing precision.
  73. template <typename SrcScalar, typename TgtScalar>
  74. struct random_without_cast_overflow<
  75. SrcScalar, TgtScalar,
  76. typename internal::enable_if<
  77. !NumTraits<SrcScalar>::IsInteger && !NumTraits<SrcScalar>::IsComplex && NumTraits<TgtScalar>::IsInteger &&
  78. (std::numeric_limits<TgtScalar>::digits > std::numeric_limits<SrcScalar>::digits)>::type> {
  79. static SrcScalar value() {
  80. // NOTE: internal::random<T>() is limited by RAND_MAX, so random<int64_t> is always within that range.
  81. // This prevents us from simply shifting bits, which would result in only 0 or -1.
  82. // Instead, keep least-significant K bits and sign.
  83. static const TgtScalar KeepMask = (static_cast<TgtScalar>(1) << std::numeric_limits<SrcScalar>::digits) - 1;
  84. const TgtScalar a = internal::random<TgtScalar>();
  85. return static_cast<SrcScalar>(a > TgtScalar(0) ? (a & KeepMask) : -(a & KeepMask));
  86. }
  87. };
  88. // Integer to floating-point, re-use above logic.
  89. template <typename SrcScalar, typename TgtScalar>
  90. struct random_without_cast_overflow<
  91. SrcScalar, TgtScalar,
  92. typename internal::enable_if<NumTraits<SrcScalar>::IsInteger && !NumTraits<TgtScalar>::IsInteger &&
  93. !NumTraits<TgtScalar>::IsComplex>::type> {
  94. static SrcScalar value() {
  95. return static_cast<SrcScalar>(random_without_cast_overflow<TgtScalar, SrcScalar>::value());
  96. }
  97. };
  98. // Floating-point narrowing conversion.
  99. template <typename SrcScalar, typename TgtScalar>
  100. struct random_without_cast_overflow<
  101. SrcScalar, TgtScalar,
  102. typename internal::enable_if<!NumTraits<SrcScalar>::IsInteger && !NumTraits<SrcScalar>::IsComplex &&
  103. !NumTraits<TgtScalar>::IsInteger && !NumTraits<TgtScalar>::IsComplex &&
  104. (std::numeric_limits<SrcScalar>::digits >
  105. std::numeric_limits<TgtScalar>::digits)>::type> {
  106. static SrcScalar value() { return static_cast<SrcScalar>(internal::random<TgtScalar>()); }
  107. };
  108. // Complex to non-complex.
  109. template <typename SrcScalar, typename TgtScalar>
  110. struct random_without_cast_overflow<
  111. SrcScalar, TgtScalar,
  112. typename internal::enable_if<NumTraits<SrcScalar>::IsComplex && !NumTraits<TgtScalar>::IsComplex>::type> {
  113. typedef typename NumTraits<SrcScalar>::Real SrcReal;
  114. static SrcScalar value() { return SrcScalar(random_without_cast_overflow<SrcReal, TgtScalar>::value(), 0); }
  115. };
  116. // Non-complex to complex.
  117. template <typename SrcScalar, typename TgtScalar>
  118. struct random_without_cast_overflow<
  119. SrcScalar, TgtScalar,
  120. typename internal::enable_if<!NumTraits<SrcScalar>::IsComplex && NumTraits<TgtScalar>::IsComplex>::type> {
  121. typedef typename NumTraits<TgtScalar>::Real TgtReal;
  122. static SrcScalar value() { return random_without_cast_overflow<SrcScalar, TgtReal>::value(); }
  123. };
  124. // Complex to complex.
  125. template <typename SrcScalar, typename TgtScalar>
  126. struct random_without_cast_overflow<
  127. SrcScalar, TgtScalar,
  128. typename internal::enable_if<NumTraits<SrcScalar>::IsComplex && NumTraits<TgtScalar>::IsComplex>::type> {
  129. typedef typename NumTraits<SrcScalar>::Real SrcReal;
  130. typedef typename NumTraits<TgtScalar>::Real TgtReal;
  131. static SrcScalar value() {
  132. return SrcScalar(random_without_cast_overflow<SrcReal, TgtReal>::value(),
  133. random_without_cast_overflow<SrcReal, TgtReal>::value());
  134. }
  135. };
  136. } // namespace internal
  137. } // namespace Eigen