Clean up tensor_testutil.
Only report the 10 first mismatches. PiperOrigin-RevId: 319429240 Change-Id: I187c65f6016d8020402f0eee6b05ccbcc50ae900
This commit is contained in:
parent
e25d3e084b
commit
2ae9c259aa
tensorflow/core
common_runtime
framework
@ -41,8 +41,6 @@ limitations under the License.
|
||||
namespace tensorflow {
|
||||
namespace {
|
||||
|
||||
using test::internal::ExpectEqual;
|
||||
|
||||
TEST(GraphRunnerTest, SingleConst) {
|
||||
Scope root = Scope::NewRootScope();
|
||||
auto c = ops::Const(root, 42.0f);
|
||||
@ -50,7 +48,7 @@ TEST(GraphRunnerTest, SingleConst) {
|
||||
std::vector<Tensor> outputs;
|
||||
Status s = graph_runner.Run(root.graph(), nullptr, {}, {c.name()}, &outputs);
|
||||
TF_ASSERT_OK(s);
|
||||
ExpectEqual(42.0f, outputs[0].scalar<float>()());
|
||||
test::ExpectEqual(test::AsScalar(42.0f), outputs[0]);
|
||||
}
|
||||
|
||||
// If not using DeepCopy, and the allocator is deleted with the cpu-device,
|
||||
@ -77,7 +75,7 @@ TEST(GraphRunnerTest, DeepCopy) {
|
||||
graph_runner.Run(root.graph(), nullptr, inputs, {"add:0"}, &outputs);
|
||||
TF_ASSERT_OK(s);
|
||||
}
|
||||
ExpectEqual(3.0f, outputs[0].scalar<float>()());
|
||||
test::ExpectEqual(test::AsScalar(3.0f), outputs[0]);
|
||||
}
|
||||
|
||||
TEST(GraphRunnerTest, MultiFetchConst) {
|
||||
@ -89,8 +87,8 @@ TEST(GraphRunnerTest, MultiFetchConst) {
|
||||
Status s = graph_runner.Run(root.graph(), nullptr, {}, {c.name(), pi.name()},
|
||||
&outputs);
|
||||
TF_ASSERT_OK(s);
|
||||
ExpectEqual(42.0f, outputs[0].scalar<float>()());
|
||||
ExpectEqual(3.14f, outputs[1].scalar<float>()());
|
||||
test::ExpectEqual(test::AsScalar(42.0f), outputs[0]);
|
||||
test::ExpectEqual(test::AsScalar(3.14f), outputs[1]);
|
||||
}
|
||||
|
||||
TEST(GraphRunnerTest, FeedAndFetch) {
|
||||
@ -111,7 +109,7 @@ TEST(GraphRunnerTest, FeedAndFetch) {
|
||||
Status s =
|
||||
graph_runner.Run(root.graph(), nullptr, inputs, {"add:0"}, &outputs);
|
||||
TF_ASSERT_OK(s);
|
||||
ExpectEqual(3.0f, outputs[0].scalar<float>()());
|
||||
test::ExpectEqual(test::AsScalar(3.0f), outputs[0]);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
@ -115,25 +115,39 @@ TEST(TensorTest, DataType_Traits) {
|
||||
EXPECT_TRUE(std::is_trivial<MyComplex128>::value);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void ExpectEqual(const Tensor& x, const Tensor& y) {
|
||||
test::ExpectEqual(x, y);
|
||||
}
|
||||
// test::ExpectEqual does not support ResourceHandle or Variant.
|
||||
template <>
|
||||
void ExpectEqual<ResourceHandle>(const Tensor& x, const Tensor& y) {
|
||||
EXPECT_EQ(x, y);
|
||||
}
|
||||
template <>
|
||||
void ExpectEqual<Variant>(const Tensor& x, const Tensor& y) {
|
||||
EXPECT_EQ(x, y);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void TestCopies(const Tensor& t) {
|
||||
{
|
||||
LOG(INFO) << "CopyFrom()";
|
||||
Tensor t2(t.dtype());
|
||||
EXPECT_TRUE(t2.CopyFrom(t, t.shape()));
|
||||
test::ExpectTensorEqual<T>(t, t2);
|
||||
ExpectEqual<T>(t, t2);
|
||||
}
|
||||
{
|
||||
LOG(INFO) << "operator=()";
|
||||
Tensor t2(t.dtype());
|
||||
t2 = t;
|
||||
test::ExpectTensorEqual<T>(t, t2);
|
||||
ExpectEqual<T>(t, t2);
|
||||
}
|
||||
{
|
||||
LOG(INFO) << "deep copy";
|
||||
Tensor t2(t.dtype(), t.shape());
|
||||
t2.flat<T>() = t.flat<T>();
|
||||
test::ExpectTensorEqual<T>(t, t2);
|
||||
ExpectEqual<T>(t, t2);
|
||||
}
|
||||
{
|
||||
LOG(INFO) << "AsProtoField()";
|
||||
@ -141,7 +155,7 @@ void TestCopies(const Tensor& t) {
|
||||
t.AsProtoField(&proto);
|
||||
Tensor t2(t.dtype());
|
||||
EXPECT_TRUE(t2.FromProto(proto));
|
||||
test::ExpectTensorEqual<T>(t, t2);
|
||||
ExpectEqual<T>(t, t2);
|
||||
}
|
||||
{
|
||||
LOG(INFO) << "AsProtoTensorContent()";
|
||||
@ -149,24 +163,24 @@ void TestCopies(const Tensor& t) {
|
||||
t.AsProtoTensorContent(&proto);
|
||||
Tensor t2(t.dtype());
|
||||
EXPECT_TRUE(t2.FromProto(proto));
|
||||
test::ExpectTensorEqual<T>(t, t2);
|
||||
ExpectEqual<T>(t, t2);
|
||||
// Make another copy via tensor_content field.
|
||||
*proto.mutable_tensor_content() = proto.tensor_content();
|
||||
Tensor t3(t.dtype());
|
||||
EXPECT_TRUE(t3.FromProto(proto));
|
||||
test::ExpectTensorEqual<T>(t, t2);
|
||||
ExpectEqual<T>(t, t2);
|
||||
}
|
||||
{
|
||||
LOG(INFO) << "AsTensor";
|
||||
gtl::ArraySlice<T> values(t.flat<T>().data(), t.NumElements());
|
||||
Tensor t2 = test::AsTensor(values, t.shape());
|
||||
test::ExpectTensorEqual<T>(t, t2);
|
||||
ExpectEqual<T>(t, t2);
|
||||
}
|
||||
{
|
||||
LOG(INFO) << "Move constructor";
|
||||
Tensor t2 = t;
|
||||
Tensor t3(std::move(t2));
|
||||
test::ExpectTensorEqual<T>(t, t3);
|
||||
ExpectEqual<T>(t, t3);
|
||||
EXPECT_TRUE(t3.IsInitialized());
|
||||
EXPECT_FALSE(t2.IsInitialized());
|
||||
}
|
||||
@ -176,7 +190,7 @@ void TestCopies(const Tensor& t) {
|
||||
Tensor t3 = std::move(t2);
|
||||
Tensor* t4 = &t3;
|
||||
*t4 = std::move(t3);
|
||||
test::ExpectTensorEqual<T>(t, t3);
|
||||
ExpectEqual<T>(t, t3);
|
||||
EXPECT_TRUE(t3.IsInitialized());
|
||||
EXPECT_FALSE(t2.IsInitialized());
|
||||
}
|
||||
@ -236,31 +250,31 @@ TEST(Tensor_Variant, Simple) {
|
||||
LOG(INFO) << "CopyFrom()";
|
||||
Tensor t2(t.dtype());
|
||||
EXPECT_TRUE(t2.CopyFrom(t, t.shape()));
|
||||
test::ExpectTensorEqual<Variant>(t, t2);
|
||||
ExpectEqual<Variant>(t, t2);
|
||||
}
|
||||
{
|
||||
LOG(INFO) << "operator=()";
|
||||
Tensor t2(t.dtype());
|
||||
t2 = t;
|
||||
test::ExpectTensorEqual<Variant>(t, t2);
|
||||
ExpectEqual<Variant>(t, t2);
|
||||
}
|
||||
{
|
||||
LOG(INFO) << "deep copy";
|
||||
Tensor t2(t.dtype(), t.shape());
|
||||
t2.flat<Variant>() = t.flat<Variant>();
|
||||
test::ExpectTensorEqual<Variant>(t, t2);
|
||||
ExpectEqual<Variant>(t, t2);
|
||||
}
|
||||
{
|
||||
LOG(INFO) << "AsTensor";
|
||||
gtl::ArraySlice<Variant> values(t.flat<Variant>().data(), t.NumElements());
|
||||
Tensor t2 = test::AsTensor(values, t.shape());
|
||||
test::ExpectTensorEqual<Variant>(t, t2);
|
||||
ExpectEqual<Variant>(t, t2);
|
||||
}
|
||||
{
|
||||
LOG(INFO) << "Move constructor";
|
||||
Tensor t2 = t;
|
||||
Tensor t3(std::move(t2));
|
||||
test::ExpectTensorEqual<Variant>(t, t3);
|
||||
ExpectEqual<Variant>(t, t3);
|
||||
EXPECT_TRUE(t3.IsInitialized());
|
||||
EXPECT_FALSE(t2.IsInitialized());
|
||||
}
|
||||
@ -270,7 +284,7 @@ TEST(Tensor_Variant, Simple) {
|
||||
Tensor t3 = std::move(t2);
|
||||
Tensor* t4 = &t3;
|
||||
*t4 = std::move(t3);
|
||||
test::ExpectTensorEqual<Variant>(t, t3);
|
||||
ExpectEqual<Variant>(t, t3);
|
||||
EXPECT_TRUE(t3.IsInitialized());
|
||||
EXPECT_FALSE(t2.IsInitialized());
|
||||
}
|
||||
@ -933,7 +947,7 @@ TEST(Tensor_Float, SimpleWithHelper) {
|
||||
Tensor t2(t1.dtype(), t1.shape());
|
||||
t2.flat<float>() = t1.flat<float>() * 2.0f;
|
||||
Tensor t3 = test::AsTensor<float>({0, 2, 4, 6, 8, 10}, t1.shape());
|
||||
test::ExpectTensorEqual<float>(t2, t3);
|
||||
ExpectEqual<float>(t2, t3);
|
||||
}
|
||||
|
||||
TEST(Tensor_Int32, SimpleWithHelper) {
|
||||
@ -941,7 +955,7 @@ TEST(Tensor_Int32, SimpleWithHelper) {
|
||||
Tensor t2(t1.dtype(), t1.shape());
|
||||
t2.flat<int32>() = t1.flat<int32>() * 2;
|
||||
Tensor t3 = test::AsTensor<int32>({0, 2, 4, 6, 8, 10}, t1.shape());
|
||||
test::ExpectTensorEqual<int32>(t2, t3);
|
||||
ExpectEqual<int32>(t2, t3);
|
||||
}
|
||||
|
||||
TEST(Tensor_UInt16, SimpleWithHelper) {
|
||||
@ -949,7 +963,7 @@ TEST(Tensor_UInt16, SimpleWithHelper) {
|
||||
Tensor t2(t1.dtype(), t1.shape());
|
||||
t2.flat<uint16>() = t1.flat<uint16>() * uint16(2);
|
||||
Tensor t3 = test::AsTensor<uint16>({0, 2, 4, 6, 8, 10}, t1.shape());
|
||||
test::ExpectTensorEqual<uint16>(t2, t3);
|
||||
ExpectEqual<uint16>(t2, t3);
|
||||
}
|
||||
|
||||
TEST(Tensor_QInt8, SimpleWithHelper) {
|
||||
@ -957,7 +971,7 @@ TEST(Tensor_QInt8, SimpleWithHelper) {
|
||||
Tensor t2(t1.dtype(), t1.shape());
|
||||
t2.flat<qint8>() = t1.flat<qint8>() + qint8(-2);
|
||||
Tensor t3 = test::AsTensor<qint8>({-2, -1, 0, 1, 2, 3}, {2, 3});
|
||||
test::ExpectTensorEqual<qint8>(t2, t3);
|
||||
ExpectEqual<qint8>(t2, t3);
|
||||
}
|
||||
|
||||
TEST(Tensor_QUInt8, SimpleWithHelper) {
|
||||
@ -965,7 +979,7 @@ TEST(Tensor_QUInt8, SimpleWithHelper) {
|
||||
Tensor t2(t1.dtype(), t1.shape());
|
||||
t2.flat<quint8>() = t1.flat<quint8>() + quint8(2);
|
||||
Tensor t3 = test::AsTensor<quint8>({2, 3, 4, 5, 6, 7}, {2, 3});
|
||||
test::ExpectTensorEqual<quint8>(t2, t3);
|
||||
ExpectEqual<quint8>(t2, t3);
|
||||
}
|
||||
|
||||
TEST(Tensor_Int64, SimpleWithHelper) {
|
||||
@ -977,7 +991,7 @@ TEST(Tensor_Int64, SimpleWithHelper) {
|
||||
Tensor t3 = test::AsTensor<int64>(
|
||||
{0LL << 48, 2LL << 48, 4LL << 48, 6LL << 48, 8LL << 48, 10LL << 48},
|
||||
{2, 3});
|
||||
test::ExpectTensorEqual<int64>(t2, t3);
|
||||
ExpectEqual<int64>(t2, t3);
|
||||
}
|
||||
|
||||
TEST(Tensor_String, SimpleWithHelper) {
|
||||
@ -990,7 +1004,7 @@ TEST(Tensor_String, SimpleWithHelper) {
|
||||
}
|
||||
|
||||
// Test with helper.
|
||||
test::ExpectTensorEqual<tstring>(t1, t2);
|
||||
ExpectEqual<tstring>(t1, t2);
|
||||
}
|
||||
|
||||
TEST(Tensor_Bool, SimpleWithHelper) {
|
||||
@ -1005,7 +1019,7 @@ TEST(Tensor_Bool, SimpleWithHelper) {
|
||||
}
|
||||
|
||||
// Test with helper.
|
||||
test::ExpectTensorEqual<bool>(t1, t2);
|
||||
ExpectEqual<bool>(t1, t2);
|
||||
}
|
||||
|
||||
TEST(Tensor_Complex, Simple64) {
|
||||
@ -1035,7 +1049,7 @@ TEST(Tensor_Complex, SimpleWithHelper64) {
|
||||
{0, {-2, 2}, {0, 4}, {-6, 6}, {-8, 0}, {-10, 4}},
|
||||
// shape
|
||||
{2, 3});
|
||||
test::ExpectTensorEqual<complex64>(t2, t3);
|
||||
ExpectEqual<complex64>(t2, t3);
|
||||
}
|
||||
|
||||
// Does some numeric operations for complex64 numbers.
|
||||
@ -1084,7 +1098,7 @@ TEST(Tensor_Complex, SimpleWithHelper128) {
|
||||
{0, {-2, 2}, {0, 4}, {-6, 6}, {-8, 0}, {-10, 4}},
|
||||
// shape
|
||||
{2, 3});
|
||||
test::ExpectTensorEqual<complex128>(t2, t3);
|
||||
ExpectEqual<complex128>(t2, t3);
|
||||
}
|
||||
|
||||
// Does some numeric operations for complex128 numbers.
|
||||
@ -1223,7 +1237,7 @@ TEST(Tensor, Slice_Basic) {
|
||||
// A simple slice equivalent to identity.
|
||||
TestCopies<float>(y);
|
||||
y = x.Slice(0, 10);
|
||||
test::ExpectTensorEqual<float>(x, y);
|
||||
ExpectEqual<float>(x, y);
|
||||
EXPECT_EQ(x.flat<float>().data(), y.flat<float>().data());
|
||||
|
||||
// A slice of a slice.
|
||||
|
@ -14,68 +14,236 @@ limitations under the License.
|
||||
==============================================================================*/
|
||||
|
||||
#include "tensorflow/core/framework/tensor_testutil.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include "tensorflow/core/framework/tensor.h"
|
||||
|
||||
namespace tensorflow {
|
||||
namespace test {
|
||||
|
||||
template <typename T>
|
||||
void ExpectClose(const Tensor& x, const Tensor& y, double atol, double rtol) {
|
||||
const T* Tx = x.flat<T>().data();
|
||||
const T* Ty = y.flat<T>().data();
|
||||
const auto size = x.NumElements();
|
||||
static ::testing::AssertionResult IsSameType(const Tensor& x, const Tensor& y) {
|
||||
if (x.dtype() != y.dtype()) {
|
||||
return ::testing::AssertionFailure()
|
||||
<< "Tensors have different dtypes (" << x.dtype() << " vs "
|
||||
<< y.dtype() << ")";
|
||||
}
|
||||
return ::testing::AssertionSuccess();
|
||||
}
|
||||
|
||||
// Tolerance's type (RealType) can be different from T.
|
||||
// For example, if T = std::complex<float>, then RealType = float.
|
||||
// Did not use std::numeric_limits<T> because
|
||||
// 1) It returns 0 for Eigen::half.
|
||||
// 2) It doesn't support T=std::complex<RealType>.
|
||||
// (Would have to write a templated struct to handle this.)
|
||||
typedef decltype(Eigen::NumTraits<T>::epsilon()) RealType;
|
||||
const RealType kSlackFactor = static_cast<RealType>(5.0);
|
||||
const RealType kDefaultTol = kSlackFactor * Eigen::NumTraits<T>::epsilon();
|
||||
const RealType typed_atol =
|
||||
(atol < 0) ? kDefaultTol : static_cast<RealType>(atol);
|
||||
const RealType typed_rtol =
|
||||
(rtol < 0) ? kDefaultTol : static_cast<RealType>(rtol);
|
||||
ASSERT_GE(typed_atol, static_cast<RealType>(0.0))
|
||||
<< "typed_atol is negative: " << typed_atol;
|
||||
ASSERT_GE(typed_rtol, static_cast<RealType>(0.0))
|
||||
<< "typed_rtol is negative: " << typed_rtol;
|
||||
const int max_failures = 10;
|
||||
static ::testing::AssertionResult IsSameShape(const Tensor& x,
|
||||
const Tensor& y) {
|
||||
if (!x.IsSameSize(y)) {
|
||||
return ::testing::AssertionFailure()
|
||||
<< "Tensors have different shapes (" << x.shape().DebugString()
|
||||
<< " vs " << y.shape().DebugString() << ")";
|
||||
}
|
||||
return ::testing::AssertionSuccess();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static ::testing::AssertionResult EqualFailure(const T& x, const T& y) {
|
||||
return ::testing::AssertionFailure()
|
||||
<< std::setprecision(std::numeric_limits<T>::digits10 + 2) << x
|
||||
<< " not equal to " << y;
|
||||
}
|
||||
static ::testing::AssertionResult IsEqual(float x, float y) {
|
||||
if (::testing::internal::CmpHelperFloatingPointEQ<float>("", "", x, y))
|
||||
return ::testing::AssertionSuccess();
|
||||
return EqualFailure(x, y);
|
||||
}
|
||||
static ::testing::AssertionResult IsEqual(double x, double y) {
|
||||
if (::testing::internal::CmpHelperFloatingPointEQ<double>("", "", x, y))
|
||||
return ::testing::AssertionSuccess();
|
||||
return EqualFailure(x, y);
|
||||
}
|
||||
static ::testing::AssertionResult IsEqual(Eigen::half x, Eigen::half y) {
|
||||
// Below is a reimplementation of CmpHelperFloatingPointEQ<Eigen::half>, which
|
||||
// we cannot use because Eigen::half is not default-constructible.
|
||||
|
||||
if (isnan(x) || isnan(y)) return EqualFailure(x, y);
|
||||
|
||||
auto sign_and_magnitude_to_biased = [](uint16_t sam) {
|
||||
const uint16_t kSignBitMask = 0x8000;
|
||||
if (kSignBitMask & sam) return ~sam + 1; // negative number.
|
||||
return kSignBitMask | sam; // positive number.
|
||||
};
|
||||
|
||||
auto xb = sign_and_magnitude_to_biased(x.x);
|
||||
auto yb = sign_and_magnitude_to_biased(y.x);
|
||||
auto distance = xb >= yb ? xb - yb : yb - xb;
|
||||
const uint16_t kMaxUlps = 4;
|
||||
|
||||
if (distance <= kMaxUlps) return ::testing::AssertionSuccess();
|
||||
return EqualFailure(x, y);
|
||||
}
|
||||
template <typename T>
|
||||
static ::testing::AssertionResult IsEqual(const T& x, const T& y) {
|
||||
if (::testing::internal::CmpHelperEQ<T>("", "", x, y))
|
||||
return ::testing::AssertionSuccess();
|
||||
return EqualFailure(x, y);
|
||||
}
|
||||
template <typename T>
|
||||
static ::testing::AssertionResult IsEqual(const std::complex<T>& x,
|
||||
const std::complex<T>& y) {
|
||||
if (IsEqual(x.real(), y.real()) && IsEqual(x.imag(), y.imag()))
|
||||
return ::testing::AssertionSuccess();
|
||||
return EqualFailure(x, y);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static void ExpectEqual(const Tensor& x, const Tensor& y) {
|
||||
const T* Tx = x.unaligned_flat<T>().data();
|
||||
const T* Ty = y.unaligned_flat<T>().data();
|
||||
auto size = x.NumElements();
|
||||
int max_failures = 10;
|
||||
int num_failures = 0;
|
||||
for (int i = 0; i < size; ++i) {
|
||||
EXPECT_TRUE(
|
||||
internal::Helper<T>::IsClose(Tx[i], Ty[i], typed_atol, typed_rtol))
|
||||
<< "index = " << (++num_failures, i) << " x = " << Tx[i]
|
||||
<< " y = " << Ty[i] << " typed_atol = " << typed_atol
|
||||
<< " typed_rtol = " << typed_rtol;
|
||||
for (decltype(size) i = 0; i < size; ++i) {
|
||||
EXPECT_TRUE(IsEqual(Tx[i], Ty[i])) << "i = " << (++num_failures, i);
|
||||
ASSERT_LT(num_failures, max_failures) << "Too many mismatches, giving up.";
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static ::testing::AssertionResult IsClose(const T& x, const T& y, const T& atol,
|
||||
const T& rtol) {
|
||||
if (x == y) return ::testing::AssertionSuccess(); // Handle infinity.
|
||||
auto tolerance = atol + rtol * Eigen::numext::abs(x);
|
||||
if (Eigen::numext::abs(x - y) <= tolerance)
|
||||
return ::testing::AssertionSuccess();
|
||||
return ::testing::AssertionFailure() << x << " not close to " << y;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static ::testing::AssertionResult IsClose(const std::complex<T>& x,
|
||||
const std::complex<T>& y,
|
||||
const T& atol, const T& rtol) {
|
||||
if (IsClose(x.real(), y.real(), atol, rtol) &&
|
||||
IsClose(x.imag(), y.imag(), atol, rtol))
|
||||
return ::testing::AssertionSuccess();
|
||||
return ::testing::AssertionFailure() << x << " not close to " << y;
|
||||
}
|
||||
|
||||
// Return type can be different from T, e.g. float for T=std::complex<float>.
|
||||
template <typename T>
|
||||
static auto GetTolerance(double tolerance) {
|
||||
using Real = typename Eigen::NumTraits<T>::Real;
|
||||
auto default_tol = static_cast<Real>(5.0) * Eigen::NumTraits<T>::epsilon();
|
||||
auto result = tolerance < 0.0 ? default_tol : static_cast<Real>(tolerance);
|
||||
EXPECT_GE(result, static_cast<Real>(0));
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static void ExpectClose(const Tensor& x, const Tensor& y, double atol,
|
||||
double rtol) {
|
||||
auto typed_atol = GetTolerance<T>(atol);
|
||||
auto typed_rtol = GetTolerance<T>(rtol);
|
||||
|
||||
const T* Tx = x.unaligned_flat<T>().data();
|
||||
const T* Ty = y.unaligned_flat<T>().data();
|
||||
auto size = x.NumElements();
|
||||
int max_failures = 10;
|
||||
int num_failures = 0;
|
||||
for (decltype(size) i = 0; i < size; ++i) {
|
||||
EXPECT_TRUE(IsClose(Tx[i], Ty[i], typed_atol, typed_rtol))
|
||||
<< "i = " << (++num_failures, i) << " Tx[i] = " << Tx[i]
|
||||
<< " Ty[i] = " << Ty[i];
|
||||
ASSERT_LT(num_failures, max_failures)
|
||||
<< "Too many mismatches (atol = " << atol << " rtol = " << rtol
|
||||
<< "), giving up.";
|
||||
}
|
||||
EXPECT_EQ(num_failures, 0)
|
||||
<< "Mismatches detected (atol = " << atol << " rtol = " << rtol << ").";
|
||||
}
|
||||
|
||||
void ExpectEqual(const Tensor& x, const Tensor& y) {
|
||||
ASSERT_TRUE(IsSameType(x, y));
|
||||
ASSERT_TRUE(IsSameShape(x, y));
|
||||
|
||||
switch (x.dtype()) {
|
||||
case DT_FLOAT:
|
||||
return ExpectEqual<float>(x, y);
|
||||
case DT_DOUBLE:
|
||||
return ExpectEqual<double>(x, y);
|
||||
case DT_INT32:
|
||||
return ExpectEqual<int32>(x, y);
|
||||
case DT_UINT32:
|
||||
return ExpectEqual<uint32>(x, y);
|
||||
case DT_UINT16:
|
||||
return ExpectEqual<uint16>(x, y);
|
||||
case DT_UINT8:
|
||||
return ExpectEqual<uint8>(x, y);
|
||||
case DT_INT16:
|
||||
return ExpectEqual<int16>(x, y);
|
||||
case DT_INT8:
|
||||
return ExpectEqual<int8>(x, y);
|
||||
case DT_STRING:
|
||||
return ExpectEqual<tstring>(x, y);
|
||||
case DT_COMPLEX64:
|
||||
return ExpectEqual<complex64>(x, y);
|
||||
case DT_COMPLEX128:
|
||||
return ExpectEqual<complex128>(x, y);
|
||||
case DT_INT64:
|
||||
return ExpectEqual<int64>(x, y);
|
||||
case DT_UINT64:
|
||||
return ExpectEqual<uint64>(x, y);
|
||||
case DT_BOOL:
|
||||
return ExpectEqual<bool>(x, y);
|
||||
case DT_QINT8:
|
||||
return ExpectEqual<qint8>(x, y);
|
||||
case DT_QUINT8:
|
||||
return ExpectEqual<quint8>(x, y);
|
||||
case DT_QINT16:
|
||||
return ExpectEqual<qint16>(x, y);
|
||||
case DT_QUINT16:
|
||||
return ExpectEqual<quint16>(x, y);
|
||||
case DT_QINT32:
|
||||
return ExpectEqual<qint32>(x, y);
|
||||
case DT_BFLOAT16:
|
||||
return ExpectEqual<bfloat16>(x, y);
|
||||
case DT_HALF:
|
||||
return ExpectEqual<Eigen::half>(x, y);
|
||||
default:
|
||||
EXPECT_TRUE(false) << "Unsupported type : " << DataTypeString(x.dtype());
|
||||
}
|
||||
}
|
||||
|
||||
void ExpectClose(const Tensor& x, const Tensor& y, double atol, double rtol) {
|
||||
internal::AssertSameTypeDims(x, y);
|
||||
ASSERT_TRUE(IsSameType(x, y));
|
||||
ASSERT_TRUE(IsSameShape(x, y));
|
||||
|
||||
switch (x.dtype()) {
|
||||
case DT_HALF:
|
||||
ExpectClose<Eigen::half>(x, y, atol, rtol);
|
||||
break;
|
||||
return ExpectClose<Eigen::half>(x, y, atol, rtol);
|
||||
case DT_FLOAT:
|
||||
ExpectClose<float>(x, y, atol, rtol);
|
||||
break;
|
||||
return ExpectClose<float>(x, y, atol, rtol);
|
||||
case DT_DOUBLE:
|
||||
ExpectClose<double>(x, y, atol, rtol);
|
||||
break;
|
||||
return ExpectClose<double>(x, y, atol, rtol);
|
||||
case DT_COMPLEX64:
|
||||
ExpectClose<complex64>(x, y, atol, rtol);
|
||||
break;
|
||||
return ExpectClose<complex64>(x, y, atol, rtol);
|
||||
case DT_COMPLEX128:
|
||||
ExpectClose<complex128>(x, y, atol, rtol);
|
||||
break;
|
||||
return ExpectClose<complex128>(x, y, atol, rtol);
|
||||
default:
|
||||
LOG(FATAL) << "Unexpected type : " << DataTypeString(x.dtype());
|
||||
EXPECT_TRUE(false) << "Unsupported type : " << DataTypeString(x.dtype());
|
||||
}
|
||||
}
|
||||
|
||||
::testing::AssertionResult internal_test::IsClose(Eigen::half x, Eigen::half y,
|
||||
double atol, double rtol) {
|
||||
return test::IsClose(x, y, GetTolerance<Eigen::half>(atol),
|
||||
GetTolerance<Eigen::half>(rtol));
|
||||
}
|
||||
::testing::AssertionResult internal_test::IsClose(float x, float y, double atol,
|
||||
double rtol) {
|
||||
return test::IsClose(x, y, GetTolerance<float>(atol),
|
||||
GetTolerance<float>(rtol));
|
||||
}
|
||||
::testing::AssertionResult internal_test::IsClose(double x, double y,
|
||||
double atol, double rtol) {
|
||||
return test::IsClose(x, y, GetTolerance<double>(atol),
|
||||
GetTolerance<double>(rtol));
|
||||
}
|
||||
|
||||
} // end namespace test
|
||||
} // end namespace tensorflow
|
||||
|
@ -94,190 +94,42 @@ void FillFn(Tensor* tensor, std::function<T(int)> fn) {
|
||||
}
|
||||
|
||||
// Expects "x" and "y" are tensors of the same type, same shape, and
|
||||
// identical values.
|
||||
template <typename T>
|
||||
void ExpectTensorEqual(const Tensor& x, const Tensor& y);
|
||||
// identical values (within 4 ULPs for floating point types).
|
||||
void ExpectEqual(const Tensor& x, const Tensor& y);
|
||||
|
||||
// Expects "x" and "y" are tensors of the same type, same shape, and
|
||||
// approximate equal values, each within "abs_err".
|
||||
template <typename T>
|
||||
void ExpectTensorNear(const Tensor& x, const Tensor& y, const T& abs_err);
|
||||
|
||||
// Expects "x" and "y" are tensors of the same type (float or double),
|
||||
// Expects "x" and "y" are tensors of the same (floating point) type,
|
||||
// same shape and element-wise difference between x and y is no more
|
||||
// than atol + rtol * abs(x). If atol or rtol is negative, it is replaced
|
||||
// with a default tolerance value = data type's epsilon * kSlackFactor.
|
||||
// than atol + rtol * abs(x). If atol or rtol is negative, the data type's
|
||||
// epsilon * kSlackFactor is used.
|
||||
void ExpectClose(const Tensor& x, const Tensor& y, double atol = -1.0,
|
||||
double rtol = -1.0);
|
||||
|
||||
// Implementation details.
|
||||
|
||||
namespace internal {
|
||||
|
||||
template <typename T>
|
||||
struct is_floating_point_type {
|
||||
static constexpr bool value = std::is_same<T, Eigen::half>::value ||
|
||||
std::is_same<T, float>::value ||
|
||||
std::is_same<T, double>::value ||
|
||||
std::is_same<T, std::complex<float>>::value ||
|
||||
std::is_same<T, std::complex<double>>::value;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
inline void ExpectEqual(const T& a, const T& b) {
|
||||
EXPECT_EQ(a, b);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline void ExpectEqual<float>(const float& a, const float& b) {
|
||||
EXPECT_FLOAT_EQ(a, b);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline void ExpectEqual<double>(const double& a, const double& b) {
|
||||
EXPECT_DOUBLE_EQ(a, b);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline void ExpectEqual<complex64>(const complex64& a, const complex64& b) {
|
||||
EXPECT_FLOAT_EQ(a.real(), b.real()) << a << " vs. " << b;
|
||||
EXPECT_FLOAT_EQ(a.imag(), b.imag()) << a << " vs. " << b;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline void ExpectEqual<complex128>(const complex128& a, const complex128& b) {
|
||||
EXPECT_DOUBLE_EQ(a.real(), b.real()) << a << " vs. " << b;
|
||||
EXPECT_DOUBLE_EQ(a.imag(), b.imag()) << a << " vs. " << b;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void ExpectEqual(const T& a, const T& b, int index) {
|
||||
EXPECT_EQ(a, b) << " at index " << index;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline void ExpectEqual<float>(const float& a, const float& b, int index) {
|
||||
EXPECT_FLOAT_EQ(a, b) << " at index " << index;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline void ExpectEqual<double>(const double& a, const double& b, int index) {
|
||||
EXPECT_DOUBLE_EQ(a, b) << " at index " << index;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline void ExpectEqual<complex64>(const complex64& a, const complex64& b,
|
||||
int index) {
|
||||
EXPECT_FLOAT_EQ(a.real(), b.real())
|
||||
<< a << " vs. " << b << " at index " << index;
|
||||
EXPECT_FLOAT_EQ(a.imag(), b.imag())
|
||||
<< a << " vs. " << b << " at index " << index;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline void ExpectEqual<complex128>(const complex128& a, const complex128& b,
|
||||
int index) {
|
||||
EXPECT_DOUBLE_EQ(a.real(), b.real())
|
||||
<< a << " vs. " << b << " at index " << index;
|
||||
EXPECT_DOUBLE_EQ(a.imag(), b.imag())
|
||||
<< a << " vs. " << b << " at index " << index;
|
||||
}
|
||||
|
||||
inline void AssertSameTypeDims(const Tensor& x, const Tensor& y) {
|
||||
ASSERT_EQ(x.dtype(), y.dtype());
|
||||
ASSERT_TRUE(x.IsSameSize(y))
|
||||
<< "x.shape [" << x.shape().DebugString() << "] vs "
|
||||
<< "y.shape [ " << y.shape().DebugString() << "]";
|
||||
}
|
||||
|
||||
template <typename T, bool is_fp = is_floating_point_type<T>::value>
|
||||
struct Expector;
|
||||
|
||||
template <typename T>
|
||||
struct Expector<T, false> {
|
||||
static void Equal(const T& a, const T& b) { ExpectEqual(a, b); }
|
||||
|
||||
static void Equal(const Tensor& x, const Tensor& y) {
|
||||
ASSERT_EQ(x.dtype(), DataTypeToEnum<T>::v());
|
||||
AssertSameTypeDims(x, y);
|
||||
const auto size = x.NumElements();
|
||||
const T* a = x.unaligned_flat<T>().data();
|
||||
const T* b = y.unaligned_flat<T>().data();
|
||||
for (int i = 0; i < size; ++i) {
|
||||
ExpectEqual(a[i], b[i]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Partial specialization for float and double.
|
||||
template <typename T>
|
||||
struct Expector<T, true> {
|
||||
static void Equal(const T& a, const T& b) { ExpectEqual(a, b); }
|
||||
|
||||
static void Equal(const Tensor& x, const Tensor& y) {
|
||||
ASSERT_EQ(x.dtype(), DataTypeToEnum<T>::v());
|
||||
AssertSameTypeDims(x, y);
|
||||
const auto size = x.NumElements();
|
||||
const T* a = x.unaligned_flat<T>().data();
|
||||
const T* b = y.unaligned_flat<T>().data();
|
||||
for (int i = 0; i < size; ++i) {
|
||||
ExpectEqual(a[i], b[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static bool Near(const T& a, const T& b, const double abs_err) {
|
||||
// Need a == b so that infinities are close to themselves.
|
||||
return (a == b) ||
|
||||
(static_cast<double>(Eigen::numext::abs(a - b)) <= abs_err);
|
||||
}
|
||||
|
||||
static void Near(const Tensor& x, const Tensor& y, const double abs_err) {
|
||||
ASSERT_EQ(x.dtype(), DataTypeToEnum<T>::v());
|
||||
AssertSameTypeDims(x, y);
|
||||
const auto size = x.NumElements();
|
||||
const T* a = x.unaligned_flat<T>().data();
|
||||
const T* b = y.unaligned_flat<T>().data();
|
||||
for (int i = 0; i < size; ++i) {
|
||||
EXPECT_TRUE(Near(a[i], b[i], abs_err))
|
||||
<< "a = " << a[i] << " b = " << b[i] << " index = " << i;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct Helper {
|
||||
// Assumes atol and rtol are nonnegative.
|
||||
static bool IsClose(const T& x, const T& y, const T& atol, const T& rtol) {
|
||||
// Need x == y so that infinities are close to themselves.
|
||||
return (x == y) ||
|
||||
(Eigen::numext::abs(x - y) <= atol + rtol * Eigen::numext::abs(x));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct Helper<std::complex<T>> {
|
||||
static bool IsClose(const std::complex<T>& x, const std::complex<T>& y,
|
||||
const T& atol, const T& rtol) {
|
||||
return Helper<T>::IsClose(x.real(), y.real(), atol, rtol) &&
|
||||
Helper<T>::IsClose(x.imag(), y.imag(), atol, rtol);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
// Expects "x" and "y" are tensors of the same type T, same shape, and
|
||||
// equal equal values. Consider using ExpectEqual above instead.
|
||||
template <typename T>
|
||||
void ExpectTensorEqual(const Tensor& x, const Tensor& y) {
|
||||
internal::Expector<T>::Equal(x, y);
|
||||
EXPECT_EQ(x.dtype(), DataTypeToEnum<T>::value);
|
||||
ExpectEqual(x, y);
|
||||
}
|
||||
|
||||
// Expects "x" and "y" are tensors of the same type T, same shape, and
|
||||
// approximate equal values. Consider using ExpectClose above instead.
|
||||
template <typename T>
|
||||
void ExpectTensorNear(const Tensor& x, const Tensor& y, const double abs_err) {
|
||||
static_assert(internal::is_floating_point_type<T>::value,
|
||||
"T is not a floating point types.");
|
||||
ASSERT_GE(abs_err, 0.0) << "abs_error is negative" << abs_err;
|
||||
internal::Expector<T>::Near(x, y, abs_err);
|
||||
void ExpectTensorNear(const Tensor& x, const Tensor& y, double atol) {
|
||||
EXPECT_EQ(x.dtype(), DataTypeToEnum<T>::value);
|
||||
ExpectClose(x, y, atol, /*rtol=*/0.0);
|
||||
}
|
||||
|
||||
// For tensor_testutil_test only.
|
||||
namespace internal_test {
|
||||
::testing::AssertionResult IsClose(Eigen::half x, Eigen::half y,
|
||||
double atol = -1.0, double rtol = -1.0);
|
||||
::testing::AssertionResult IsClose(float x, float y, double atol = -1.0,
|
||||
double rtol = -1.0);
|
||||
::testing::AssertionResult IsClose(double x, double y, double atol = -1.0,
|
||||
double rtol = -1.0);
|
||||
} // namespace internal_test
|
||||
|
||||
} // namespace test
|
||||
} // namespace tensorflow
|
||||
|
||||
|
@ -22,24 +22,23 @@ namespace tensorflow {
|
||||
namespace test {
|
||||
namespace {
|
||||
|
||||
using internal::Expector;
|
||||
using internal::Helper;
|
||||
using internal_test::IsClose;
|
||||
|
||||
template <typename T>
|
||||
static void TestEdgeCasesNear() {
|
||||
EXPECT_TRUE(Expector<T>::Near(Eigen::NumTraits<T>::infinity(),
|
||||
Eigen::NumTraits<T>::infinity(), 0.0));
|
||||
EXPECT_TRUE(Expector<T>::Near(Eigen::NumTraits<T>::lowest(),
|
||||
Eigen::NumTraits<T>::highest(),
|
||||
Eigen::NumTraits<double>::infinity()));
|
||||
EXPECT_FALSE(Expector<T>::Near(Eigen::NumTraits<T>::lowest(),
|
||||
Eigen::NumTraits<T>::highest(),
|
||||
Eigen::NumTraits<double>::highest()));
|
||||
EXPECT_FALSE(Expector<T>::Near(Eigen::NumTraits<T>::quiet_NaN(),
|
||||
Eigen::NumTraits<T>::quiet_NaN(), 0.0));
|
||||
EXPECT_FALSE(Expector<T>::Near(Eigen::NumTraits<T>::quiet_NaN(),
|
||||
Eigen::NumTraits<T>::quiet_NaN(),
|
||||
Eigen::NumTraits<double>::infinity()));
|
||||
void TestEdgeCasesNear() {
|
||||
EXPECT_TRUE(IsClose(Eigen::NumTraits<T>::infinity(),
|
||||
Eigen::NumTraits<T>::infinity(), 0.0, 0.0));
|
||||
EXPECT_TRUE(IsClose(Eigen::NumTraits<T>::lowest(),
|
||||
Eigen::NumTraits<T>::highest(),
|
||||
Eigen::NumTraits<double>::infinity(), 0.0));
|
||||
EXPECT_FALSE(
|
||||
IsClose(Eigen::NumTraits<T>::lowest(), Eigen::NumTraits<T>::highest(),
|
||||
static_cast<double>(Eigen::NumTraits<T>::highest()), 0.0));
|
||||
EXPECT_FALSE(IsClose(Eigen::NumTraits<T>::quiet_NaN(),
|
||||
Eigen::NumTraits<T>::quiet_NaN(), 0.0, 0.0));
|
||||
EXPECT_FALSE(IsClose(Eigen::NumTraits<T>::quiet_NaN(),
|
||||
Eigen::NumTraits<T>::quiet_NaN(),
|
||||
Eigen::NumTraits<double>::infinity(), 0.0));
|
||||
}
|
||||
|
||||
// For debug printing. Example usage:
|
||||
@ -48,7 +47,7 @@ static void TestEdgeCasesNear() {
|
||||
// dumpFloatingPointStorage<float, uint32>(-2.718281f);
|
||||
// dumpFloatingPointStorage <double, uint64>(-2.71828182846);
|
||||
template <typename T, typename U>
|
||||
static void dumpFloatingPointStorage(T value) {
|
||||
void dumpFloatingPointStorage(T value) {
|
||||
U* integral = reinterpret_cast<U*>(&value);
|
||||
int shift_amount = (sizeof(U) << 3) - 1;
|
||||
int exponent_bits = 2 + (log2(sizeof(U)) * 3);
|
||||
@ -67,40 +66,43 @@ TEST(TensorTestUtilTest, ExpectTensorNearHalf) {
|
||||
// The exponent is offset at 15.
|
||||
// https://en.wikipedia.org/wiki/Half-precision_floating-point_format
|
||||
typedef Eigen::half T;
|
||||
#define HALF(x) static_cast<T>(x)
|
||||
|
||||
// Trivial cases: equalities.
|
||||
EXPECT_TRUE(Expector<T>::Near(HALF(1.0f), HALF(1.0f), 0.0));
|
||||
EXPECT_TRUE(Expector<T>::Near(HALF(0.0f), HALF(-0.0f), 0.0));
|
||||
EXPECT_TRUE(Expector<T>::Near(HALF(3.141592f), HALF(3.141592f), 0.0));
|
||||
EXPECT_TRUE(IsClose(static_cast<T>(1.0f), static_cast<T>(1.0f), 0.0, 0.0));
|
||||
EXPECT_TRUE(IsClose(static_cast<T>(0.0f), static_cast<T>(-0.0f), 0.0, 0.0));
|
||||
EXPECT_TRUE(
|
||||
IsClose(static_cast<T>(3.141592f), static_cast<T>(3.141592f), 0.0, 0.0));
|
||||
|
||||
// 0 10010 0001111110 -> 1150/128 = 8.984375 vs
|
||||
// 0 10010 0001111111 -> 1151/128 = 8.9921875 (diff = 0.0078125)
|
||||
EXPECT_TRUE(Expector<T>::Near(HALF(8.9875f), HALF(8.99f), 0.0078125));
|
||||
EXPECT_FALSE(Expector<T>::Near(HALF(8.9875f), HALF(8.99f), 0.007));
|
||||
EXPECT_TRUE(
|
||||
IsClose(static_cast<T>(8.9875f), static_cast<T>(8.99f), 0.0078125, 0.0));
|
||||
EXPECT_FALSE(
|
||||
IsClose(static_cast<T>(8.9875f), static_cast<T>(8.99f), 0.007, 0.0));
|
||||
|
||||
// 0 11000 0110100000 -> 1440/2 = 720 vs
|
||||
// 0 11000 0110100001 -> 1441/2 = 720.5 (diff = 0.5)
|
||||
EXPECT_TRUE(Expector<T>::Near(HALF(720.2f), HALF(720.3f), 0.5));
|
||||
EXPECT_FALSE(Expector<T>::Near(HALF(720.2f), HALF(720.3f), 0.4));
|
||||
EXPECT_TRUE(
|
||||
IsClose(static_cast<T>(720.2f), static_cast<T>(720.3f), 0.5, 0.0));
|
||||
EXPECT_FALSE(
|
||||
IsClose(static_cast<T>(720.2f), static_cast<T>(720.3f), 0.4, 0.0));
|
||||
|
||||
// 0 11001 0011010010 -> 1234 vs
|
||||
// 0 11001 0011010011 -> 1235 (diff = 1)
|
||||
// Rounds to even (1234.5 -> 1234).
|
||||
EXPECT_TRUE(Expector<T>::Near(HALF(1234.f), HALF(1235.f), 1.0));
|
||||
EXPECT_FALSE(Expector<T>::Near(HALF(1234.5f), HALF(1235.f), 0.5));
|
||||
EXPECT_TRUE(Expector<T>::Near(HALF(1234.5f), HALF(1235.f), 1.0));
|
||||
EXPECT_TRUE(
|
||||
IsClose(static_cast<T>(1234.f), static_cast<T>(1235.f), 1.0, 0.0));
|
||||
EXPECT_FALSE(
|
||||
IsClose(static_cast<T>(1234.5f), static_cast<T>(1235.f), 0.5, 0.0));
|
||||
EXPECT_TRUE(
|
||||
IsClose(static_cast<T>(1234.5f), static_cast<T>(1235.f), 1.0, 0.0));
|
||||
|
||||
// 1 10000 0101101100 -> -1388/512 = -2.7109375 vs
|
||||
// 1 10000 0101110001 -> -1393/512 = -2.720703125 (diff = 0.009765625)
|
||||
EXPECT_TRUE(Expector<T>::Near(HALF(-2.71f), HALF(-2.72f), 0.01));
|
||||
EXPECT_TRUE(
|
||||
IsClose(static_cast<T>(-2.71f), static_cast<T>(-2.72f), 0.01, 0.0));
|
||||
|
||||
#undef HALF
|
||||
|
||||
// Some of the cases failed because Eigen::half doesn't behave as expected.
|
||||
// For example, (inf == inf) should have been true, but it returns false.
|
||||
// TODO(penporn): uncomment this test once we fix Eigen::half
|
||||
// TestEdgeCasesNear<T>();
|
||||
TestEdgeCasesNear<T>();
|
||||
}
|
||||
|
||||
TEST(TensorTestUtilTest, ExpectTensorNearFloat) {
|
||||
@ -109,32 +111,32 @@ TEST(TensorTestUtilTest, ExpectTensorNearFloat) {
|
||||
// https://en.wikipedia.org/wiki/Single-precision_floating-point_format
|
||||
typedef float T;
|
||||
// Trivial cases: equalities.
|
||||
EXPECT_TRUE(Expector<T>::Near(1.0f, 1.0f, 0.0));
|
||||
EXPECT_TRUE(Expector<T>::Near(0.0f, -0.0f, 0.0));
|
||||
EXPECT_TRUE(Expector<T>::Near(3.14159265359f, 3.14159265359f, 0.0));
|
||||
EXPECT_TRUE(IsClose(1.0f, 1.0f, 0.0f, 0.0f));
|
||||
EXPECT_TRUE(IsClose(0.0f, -0.0f, 0.0f, 0.0f));
|
||||
EXPECT_TRUE(IsClose(3.14159265359f, 3.14159265359f, 0.0f, 0.0f));
|
||||
|
||||
// 0 10000010 00011111100110011001101 -> 9,424,077/2^20 vs
|
||||
// 0 10000010 00011111100110100110110 -> 9,424,182/2^20
|
||||
// diff = 105/2^20 = 0.000100135803223
|
||||
EXPECT_TRUE(Expector<T>::Near(8.9875f, 8.9876f, 0.0001002));
|
||||
EXPECT_FALSE(Expector<T>::Near(8.9875f, 8.9876f, 0.0001));
|
||||
EXPECT_TRUE(IsClose(8.9875f, 8.9876f, 0.0001002f, 0.0f));
|
||||
EXPECT_FALSE(IsClose(8.9875f, 8.9876f, 0.0001f, 0.0f));
|
||||
|
||||
// 0 10001000 01101000000110011101001 -> 11,799,785/2^14 vs
|
||||
// 0 10001000 01101000000110011101010 -> 11,799,786/2^14
|
||||
// diff = 1/2^14 = 0.00006103515625
|
||||
EXPECT_TRUE(Expector<T>::Near(720.2017f, 720.2018f, 0.0001));
|
||||
EXPECT_FALSE(Expector<T>::Near(720.20175f, 720.20185f, 0.0001));
|
||||
EXPECT_TRUE(Expector<T>::Near(720.20175f, 720.20185f, 0.00013));
|
||||
EXPECT_TRUE(IsClose(720.2017f, 720.2018f, 0.0001f, 0.0f));
|
||||
EXPECT_FALSE(IsClose(720.20175f, 720.20185f, 0.0001f, 0.0f));
|
||||
EXPECT_TRUE(IsClose(720.20175f, 720.20185f, 0.00013f, 0.0f));
|
||||
|
||||
// 0 10011001 11010110111100110100010 -> 15,432,098*2^3 vs
|
||||
// 0 10011001 11010110111100110100011 -> 15,432,099*2^3 (diff = 2^3 = 8)
|
||||
EXPECT_FALSE(Expector<T>::Near(123456788.f, 123456789.f, 4.0));
|
||||
EXPECT_TRUE(Expector<T>::Near(123456788.f, 123456789.f, 8.0));
|
||||
EXPECT_FALSE(IsClose(123456788.f, 123456789.f, 4.0f, 0.0f));
|
||||
EXPECT_TRUE(IsClose(123456788.f, 123456789.f, 8.0f, 0.0f));
|
||||
|
||||
// 1 10000000 01011011111100001010001 -> 11,401,297/2^22 vs
|
||||
// 1 10000000 01011011111100001010101 -> 11,401,301/2^22
|
||||
// diff = 4/2^22 = 0.000000953674316
|
||||
EXPECT_TRUE(Expector<T>::Near(-2.718281f, -2.718282f, 0.1));
|
||||
EXPECT_TRUE(IsClose(-2.718281f, -2.718282f, 0.1f, 0.0f));
|
||||
|
||||
TestEdgeCasesNear<T>();
|
||||
}
|
||||
@ -145,41 +147,40 @@ TEST(TensorTestUtilTest, ExpectTensorNearDouble) {
|
||||
// https://en.wikipedia.org/wiki/Double-precision_floating-point_format
|
||||
typedef double T;
|
||||
// Trivial cases: equalities.
|
||||
EXPECT_TRUE(Expector<T>::Near(1.0, 1.0, 0.0));
|
||||
EXPECT_TRUE(Expector<T>::Near(0.0, -0.0, 0.0));
|
||||
EXPECT_TRUE(Expector<T>::Near(3.14159265359, 3.14159265359, 0.0));
|
||||
EXPECT_TRUE(IsClose(1.0, 1.0, 0.0, 0.0));
|
||||
EXPECT_TRUE(IsClose(0.0, -0.0, 0.0, 0.0));
|
||||
EXPECT_TRUE(IsClose(3.14159265359, 3.14159265359, 0.0, 0.0));
|
||||
|
||||
// 0 10000000010 0001111110011001100110011001100110011001100110011010
|
||||
// -> 5,059,512,706,374,042/2^49 vs
|
||||
// 0 10000000010 0001111110011010011010110101000010110000111100101000
|
||||
// -> 5,059,569,001,369,384/2^49
|
||||
// diff = 56,294,995,342/2^49 = 9.999999999976694198267E-5
|
||||
EXPECT_TRUE(Expector<T>::Near(8.9875, 8.9876, 0.0001));
|
||||
EXPECT_TRUE(IsClose(8.9875, 8.9876, 0.0001, 0.0));
|
||||
|
||||
// 0 10000001111 1000100101110000001100111010100100101010001100000101
|
||||
// -> 6,921,439,564,440,325/2^36
|
||||
// 0 10000001111 1000100101110000001100111010111110110111111010010001
|
||||
// -> 6,921,439,571,312,273/2^36
|
||||
// diff = 6,871,948/2^36 = 1.000000047497451305389E-4
|
||||
EXPECT_FALSE(Expector<T>::Near(100720.2018, 100720.2019, 0.0001));
|
||||
EXPECT_TRUE(Expector<T>::Near(100720.2018, 100720.2019, 1.00000005e-4));
|
||||
EXPECT_FALSE(IsClose(100720.2018, 100720.2019, 0.0001, 0.0));
|
||||
EXPECT_TRUE(IsClose(100720.2018, 100720.2019, 1.00000005e-4, 0.0));
|
||||
|
||||
// 0 10000110100 0101111011100010101000101110101101011010010111000100
|
||||
// -> 6,172,839,450,617,284 * 2
|
||||
// 0 10000110100 0101111011100010101000101110101101011010010111000011
|
||||
// -> 6,172,839,450,617,283 * 2
|
||||
// diff = 1 * 2 = 2
|
||||
EXPECT_FALSE(Expector<T>::Near(12345678901234567., 12345678901234566., 1.0));
|
||||
EXPECT_TRUE(Expector<T>::Near(12345678901234567., 12345678901234566., 2.0));
|
||||
EXPECT_FALSE(IsClose(12345678901234567., 12345678901234566., 1.0, 0.0));
|
||||
EXPECT_TRUE(IsClose(12345678901234567., 12345678901234566., 2.0, 0.0));
|
||||
|
||||
// 1 10000000000 0101101111110000101010001011000101000101111111001111
|
||||
// -> -6,121,026,514,870,223/2^51
|
||||
// 1 10000000000 0101101111110000101010001011000101001011011111000101
|
||||
// -> -6,121,026,514,892,741/2^51
|
||||
// diff = 22,518/2^51 = 1.00000008274037099909E-11
|
||||
EXPECT_FALSE(Expector<T>::Near(-2.71828182846, -2.71828182847, 1.0e-11));
|
||||
EXPECT_TRUE(
|
||||
Expector<T>::Near(-2.71828182846, -2.71828182847, 1.00000009e-11));
|
||||
EXPECT_FALSE(IsClose(-2.71828182846, -2.71828182847, 1.0e-11, 0.0));
|
||||
EXPECT_TRUE(IsClose(-2.71828182846, -2.71828182847, 1.00000009e-11, 0.0));
|
||||
|
||||
TestEdgeCasesNear<T>();
|
||||
}
|
||||
@ -187,49 +188,42 @@ TEST(TensorTestUtilTest, ExpectTensorNearDouble) {
|
||||
// Tensor::Slice() and Tensor::SubSlice() may return unaligned Tensor.
|
||||
TEST(TensorTestUtilTest, ExpectTensorNearSlice) {
|
||||
Tensor x(DT_FLOAT, TensorShape({7, 3}));
|
||||
test::FillFn<float>(&x, [](int i) -> float { return 1.0; });
|
||||
test::FillFn<float>(&x, [](int i) { return 1.0f; });
|
||||
|
||||
test::ExpectTensorNear<float>(
|
||||
x.SubSlice(3), test::AsTensor<float>({1.0, 1.0, 1.0}, TensorShape({3})),
|
||||
1e-10);
|
||||
}
|
||||
|
||||
static const double kSlackFactor = 5.0;
|
||||
|
||||
template <typename T>
|
||||
static void TestEdgeCasesClose() {
|
||||
T kZero = static_cast<T>(0.0);
|
||||
EXPECT_TRUE(Helper<T>::IsClose(Eigen::NumTraits<T>::infinity(),
|
||||
Eigen::NumTraits<T>::infinity(), kZero,
|
||||
kZero));
|
||||
EXPECT_TRUE(Helper<T>::IsClose(
|
||||
Eigen::NumTraits<T>::lowest(), Eigen::NumTraits<T>::highest(),
|
||||
Eigen::NumTraits<T>::infinity(), Eigen::NumTraits<T>::infinity()));
|
||||
EXPECT_TRUE(Helper<T>::IsClose(
|
||||
Eigen::NumTraits<T>::lowest(), Eigen::NumTraits<T>::highest(),
|
||||
Eigen::NumTraits<T>::highest(), Eigen::NumTraits<T>::highest()));
|
||||
EXPECT_FALSE(Helper<T>::IsClose(Eigen::NumTraits<T>::quiet_NaN(),
|
||||
Eigen::NumTraits<T>::quiet_NaN(), kZero,
|
||||
kZero));
|
||||
EXPECT_FALSE(Helper<T>::IsClose(
|
||||
Eigen::NumTraits<T>::quiet_NaN(), Eigen::NumTraits<T>::quiet_NaN(),
|
||||
Eigen::NumTraits<T>::infinity(), Eigen::NumTraits<T>::infinity()));
|
||||
void TestEdgeCasesClose() {
|
||||
EXPECT_TRUE(IsClose(Eigen::NumTraits<T>::infinity(),
|
||||
Eigen::NumTraits<T>::infinity(), 0.0, 0.0));
|
||||
EXPECT_TRUE(IsClose(Eigen::NumTraits<T>::lowest(),
|
||||
Eigen::NumTraits<T>::highest(),
|
||||
Eigen::NumTraits<double>::infinity(),
|
||||
Eigen::NumTraits<double>::infinity()));
|
||||
EXPECT_TRUE(IsClose(Eigen::NumTraits<T>::lowest(),
|
||||
Eigen::NumTraits<T>::highest(),
|
||||
static_cast<double>(Eigen::NumTraits<T>::highest()),
|
||||
static_cast<double>(Eigen::NumTraits<T>::highest())));
|
||||
EXPECT_FALSE(IsClose(Eigen::NumTraits<T>::quiet_NaN(),
|
||||
Eigen::NumTraits<T>::quiet_NaN(), 0.0, 0.0));
|
||||
EXPECT_FALSE(IsClose(Eigen::NumTraits<T>::quiet_NaN(),
|
||||
Eigen::NumTraits<T>::quiet_NaN(),
|
||||
Eigen::NumTraits<double>::infinity(),
|
||||
Eigen::NumTraits<double>::infinity()));
|
||||
}
|
||||
|
||||
TEST(TensorTestUtilTest, ExpectTensorCloseHalf) {
|
||||
typedef Eigen::half T;
|
||||
#define HALF(x) static_cast<T>(x)
|
||||
EXPECT_TRUE(
|
||||
Helper<T>::IsClose(HALF(1.0f), HALF(1.1f), HALF(0.1f), HALF(0.1f)));
|
||||
EXPECT_TRUE(
|
||||
Helper<T>::IsClose(HALF(1.0f), HALF(1.0f), HALF(0.0f), HALF(0.0f)));
|
||||
EXPECT_FALSE(
|
||||
Helper<T>::IsClose(HALF(1.0f), HALF(1.1f), HALF(0.0f), HALF(0.0f)));
|
||||
|
||||
// Epsilon: 0 00010 0000000000 -> 2^-13 = 0.0001220703125
|
||||
// kDefaultTol: 0 00100 0100000000 -> 5/2^13 = 0.0006103515625
|
||||
const T kDefaultTol =
|
||||
static_cast<T>(kSlackFactor) * Eigen::NumTraits<T>::epsilon();
|
||||
EXPECT_TRUE(IsClose(static_cast<T>(1.0f), static_cast<T>(1.1f), 0.1, 0.1));
|
||||
EXPECT_TRUE(IsClose(static_cast<T>(1.0f), static_cast<T>(1.0f), 0.0, 0.0));
|
||||
EXPECT_FALSE(IsClose(static_cast<T>(1.0f), static_cast<T>(1.1f), 0.0, 0.0));
|
||||
|
||||
// Epsilon: 0 00010 0000000000 -> 2^-13 = 0.0001220703125
|
||||
// Default Tolerance: 0 00100 0100000000 -> 5/2^13 = 0.0006103515625
|
||||
|
||||
// 1.234 -> 0 01111 0011110000 -> 1264/2^10 = 1.234375
|
||||
// 1.233 -> 0 01111 0011101111 -> 1263/2^10 = 1.2333984375
|
||||
@ -238,49 +232,37 @@ TEST(TensorTestUtilTest, ExpectTensorCloseHalf) {
|
||||
// 1.236 -> 0 01111 0011110010 -> 1266/2^10 = 1.236328125
|
||||
// 1/2^10 = 0.0009765625E
|
||||
// Threshold = 0.0013637542724609375
|
||||
EXPECT_TRUE(
|
||||
Helper<T>::IsClose(HALF(1.234f), HALF(1.234f), kDefaultTol, kDefaultTol));
|
||||
EXPECT_TRUE(
|
||||
Helper<T>::IsClose(HALF(1.234f), HALF(1.233f), kDefaultTol, kDefaultTol));
|
||||
EXPECT_TRUE(
|
||||
Helper<T>::IsClose(HALF(1.234f), HALF(1.235f), kDefaultTol, kDefaultTol));
|
||||
EXPECT_TRUE(IsClose(static_cast<T>(1.234f), static_cast<T>(1.234f)));
|
||||
EXPECT_TRUE(IsClose(static_cast<T>(1.234f), static_cast<T>(1.233f)));
|
||||
EXPECT_TRUE(IsClose(static_cast<T>(1.234f), static_cast<T>(1.235f)));
|
||||
|
||||
// Diff = 0.001953125
|
||||
EXPECT_FALSE(
|
||||
Helper<T>::IsClose(HALF(1.234f), HALF(1.232f), kDefaultTol, kDefaultTol));
|
||||
EXPECT_FALSE(
|
||||
Helper<T>::IsClose(HALF(1.234f), HALF(1.236f), kDefaultTol, kDefaultTol));
|
||||
EXPECT_FALSE(IsClose(static_cast<T>(1.234f), static_cast<T>(1.232f)));
|
||||
EXPECT_FALSE(IsClose(static_cast<T>(1.234f), static_cast<T>(1.236f)));
|
||||
EXPECT_TRUE(
|
||||
Helper<T>::IsClose(HALF(1.234f), HALF(1.232f), HALF(8e-4f), HALF(1e-3f)));
|
||||
EXPECT_TRUE(Helper<T>::IsClose(HALF(1.234f), HALF(1.236f), HALF(1.4e-3f),
|
||||
HALF(5e-4f)));
|
||||
IsClose(static_cast<T>(1.234f), static_cast<T>(1.232f), 8e-4f, 1e-3f));
|
||||
EXPECT_TRUE(
|
||||
IsClose(static_cast<T>(1.234f), static_cast<T>(1.236f), 1.4e-3f, 5e-4f));
|
||||
|
||||
// Too fine-grained: won't detect the difference
|
||||
EXPECT_TRUE(Helper<T>::IsClose(HALF(3.141592f), HALF(3.141593f), HALF(0.0),
|
||||
HALF(0.0)));
|
||||
EXPECT_TRUE(
|
||||
IsClose(static_cast<T>(3.141592f), static_cast<T>(3.141593f), 0.0, 0.0));
|
||||
|
||||
// Trivial case.
|
||||
EXPECT_FALSE(
|
||||
Helper<T>::IsClose(HALF(1e4f), HALF(1e-4f), kDefaultTol, kDefaultTol));
|
||||
#undef HALF
|
||||
EXPECT_FALSE(IsClose(static_cast<T>(1e4f), static_cast<T>(1e-4f)));
|
||||
|
||||
// Some of the cases failed because Eigen::half doesn't behave as expected.
|
||||
// For example, (inf == inf) should have been true, but it returns false.
|
||||
// TODO(penporn): uncomment this test once we fix Eigen::half
|
||||
// TestEdgeCasesClose<T>();
|
||||
TestEdgeCasesClose<T>();
|
||||
}
|
||||
|
||||
TEST(TensorTestUtilTest, ExpectTensorCloseFloat) {
|
||||
typedef float T;
|
||||
|
||||
EXPECT_TRUE(Helper<T>::IsClose(1.0f, 1.1f, 0.1f, 0.1f));
|
||||
EXPECT_TRUE(Helper<T>::IsClose(1.0f, 1.0f, 0.0f, 0.0f));
|
||||
EXPECT_FALSE(Helper<T>::IsClose(1.0f, 1.1f, 0.0f, 0.0f));
|
||||
EXPECT_TRUE(IsClose(1.0f, 1.1f, 0.1f, 0.1f));
|
||||
EXPECT_TRUE(IsClose(1.0f, 1.0f, 0.0f, 0.0f));
|
||||
EXPECT_FALSE(IsClose(1.0f, 1.1f, 0.0f, 0.0f));
|
||||
|
||||
// Epsilon: 2^-23 ~ 0.00000011920928955078
|
||||
// kDefaultTol: 5/2^23 ~ 0.00000059604644775391
|
||||
const T kDefaultTol =
|
||||
static_cast<T>(kSlackFactor) * Eigen::NumTraits<T>::epsilon();
|
||||
// Epsilon: 2^-23 ~ 0.00000011920928955078
|
||||
// Default Tolerance: 5/2^23 ~ 0.00000059604644775391
|
||||
|
||||
// 1.234567f -> 10,356,299/2^23 ~ 1.234567046165466308594
|
||||
// 1.234568f -> 10,356,307/2^23 ~ 1.234567999839782714844
|
||||
@ -288,25 +270,20 @@ TEST(TensorTestUtilTest, ExpectTensorCloseFloat) {
|
||||
// 1.234569f -> 10,356,315/2^23 ~ 1.234568953514099121094
|
||||
// 1.234565f -> 10,356,282/2^23 ~ 1.234565019607543945313
|
||||
// Threshold ~ 0.00000133190576434572
|
||||
EXPECT_TRUE(
|
||||
Helper<T>::IsClose(1.234567f, 1.234567f, kDefaultTol, kDefaultTol));
|
||||
EXPECT_TRUE(
|
||||
Helper<T>::IsClose(1.234567f, 1.234568f, kDefaultTol, kDefaultTol));
|
||||
EXPECT_TRUE(
|
||||
Helper<T>::IsClose(1.234567f, 1.234566f, kDefaultTol, kDefaultTol));
|
||||
EXPECT_FALSE(
|
||||
Helper<T>::IsClose(1.234567f, 1.234569f, kDefaultTol, kDefaultTol));
|
||||
EXPECT_FALSE(
|
||||
Helper<T>::IsClose(1.234567f, 1.234565f, kDefaultTol, kDefaultTol));
|
||||
EXPECT_TRUE(Helper<T>::IsClose(1.234567f, 1.234569f, 8e-7f, 1e-6f));
|
||||
EXPECT_TRUE(Helper<T>::IsClose(1.234567f, 1.234565f, 3e-7f, 1.5e-6f));
|
||||
EXPECT_TRUE(IsClose(1.234567f, 1.234567f));
|
||||
EXPECT_TRUE(IsClose(1.234567f, 1.234568f));
|
||||
EXPECT_TRUE(IsClose(1.234567f, 1.234566f));
|
||||
EXPECT_FALSE(IsClose(1.234567f, 1.234569f));
|
||||
EXPECT_FALSE(IsClose(1.234567f, 1.234565f));
|
||||
EXPECT_TRUE(IsClose(1.234567f, 1.234569f, 8e-7f, 1e-6f));
|
||||
EXPECT_TRUE(IsClose(1.234567f, 1.234565f, 3e-7f, 1.5e-6f));
|
||||
|
||||
// Too fine-grained: won't detect the difference
|
||||
EXPECT_TRUE(Helper<T>::IsClose(3.14159265f, 3.14159266f, 0.0f, 0.0f));
|
||||
EXPECT_TRUE(IsClose(3.14159265f, 3.14159266f, 0.0f, 0.0f));
|
||||
|
||||
// Trivial cases
|
||||
EXPECT_FALSE(Helper<T>::IsClose(1e8f, 1e-8f, kDefaultTol, kDefaultTol));
|
||||
EXPECT_FALSE(Helper<T>::IsClose(1e15f, 1e-15f, kDefaultTol, kDefaultTol));
|
||||
EXPECT_FALSE(IsClose(1e8f, 1e-8f));
|
||||
EXPECT_FALSE(IsClose(1e15f, 1e-15f));
|
||||
|
||||
TestEdgeCasesClose<T>();
|
||||
}
|
||||
@ -314,14 +291,12 @@ TEST(TensorTestUtilTest, ExpectTensorCloseFloat) {
|
||||
TEST(TensorTestUtilTest, ExpectTensorCloseDouble) {
|
||||
typedef double T;
|
||||
|
||||
EXPECT_TRUE(Helper<T>::IsClose(1.0, 1.1, 0.1, 0.1));
|
||||
EXPECT_TRUE(Helper<T>::IsClose(1.0, 1.0, 0.0, 0.0));
|
||||
EXPECT_FALSE(Helper<T>::IsClose(1.0, 1.1, 0.0, 0.0));
|
||||
EXPECT_TRUE(IsClose(1.0, 1.1, 0.1, 0.1));
|
||||
EXPECT_TRUE(IsClose(1.0, 1.0, 0.0, 0.0));
|
||||
EXPECT_FALSE(IsClose(1.0, 1.1, 0.0, 0.0));
|
||||
|
||||
// Epsilon: 2^-52 ~ 2.220446049250313080847E-16
|
||||
// kDefaultTol: 5/2^52 ~ 1.110223024625156540424E-15
|
||||
const T kDefaultTol =
|
||||
static_cast<T>(kSlackFactor) * Eigen::NumTraits<T>::epsilon();
|
||||
// Epsilon: 2^-52 ~ 2.220446049250313080847E-16
|
||||
// Default Tolerance: 5/2^52 ~ 1.110223024625156540424E-15
|
||||
|
||||
// 1.234567890123456 -> 5,559,999,489,923,576/2^52 ~ 1.234567890123456024298
|
||||
// 1.234567890123457 -> 5,559,999,489,923,580/2^52 ~ 1.234567890123456912477
|
||||
@ -331,32 +306,22 @@ TEST(TensorTestUtilTest, ExpectTensorCloseDouble) {
|
||||
// 1.234567890123459 -> 5,559,999,489,923,589/2^52 ~ 1.234567890123458910878
|
||||
// 1.234567890123453 -> 5,559,999,489,923,562/2^52 ~ 1.234567890123452915674
|
||||
// Threshold ~ 2.480868721703117812159E-15
|
||||
EXPECT_TRUE(Helper<T>::IsClose(1.234567890123456, 1.234567890123456,
|
||||
kDefaultTol, kDefaultTol));
|
||||
EXPECT_TRUE(Helper<T>::IsClose(1.234567890123456, 1.234567890123457,
|
||||
kDefaultTol, kDefaultTol));
|
||||
EXPECT_TRUE(Helper<T>::IsClose(1.234567890123456, 1.234567890123455,
|
||||
kDefaultTol, kDefaultTol));
|
||||
EXPECT_TRUE(Helper<T>::IsClose(1.234567890123456, 1.234567890123458,
|
||||
kDefaultTol, kDefaultTol));
|
||||
EXPECT_TRUE(Helper<T>::IsClose(1.234567890123456, 1.234567890123454,
|
||||
kDefaultTol, kDefaultTol));
|
||||
EXPECT_FALSE(Helper<T>::IsClose(1.234567890123456, 1.234567890123459,
|
||||
kDefaultTol, kDefaultTol));
|
||||
EXPECT_FALSE(Helper<T>::IsClose(1.234567890123456, 1.234567890123453,
|
||||
kDefaultTol, kDefaultTol));
|
||||
EXPECT_TRUE(Helper<T>::IsClose(1.234567890123456, 1.234567890123459, 9.5e-16,
|
||||
1.6e-15));
|
||||
EXPECT_TRUE(
|
||||
Helper<T>::IsClose(1.234567890123456, 1.234567890123453, 7e-16, 2e-15));
|
||||
EXPECT_TRUE(IsClose(1.234567890123456, 1.234567890123456));
|
||||
EXPECT_TRUE(IsClose(1.234567890123456, 1.234567890123457));
|
||||
EXPECT_TRUE(IsClose(1.234567890123456, 1.234567890123455));
|
||||
EXPECT_TRUE(IsClose(1.234567890123456, 1.234567890123458));
|
||||
EXPECT_TRUE(IsClose(1.234567890123456, 1.234567890123454));
|
||||
EXPECT_FALSE(IsClose(1.234567890123456, 1.234567890123459));
|
||||
EXPECT_FALSE(IsClose(1.234567890123456, 1.234567890123453));
|
||||
EXPECT_TRUE(IsClose(1.234567890123456, 1.234567890123459, 9.5e-16, 1.6e-15));
|
||||
EXPECT_TRUE(IsClose(1.234567890123456, 1.234567890123453, 7e-16, 2e-15));
|
||||
|
||||
// Too fine-grained: won't detect the difference
|
||||
EXPECT_TRUE(
|
||||
Helper<T>::IsClose(3.141592653589793238, 3.141592653589793239, 0.0, 0.0));
|
||||
EXPECT_TRUE(IsClose(3.141592653589793238, 3.141592653589793239, 0.0, 0.0));
|
||||
|
||||
// Trivial cases
|
||||
EXPECT_FALSE(Helper<T>::IsClose(1e15, 1e-15, kDefaultTol, kDefaultTol));
|
||||
EXPECT_FALSE(Helper<T>::IsClose(1e30, 1e-30, kDefaultTol, kDefaultTol));
|
||||
EXPECT_FALSE(IsClose(1e15, 1e-15));
|
||||
EXPECT_FALSE(IsClose(1e30, 1e-30));
|
||||
|
||||
TestEdgeCasesClose<T>();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user