aboutsummaryrefslogtreecommitdiffhomepage
path: root/test
diff options
context:
space:
mode:
authorGravatar Antonio Sanchez <cantonios@google.com>2020-06-25 14:31:16 -0700
committerGravatar Antonio Sánchez <cantonios@google.com>2020-06-30 18:53:55 +0000
commit9cb8771e9c4a1f44ba59741c9fac495d1872bb25 (patch)
tree5348c34ac0673d09fe97aea29770e7b236e85510 /test
parent145e51516fdac7b30d22c11c6878c2805fc3d724 (diff)
Fix tensor casts for large packets and casts to/from std::complex
The original tensor casts were only defined for `SrcCoeffRatio`:`TgtCoeffRatio` 1:1, 1:2, 2:1, 4:1. Here we add the missing 1:N and 8:1. We also add casting `Eigen::half` to/from `std::complex<T>`, which was missing to make it consistent with `Eigen:bfloat16`, and generalize the overload to work for any complex type. Tests were added to `basicstuff`, `packetmath`, and `cxx11_tensor_casts` to test all cast configurations.
Diffstat (limited to 'test')
-rw-r--r--test/basicstuff.cpp92
-rw-r--r--test/packetmath.cpp185
-rw-r--r--test/random_without_cast_overflow.h152
3 files changed, 265 insertions, 164 deletions
diff --git a/test/basicstuff.cpp b/test/basicstuff.cpp
index 85af603d8..80fc8a07f 100644
--- a/test/basicstuff.cpp
+++ b/test/basicstuff.cpp
@@ -10,6 +10,7 @@
#define EIGEN_NO_STATIC_ASSERT
#include "main.h"
+#include "random_without_cast_overflow.h"
template<typename MatrixType> void basicStuff(const MatrixType& m)
{
@@ -90,7 +91,7 @@ template<typename MatrixType> void basicStuff(const MatrixType& m)
Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> cv(rows);
rv = square.row(r);
cv = square.col(r);
-
+
VERIFY_IS_APPROX(rv, cv.transpose());
if(cols!=1 && rows!=1 && MatrixType::SizeAtCompileTime!=Dynamic)
@@ -120,28 +121,28 @@ template<typename MatrixType> void basicStuff(const MatrixType& m)
m1 = m2;
VERIFY(m1==m2);
VERIFY(!(m1!=m2));
-
+
// check automatic transposition
sm2.setZero();
for(Index i=0;i<rows;++i)
sm2.col(i) = sm1.row(i);
VERIFY_IS_APPROX(sm2,sm1.transpose());
-
+
sm2.setZero();
for(Index i=0;i<rows;++i)
sm2.col(i).noalias() = sm1.row(i);
VERIFY_IS_APPROX(sm2,sm1.transpose());
-
+
sm2.setZero();
for(Index i=0;i<rows;++i)
sm2.col(i).noalias() += sm1.row(i);
VERIFY_IS_APPROX(sm2,sm1.transpose());
-
+
sm2.setZero();
for(Index i=0;i<rows;++i)
sm2.col(i).noalias() -= sm1.row(i);
VERIFY_IS_APPROX(sm2,-sm1.transpose());
-
+
// check ternary usage
{
bool b = internal::random<int>(0,10)>5;
@@ -194,14 +195,72 @@ template<typename MatrixType> void basicStuffComplex(const MatrixType& m)
VERIFY(!static_cast<const MatrixType&>(cm).imag().isZero());
}
-template<int>
-void casting()
+template<typename SrcScalar, typename TgtScalar>
+void casting_test()
{
- Matrix4f m = Matrix4f::Random(), m2;
- Matrix4d n = m.cast<double>();
- VERIFY(m.isApprox(n.cast<float>()));
- m2 = m.cast<float>(); // check the specialization when NewType == Type
- VERIFY(m.isApprox(m2));
+ Matrix<SrcScalar,4,4> m;
+ for (int i=0; i<m.rows(); ++i) {
+ for (int j=0; j<m.cols(); ++j) {
+ m(i, j) = internal::random_without_cast_overflow<SrcScalar,TgtScalar>::value();
+ }
+ }
+ Matrix<TgtScalar,4,4> n = m.template cast<TgtScalar>();
+ for (int i=0; i<m.rows(); ++i) {
+ for (int j=0; j<m.cols(); ++j) {
+ VERIFY_IS_APPROX(n(i, j), static_cast<TgtScalar>(m(i, j)));
+ }
+ }
+}
+
+template<typename SrcScalar, typename EnableIf = void>
+struct casting_test_runner {
+ static void run() {
+ casting_test<SrcScalar, bool>();
+ casting_test<SrcScalar, int8_t>();
+ casting_test<SrcScalar, uint8_t>();
+ casting_test<SrcScalar, int16_t>();
+ casting_test<SrcScalar, uint16_t>();
+ casting_test<SrcScalar, int32_t>();
+ casting_test<SrcScalar, uint32_t>();
+ casting_test<SrcScalar, int64_t>();
+ casting_test<SrcScalar, uint64_t>();
+ casting_test<SrcScalar, half>();
+ casting_test<SrcScalar, bfloat16>();
+ casting_test<SrcScalar, float>();
+ casting_test<SrcScalar, double>();
+ casting_test<SrcScalar, std::complex<float>>();
+ casting_test<SrcScalar, std::complex<double>>();
+ }
+};
+
+template<typename SrcScalar>
+struct casting_test_runner<SrcScalar, typename internal::enable_if<(NumTraits<SrcScalar>::IsComplex)>::type>
+{
+ static void run() {
+ // Only a few casts from std::complex<T> are defined.
+ casting_test<SrcScalar, half>();
+ casting_test<SrcScalar, bfloat16>();
+ casting_test<SrcScalar, std::complex<float>>();
+ casting_test<SrcScalar, std::complex<double>>();
+ }
+};
+
+void casting_all() {
+ casting_test_runner<bool>::run();
+ casting_test_runner<int8_t>::run();
+ casting_test_runner<uint8_t>::run();
+ casting_test_runner<int16_t>::run();
+ casting_test_runner<uint16_t>::run();
+ casting_test_runner<int32_t>::run();
+ casting_test_runner<uint32_t>::run();
+ casting_test_runner<int64_t>::run();
+ casting_test_runner<uint64_t>::run();
+ casting_test_runner<half>::run();
+ casting_test_runner<bfloat16>::run();
+ casting_test_runner<float>::run();
+ casting_test_runner<double>::run();
+ casting_test_runner<std::complex<float>>::run();
+ casting_test_runner<std::complex<double>>::run();
}
template <typename Scalar>
@@ -210,12 +269,12 @@ void fixedSizeMatrixConstruction()
Scalar raw[4];
for(int k=0; k<4; ++k)
raw[k] = internal::random<Scalar>();
-
+
{
Matrix<Scalar,4,1> m(raw);
Array<Scalar,4,1> a(raw);
for(int k=0; k<4; ++k) VERIFY(m(k) == raw[k]);
- for(int k=0; k<4; ++k) VERIFY(a(k) == raw[k]);
+ for(int k=0; k<4; ++k) VERIFY(a(k) == raw[k]);
VERIFY_IS_EQUAL(m,(Matrix<Scalar,4,1>(raw[0],raw[1],raw[2],raw[3])));
VERIFY((a==(Array<Scalar,4,1>(raw[0],raw[1],raw[2],raw[3]))).all());
}
@@ -277,6 +336,7 @@ EIGEN_DECLARE_TEST(basicstuff)
CALL_SUBTEST_5( basicStuff(MatrixXcd(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
CALL_SUBTEST_6( basicStuff(Matrix<float, 100, 100>()) );
CALL_SUBTEST_7( basicStuff(Matrix<long double,Dynamic,Dynamic>(internal::random<int>(1,EIGEN_TEST_MAX_SIZE),internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
+ CALL_SUBTEST_8( casting_all() );
CALL_SUBTEST_3( basicStuffComplex(MatrixXcf(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
CALL_SUBTEST_5( basicStuffComplex(MatrixXcd(internal::random<int>(1,EIGEN_TEST_MAX_SIZE), internal::random<int>(1,EIGEN_TEST_MAX_SIZE))) );
@@ -288,6 +348,4 @@ EIGEN_DECLARE_TEST(basicstuff)
CALL_SUBTEST_1(fixedSizeMatrixConstruction<int>());
CALL_SUBTEST_1(fixedSizeMatrixConstruction<long int>());
CALL_SUBTEST_1(fixedSizeMatrixConstruction<std::ptrdiff_t>());
-
- CALL_SUBTEST_2(casting<0>());
}
diff --git a/test/packetmath.cpp b/test/packetmath.cpp
index dbc1d3f5a..7821877db 100644
--- a/test/packetmath.cpp
+++ b/test/packetmath.cpp
@@ -8,8 +8,8 @@
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
-#include <limits>
#include "packetmath_test_shared.h"
+#include "random_without_cast_overflow.h"
template <typename T>
inline T REF_ADD(const T& a, const T& b) {
@@ -126,129 +126,6 @@ struct test_cast_helper<SrcPacket, TgtPacket, SrcCoeffRatio, TgtCoeffRatio, fals
static void run() {}
};
-// Generates random values that fit in both SrcScalar and TgtScalar without
-// overflowing when cast.
-template <typename SrcScalar, typename TgtScalar, typename EnableIf = void>
-struct random_without_cast_overflow {
- static SrcScalar value() { return internal::random<SrcScalar>(); }
-};
-
-// Widening integer cast signed to unsigned.
-template <typename SrcScalar, typename TgtScalar>
-struct random_without_cast_overflow<
- SrcScalar, TgtScalar,
- typename internal::enable_if<NumTraits<SrcScalar>::IsInteger && NumTraits<TgtScalar>::IsInteger &&
- !NumTraits<TgtScalar>::IsSigned &&
- (std::numeric_limits<SrcScalar>::digits < std::numeric_limits<TgtScalar>::digits ||
- (std::numeric_limits<SrcScalar>::digits == std::numeric_limits<TgtScalar>::digits &&
- NumTraits<SrcScalar>::IsSigned))>::type> {
- static SrcScalar value() {
- SrcScalar a = internal::random<SrcScalar>();
- return a < SrcScalar(0) ? -(a + 1) : a;
- }
-};
-
-// Narrowing integer cast to unsigned.
-template <typename SrcScalar, typename TgtScalar>
-struct random_without_cast_overflow<
- SrcScalar, TgtScalar,
- typename internal::enable_if<
- NumTraits<SrcScalar>::IsInteger && NumTraits<TgtScalar>::IsInteger && !NumTraits<SrcScalar>::IsSigned &&
- (std::numeric_limits<SrcScalar>::digits > std::numeric_limits<TgtScalar>::digits)>::type> {
- static SrcScalar value() {
- TgtScalar b = internal::random<TgtScalar>();
- return static_cast<SrcScalar>(b < TgtScalar(0) ? -(b + 1) : b);
- }
-};
-
-// Narrowing integer cast to signed.
-template <typename SrcScalar, typename TgtScalar>
-struct random_without_cast_overflow<
- SrcScalar, TgtScalar,
- typename internal::enable_if<
- NumTraits<SrcScalar>::IsInteger && NumTraits<TgtScalar>::IsInteger && NumTraits<SrcScalar>::IsSigned &&
- (std::numeric_limits<SrcScalar>::digits > std::numeric_limits<TgtScalar>::digits)>::type> {
- static SrcScalar value() {
- TgtScalar b = internal::random<TgtScalar>();
- return static_cast<SrcScalar>(b);
- }
-};
-
-// Unsigned to signed narrowing cast.
-template <typename SrcScalar, typename TgtScalar>
-struct random_without_cast_overflow<
- SrcScalar, TgtScalar,
- typename internal::enable_if<NumTraits<SrcScalar>::IsInteger && NumTraits<TgtScalar>::IsInteger &&
- !NumTraits<SrcScalar>::IsSigned && NumTraits<TgtScalar>::IsSigned &&
- (std::numeric_limits<SrcScalar>::digits ==
- std::numeric_limits<TgtScalar>::digits)>::type> {
- static SrcScalar value() { return internal::random<SrcScalar>() / 2; }
-};
-
-template <typename Scalar>
-struct is_floating_point {
- enum { value = 0 };
-};
-template <>
-struct is_floating_point<float> {
- enum { value = 1 };
-};
-template <>
-struct is_floating_point<double> {
- enum { value = 1 };
-};
-template <>
-struct is_floating_point<half> {
- enum { value = 1 };
-};
-template <>
-struct is_floating_point<bfloat16> {
- enum { value = 1 };
-};
-
-// Floating-point to integer, full precision.
-template <typename SrcScalar, typename TgtScalar>
-struct random_without_cast_overflow<
- SrcScalar, TgtScalar,
- typename internal::enable_if<is_floating_point<SrcScalar>::value && NumTraits<TgtScalar>::IsInteger &&
- (std::numeric_limits<TgtScalar>::digits <=
- std::numeric_limits<SrcScalar>::digits)>::type> {
- static SrcScalar value() { return static_cast<SrcScalar>(internal::random<TgtScalar>()); }
-};
-
-// Floating-point to integer, narrowing precision.
-template <typename SrcScalar, typename TgtScalar>
-struct random_without_cast_overflow<
- SrcScalar, TgtScalar,
- typename internal::enable_if<is_floating_point<SrcScalar>::value && NumTraits<TgtScalar>::IsInteger &&
- (std::numeric_limits<TgtScalar>::digits >
- std::numeric_limits<SrcScalar>::digits)>::type> {
- static SrcScalar value() {
- static const int BitShift = std::numeric_limits<TgtScalar>::digits - std::numeric_limits<SrcScalar>::digits;
- return static_cast<SrcScalar>(internal::random<TgtScalar>() >> BitShift);
- }
-};
-
-// Floating-point target from integer, re-use above logic.
-template <typename SrcScalar, typename TgtScalar>
-struct random_without_cast_overflow<
- SrcScalar, TgtScalar,
- typename internal::enable_if<NumTraits<SrcScalar>::IsInteger && is_floating_point<TgtScalar>::value>::type> {
- static SrcScalar value() {
- return static_cast<SrcScalar>(random_without_cast_overflow<TgtScalar, SrcScalar>::value());
- }
-};
-
-// Floating-point narrowing conversion.
-template <typename SrcScalar, typename TgtScalar>
-struct random_without_cast_overflow<
- SrcScalar, TgtScalar,
- typename internal::enable_if<is_floating_point<SrcScalar>::value && is_floating_point<TgtScalar>::value &&
- (std::numeric_limits<SrcScalar>::digits >
- std::numeric_limits<TgtScalar>::digits)>::type> {
- static SrcScalar value() { return static_cast<SrcScalar>(internal::random<TgtScalar>()); }
-};
-
template <typename SrcPacket, typename TgtPacket, int SrcCoeffRatio, int TgtCoeffRatio>
struct test_cast_helper<SrcPacket, TgtPacket, SrcCoeffRatio, TgtCoeffRatio, true> {
static void run() {
@@ -266,10 +143,12 @@ struct test_cast_helper<SrcPacket, TgtPacket, SrcCoeffRatio, TgtCoeffRatio, true
// Construct a packet of scalars that will not overflow when casting
for (int i = 0; i < DataSize; ++i) {
- data1[i] = random_without_cast_overflow<SrcScalar, TgtScalar>::value();
+ data1[i] = internal::random_without_cast_overflow<SrcScalar, TgtScalar>::value();
}
- for (int i = 0; i < DataSize; ++i) ref[i] = static_cast<const TgtScalar>(data1[i]);
+ for (int i = 0; i < DataSize; ++i) {
+ ref[i] = static_cast<const TgtScalar>(data1[i]);
+ }
pcast_array<SrcPacket, TgtPacket, SrcCoeffRatio, TgtCoeffRatio>::cast(data1, DataSize, data2);
@@ -318,21 +197,37 @@ struct test_cast_runner<SrcPacket, TgtScalar, TgtPacket, false, false> {
static void run() {}
};
+template <typename Scalar, typename Packet, typename EnableIf = void>
+struct packetmath_pcast_ops_runner {
+ static void run() {
+ test_cast_runner<Packet, float>::run();
+ test_cast_runner<Packet, double>::run();
+ test_cast_runner<Packet, int8_t>::run();
+ test_cast_runner<Packet, uint8_t>::run();
+ test_cast_runner<Packet, int16_t>::run();
+ test_cast_runner<Packet, uint16_t>::run();
+ test_cast_runner<Packet, int32_t>::run();
+ test_cast_runner<Packet, uint32_t>::run();
+ test_cast_runner<Packet, int64_t>::run();
+ test_cast_runner<Packet, uint64_t>::run();
+ test_cast_runner<Packet, bool>::run();
+ test_cast_runner<Packet, std::complex<float>>::run();
+ test_cast_runner<Packet, std::complex<double>>::run();
+ test_cast_runner<Packet, half>::run();
+ test_cast_runner<Packet, bfloat16>::run();
+ }
+};
+
+// Only some types support cast from std::complex<>.
template <typename Scalar, typename Packet>
-void packetmath_pcast_ops() {
- test_cast_runner<Packet, float>::run();
- test_cast_runner<Packet, double>::run();
- test_cast_runner<Packet, int8_t>::run();
- test_cast_runner<Packet, uint8_t>::run();
- test_cast_runner<Packet, int16_t>::run();
- test_cast_runner<Packet, uint16_t>::run();
- test_cast_runner<Packet, int32_t>::run();
- test_cast_runner<Packet, uint32_t>::run();
- test_cast_runner<Packet, int64_t>::run();
- test_cast_runner<Packet, uint64_t>::run();
- test_cast_runner<Packet, bool>::run();
- test_cast_runner<Packet, half>::run();
-}
+struct packetmath_pcast_ops_runner<Scalar, Packet, typename internal::enable_if<NumTraits<Scalar>::IsComplex>::type> {
+ static void run() {
+ test_cast_runner<Packet, std::complex<float>>::run();
+ test_cast_runner<Packet, std::complex<double>>::run();
+ test_cast_runner<Packet, half>::run();
+ test_cast_runner<Packet, bfloat16>::run();
+ }
+};
template <typename Scalar, typename Packet>
void packetmath_boolean_mask_ops() {
@@ -356,10 +251,8 @@ void packetmath_boolean_mask_ops() {
// Packet16b representing bool does not support ptrue, pandnot or pcmp_eq, since the scalar path
// (for some compilers) compute the bitwise and with 0x1 of the results to keep the value in [0,1].
-#ifdef EIGEN_PACKET_MATH_SSE_H
-template <>
-void packetmath_boolean_mask_ops<bool, internal::Packet16b>() {}
-#endif
+template<>
+void packetmath_boolean_mask_ops<bool, typename internal::packet_traits<bool>::type>() {}
template <typename Scalar, typename Packet>
void packetmath() {
@@ -560,7 +453,7 @@ void packetmath() {
CHECK_CWISE2_IF(true, internal::pand, internal::pand);
packetmath_boolean_mask_ops<Scalar, Packet>();
- packetmath_pcast_ops<Scalar, Packet>();
+ packetmath_pcast_ops_runner<Scalar, Packet>::run();
}
template <typename Scalar, typename Packet>
@@ -975,9 +868,7 @@ EIGEN_DECLARE_TEST(packetmath) {
CALL_SUBTEST_11(test::runner<std::complex<float> >::run());
CALL_SUBTEST_12(test::runner<std::complex<double> >::run());
CALL_SUBTEST_13((packetmath<half, internal::packet_traits<half>::type>()));
-#ifdef EIGEN_PACKET_MATH_SSE_H
CALL_SUBTEST_14((packetmath<bool, internal::packet_traits<bool>::type>()));
-#endif
CALL_SUBTEST_15((packetmath<bfloat16, internal::packet_traits<bfloat16>::type>()));
g_first_pass = false;
}
diff --git a/test/random_without_cast_overflow.h b/test/random_without_cast_overflow.h
new file mode 100644
index 000000000..000345110
--- /dev/null
+++ b/test/random_without_cast_overflow.h
@@ -0,0 +1,152 @@
+// This file is part of Eigen, a lightweight C++ template library
+// for linear algebra.
+//
+// Copyright (C) 2020 C. Antonio Sanchez <cantonios@google.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla
+// Public License v. 2.0. If a copy of the MPL was not distributed
+// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+// Utilities for generating random numbers without overflows, which might
+// otherwise result in undefined behavior.
+
+namespace Eigen {
+namespace internal {
+
+// Default implementation assuming SrcScalar fits into TgtScalar.
+template <typename SrcScalar, typename TgtScalar, typename EnableIf = void>
+struct random_without_cast_overflow {
+ static SrcScalar value() { return internal::random<SrcScalar>(); }
+};
+
+// Signed to unsigned integer widening cast.
+template <typename SrcScalar, typename TgtScalar>
+struct random_without_cast_overflow<
+ SrcScalar, TgtScalar,
+ typename internal::enable_if<NumTraits<SrcScalar>::IsInteger && NumTraits<TgtScalar>::IsInteger &&
+ !NumTraits<TgtScalar>::IsSigned &&
+ (std::numeric_limits<SrcScalar>::digits < std::numeric_limits<TgtScalar>::digits ||
+ (std::numeric_limits<SrcScalar>::digits == std::numeric_limits<TgtScalar>::digits &&
+ NumTraits<SrcScalar>::IsSigned))>::type> {
+ static SrcScalar value() {
+ SrcScalar a = internal::random<SrcScalar>();
+ return a < SrcScalar(0) ? -(a + 1) : a;
+ }
+};
+
+// Integer to unsigned narrowing cast.
+template <typename SrcScalar, typename TgtScalar>
+struct random_without_cast_overflow<
+ SrcScalar, TgtScalar,
+ typename internal::enable_if<
+ NumTraits<SrcScalar>::IsInteger && NumTraits<TgtScalar>::IsInteger && !NumTraits<SrcScalar>::IsSigned &&
+ (std::numeric_limits<SrcScalar>::digits > std::numeric_limits<TgtScalar>::digits)>::type> {
+ static SrcScalar value() {
+ TgtScalar b = internal::random<TgtScalar>();
+ return static_cast<SrcScalar>(b < TgtScalar(0) ? -(b + 1) : b);
+ }
+};
+
+// Integer to signed narrowing cast.
+template <typename SrcScalar, typename TgtScalar>
+struct random_without_cast_overflow<
+ SrcScalar, TgtScalar,
+ typename internal::enable_if<
+ NumTraits<SrcScalar>::IsInteger && NumTraits<TgtScalar>::IsInteger && NumTraits<SrcScalar>::IsSigned &&
+ (std::numeric_limits<SrcScalar>::digits > std::numeric_limits<TgtScalar>::digits)>::type> {
+ static SrcScalar value() { return static_cast<SrcScalar>(internal::random<TgtScalar>()); }
+};
+
+// Unsigned to signed integer narrowing cast.
+template <typename SrcScalar, typename TgtScalar>
+struct random_without_cast_overflow<
+ SrcScalar, TgtScalar,
+ typename internal::enable_if<NumTraits<SrcScalar>::IsInteger && NumTraits<TgtScalar>::IsInteger &&
+ !NumTraits<SrcScalar>::IsSigned && NumTraits<TgtScalar>::IsSigned &&
+ (std::numeric_limits<SrcScalar>::digits ==
+ std::numeric_limits<TgtScalar>::digits)>::type> {
+ static SrcScalar value() { return internal::random<SrcScalar>() / 2; }
+};
+
+// Floating-point to integer, full precision.
+template <typename SrcScalar, typename TgtScalar>
+struct random_without_cast_overflow<
+ SrcScalar, TgtScalar,
+ typename internal::enable_if<
+ !NumTraits<SrcScalar>::IsInteger && !NumTraits<SrcScalar>::IsComplex && NumTraits<TgtScalar>::IsInteger &&
+ (std::numeric_limits<TgtScalar>::digits <= std::numeric_limits<SrcScalar>::digits)>::type> {
+ static SrcScalar value() { return static_cast<SrcScalar>(internal::random<TgtScalar>()); }
+};
+
+// Floating-point to integer, narrowing precision.
+template <typename SrcScalar, typename TgtScalar>
+struct random_without_cast_overflow<
+ SrcScalar, TgtScalar,
+ typename internal::enable_if<
+ !NumTraits<SrcScalar>::IsInteger && !NumTraits<SrcScalar>::IsComplex && NumTraits<TgtScalar>::IsInteger &&
+ (std::numeric_limits<TgtScalar>::digits > std::numeric_limits<SrcScalar>::digits)>::type> {
+ static SrcScalar value() {
+ // NOTE: internal::random<T>() is limited by RAND_MAX, so random<int64_t> is always within that range.
+ // This prevents us from simply shifting bits, which would result in only 0 or -1.
+ // Instead, keep least-significant K bits and sign.
+ static const TgtScalar KeepMask = (static_cast<TgtScalar>(1) << std::numeric_limits<SrcScalar>::digits) - 1;
+ const TgtScalar a = internal::random<TgtScalar>();
+ return static_cast<SrcScalar>(a > TgtScalar(0) ? (a & KeepMask) : -(a & KeepMask));
+ }
+};
+
+// Integer to floating-point, re-use above logic.
+template <typename SrcScalar, typename TgtScalar>
+struct random_without_cast_overflow<
+ SrcScalar, TgtScalar,
+ typename internal::enable_if<NumTraits<SrcScalar>::IsInteger && !NumTraits<TgtScalar>::IsInteger &&
+ !NumTraits<TgtScalar>::IsComplex>::type> {
+ static SrcScalar value() {
+ return static_cast<SrcScalar>(random_without_cast_overflow<TgtScalar, SrcScalar>::value());
+ }
+};
+
+// Floating-point narrowing conversion.
+template <typename SrcScalar, typename TgtScalar>
+struct random_without_cast_overflow<
+ SrcScalar, TgtScalar,
+ typename internal::enable_if<!NumTraits<SrcScalar>::IsInteger && !NumTraits<SrcScalar>::IsComplex &&
+ !NumTraits<TgtScalar>::IsInteger && !NumTraits<TgtScalar>::IsComplex &&
+ (std::numeric_limits<SrcScalar>::digits >
+ std::numeric_limits<TgtScalar>::digits)>::type> {
+ static SrcScalar value() { return static_cast<SrcScalar>(internal::random<TgtScalar>()); }
+};
+
+// Complex to non-complex.
+template <typename SrcScalar, typename TgtScalar>
+struct random_without_cast_overflow<
+ SrcScalar, TgtScalar,
+ typename internal::enable_if<NumTraits<SrcScalar>::IsComplex && !NumTraits<TgtScalar>::IsComplex>::type> {
+ typedef typename NumTraits<SrcScalar>::Real SrcReal;
+ static SrcScalar value() { return SrcScalar(random_without_cast_overflow<SrcReal, TgtScalar>::value(), 0); }
+};
+
+// Non-complex to complex.
+template <typename SrcScalar, typename TgtScalar>
+struct random_without_cast_overflow<
+ SrcScalar, TgtScalar,
+ typename internal::enable_if<!NumTraits<SrcScalar>::IsComplex && NumTraits<TgtScalar>::IsComplex>::type> {
+ typedef typename NumTraits<TgtScalar>::Real TgtReal;
+ static SrcScalar value() { return random_without_cast_overflow<SrcScalar, TgtReal>::value(); }
+};
+
+// Complex to complex.
+template <typename SrcScalar, typename TgtScalar>
+struct random_without_cast_overflow<
+ SrcScalar, TgtScalar,
+ typename internal::enable_if<NumTraits<SrcScalar>::IsComplex && NumTraits<TgtScalar>::IsComplex>::type> {
+ typedef typename NumTraits<SrcScalar>::Real SrcReal;
+ typedef typename NumTraits<TgtScalar>::Real TgtReal;
+ static SrcScalar value() {
+ return SrcScalar(random_without_cast_overflow<SrcReal, TgtReal>::value(),
+ random_without_cast_overflow<SrcReal, TgtReal>::value());
+ }
+};
+
+} // namespace internal
+} // namespace Eigen