934 lines
47 KiB
C++
934 lines
47 KiB
C++
//*****************************************************************************
|
|
// Copyright 2017-2020 Intel Corporation
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
//*****************************************************************************
|
|
|
|
#include <algorithm>
|
|
#include <bitset>
|
|
#include <cmath>
|
|
#include <limits>
|
|
#include <sstream>
|
|
|
|
#include "gtest/gtest.h"
|
|
|
|
#include "ngraph/env_util.hpp"
|
|
#include "ngraph/ngraph.hpp"
|
|
#include "util/all_close_f.hpp"
|
|
#include "util/float_util.hpp"
|
|
|
|
using namespace std;
|
|
using namespace ngraph;
|
|
|
|
class all_close_f_param_test : public testing::TestWithParam<::std::tuple<float, int>>
|
|
{
|
|
protected:
|
|
all_close_f_param_test()
|
|
: upper_bound(FLT_MAX)
|
|
, lower_bound(-FLT_MAX)
|
|
, past_upper_bound(FLT_MAX)
|
|
, past_lower_bound(-FLT_MAX)
|
|
{
|
|
std::tie(expected, tolerance_bits) = GetParam();
|
|
}
|
|
void SetUp() override
|
|
{
|
|
constexpr int mantissa_bits = 24;
|
|
uint32_t expected_as_int = test::FloatUnion(expected).i;
|
|
|
|
// Turn on targeted bit
|
|
// e.g. for float with 24 bit mantissa, 2 bit accuracy, and hard-coded 8 bit exponent_bits
|
|
// tolerance_bit_shift = 32 - (1 + 8 + (24 - 1 ) - 2 )
|
|
// float_length sign exp mantissa implicit 1 tolerance_bits
|
|
uint32_t tolerance_bit_shift = 32 - (1 + 8 + (mantissa_bits - 1) - tolerance_bits);
|
|
uint32_t targeted_bit = (1u << tolerance_bit_shift);
|
|
|
|
if (expected > 0.f)
|
|
{
|
|
uint32_t upper_bound_as_int = expected_as_int + targeted_bit;
|
|
upper_bound = test::FloatUnion(upper_bound_as_int).f;
|
|
past_upper_bound = test::FloatUnion(upper_bound_as_int + 1).f;
|
|
min_signal_too_low = expected;
|
|
min_signal_enables_passing = test::FloatUnion(upper_bound_as_int + 2).f;
|
|
|
|
uint32_t lower_bound_as_int = expected_as_int - targeted_bit;
|
|
lower_bound = test::FloatUnion(lower_bound_as_int).f;
|
|
past_lower_bound = test::FloatUnion(lower_bound_as_int - 1).f;
|
|
}
|
|
else if (expected < 0.f)
|
|
{
|
|
// Same logic/math as above, but reversed variable name order
|
|
uint32_t lower_bound_as_int = expected_as_int + targeted_bit;
|
|
lower_bound = test::FloatUnion(lower_bound_as_int).f;
|
|
past_lower_bound = test::FloatUnion(lower_bound_as_int + 1).f;
|
|
min_signal_too_low = expected;
|
|
min_signal_enables_passing = test::FloatUnion(lower_bound_as_int + 2).f;
|
|
|
|
uint32_t upper_bound_as_int = expected_as_int - targeted_bit;
|
|
upper_bound = test::FloatUnion(upper_bound_as_int).f;
|
|
past_upper_bound = test::FloatUnion(upper_bound_as_int - 1).f;
|
|
}
|
|
else // (expected == 0.f) || (expected == -0.f)
|
|
{
|
|
// Special handling of 0 / -0 which get same bounds
|
|
uint32_t upper_bound_as_int = targeted_bit;
|
|
upper_bound = test::FloatUnion(upper_bound_as_int).f;
|
|
uint32_t past_upper_bound_as_int = upper_bound_as_int + 1;
|
|
past_upper_bound = test::FloatUnion(past_upper_bound_as_int).f;
|
|
min_signal_too_low = expected;
|
|
min_signal_enables_passing = test::FloatUnion(upper_bound_as_int + 2).f;
|
|
|
|
lower_bound = test::FloatUnion(upper_bound_as_int | 0x80000000).f;
|
|
past_lower_bound = test::FloatUnion(past_upper_bound_as_int | 0x80000000).f;
|
|
}
|
|
}
|
|
|
|
float expected{0};
|
|
int tolerance_bits{0};
|
|
float upper_bound;
|
|
float lower_bound;
|
|
float past_upper_bound;
|
|
float past_lower_bound;
|
|
float min_signal_too_low{0};
|
|
float min_signal_enables_passing{0};
|
|
};
|
|
|
|
TEST_P(all_close_f_param_test, test_boundaries)
|
|
{
|
|
if (getenv_bool("NGRAPH_GTEST_INFO"))
|
|
{
|
|
// Print short string documenting which test is being run
|
|
std::cout << "[ INFO ] Test params: (" << expected << ", " << tolerance_bits << ")\n";
|
|
}
|
|
|
|
// Format verbose info to only print out in case of test failure
|
|
stringstream ss;
|
|
ss << "Testing target of: " << expected << " (" << test::float_to_bits(expected) << ")\n";
|
|
ss << "Matching to targets with: " << tolerance_bits << " tolerance_bits\n";
|
|
ss << "upper_bound: " << upper_bound << " (" << test::float_to_bits(upper_bound) << ")\n";
|
|
ss << "lower_bound: " << lower_bound << " (" << test::float_to_bits(lower_bound) << ")\n";
|
|
ss << "past_upper_bound: " << past_upper_bound << " (" << test::float_to_bits(past_upper_bound)
|
|
<< ")\n";
|
|
ss << "past_lower_bound: " << past_lower_bound << " (" << test::float_to_bits(past_lower_bound)
|
|
<< ")\n";
|
|
|
|
EXPECT_TRUE(test::close_f(expected, upper_bound, tolerance_bits)) << ss.str();
|
|
EXPECT_TRUE(
|
|
test::all_close_f(vector<float>({expected}), vector<float>({upper_bound}), tolerance_bits))
|
|
<< ss.str();
|
|
EXPECT_TRUE(test::close_f(expected, lower_bound, tolerance_bits)) << ss.str();
|
|
EXPECT_TRUE(
|
|
test::all_close_f(vector<float>({expected}), vector<float>({lower_bound}), tolerance_bits))
|
|
<< ss.str();
|
|
EXPECT_FALSE(test::close_f(expected, past_upper_bound, tolerance_bits)) << ss.str();
|
|
EXPECT_FALSE(test::close_f(expected, past_upper_bound, tolerance_bits, min_signal_too_low))
|
|
<< ss.str();
|
|
EXPECT_TRUE(
|
|
test::close_f(expected, past_upper_bound, tolerance_bits, min_signal_enables_passing))
|
|
<< ss.str();
|
|
EXPECT_FALSE(test::all_close_f(
|
|
vector<float>({expected}), vector<float>({past_upper_bound}), tolerance_bits))
|
|
<< ss.str();
|
|
EXPECT_FALSE(test::all_close_f(vector<float>({expected}),
|
|
vector<float>({past_upper_bound}),
|
|
tolerance_bits,
|
|
min_signal_too_low))
|
|
<< ss.str();
|
|
EXPECT_TRUE(test::all_close_f(vector<float>({expected}),
|
|
vector<float>({past_upper_bound}),
|
|
tolerance_bits,
|
|
min_signal_enables_passing))
|
|
<< ss.str();
|
|
EXPECT_FALSE(test::close_f(expected, past_lower_bound, tolerance_bits)) << ss.str();
|
|
EXPECT_FALSE(test::close_f(expected, past_lower_bound, tolerance_bits, min_signal_too_low))
|
|
<< ss.str();
|
|
EXPECT_TRUE(
|
|
test::close_f(expected, past_lower_bound, tolerance_bits, min_signal_enables_passing))
|
|
<< ss.str();
|
|
EXPECT_FALSE(test::all_close_f(
|
|
vector<float>({expected}), vector<float>({past_lower_bound}), tolerance_bits))
|
|
<< ss.str();
|
|
EXPECT_FALSE(test::all_close_f(vector<float>({expected}),
|
|
vector<float>({past_lower_bound}),
|
|
tolerance_bits,
|
|
min_signal_too_low))
|
|
<< ss.str();
|
|
EXPECT_TRUE(test::all_close_f(vector<float>({expected}),
|
|
vector<float>({past_lower_bound}),
|
|
tolerance_bits,
|
|
min_signal_enables_passing))
|
|
<< ss.str();
|
|
}
|
|
|
|
INSTANTIATE_TEST_CASE_P(test_simple_floats_with_range_of_precisions,
|
|
all_close_f_param_test,
|
|
testing::Combine(testing::Values(0.f,
|
|
-0.f,
|
|
1.f,
|
|
-1.f,
|
|
10.f,
|
|
-10.f,
|
|
0.75f,
|
|
-0.75f,
|
|
0.5f,
|
|
-0.5f,
|
|
0.25f,
|
|
-0.25f,
|
|
0.125f,
|
|
-0.125f),
|
|
testing::Range(0, 5)), );
|
|
|
|
class all_close_f_double_param_test : public testing::TestWithParam<::std::tuple<double, int>>
|
|
{
|
|
protected:
|
|
all_close_f_double_param_test()
|
|
: upper_bound(DBL_MAX)
|
|
, lower_bound(-DBL_MAX)
|
|
, past_upper_bound(DBL_MAX)
|
|
, past_lower_bound(-DBL_MAX)
|
|
{
|
|
std::tie(expected, tolerance_bits) = GetParam();
|
|
}
|
|
void SetUp() override
|
|
{
|
|
constexpr int mantissa_bits = 53;
|
|
uint64_t expected_as_int = test::DoubleUnion(expected).i;
|
|
// Turn on targeted bit
|
|
// e.g. for double with 52 bit mantissa, 2 bit accuracy, and hard-coded 11 bit exponent_bits
|
|
// tolerance_bit_shift = 64 - (1 + 11 + (52 - 1 ) - 2 )
|
|
// double_length sign exp mantissa implicit 1 tolerance_bits
|
|
uint64_t tolerance_bit_shift = 64 - (1 + 11 + (mantissa_bits - 1) - tolerance_bits);
|
|
uint64_t targeted_bit = (1ull << tolerance_bit_shift);
|
|
|
|
if (expected > 0.)
|
|
{
|
|
uint64_t upper_bound_as_int = expected_as_int + targeted_bit;
|
|
upper_bound = test::DoubleUnion(upper_bound_as_int).d;
|
|
past_upper_bound = test::DoubleUnion(upper_bound_as_int + 1).d;
|
|
min_signal_too_low = expected;
|
|
min_signal_enables_passing = test::DoubleUnion(upper_bound_as_int + 2).d;
|
|
|
|
uint64_t lower_bound_as_int = expected_as_int - targeted_bit;
|
|
lower_bound = test::DoubleUnion(lower_bound_as_int).d;
|
|
past_lower_bound = test::DoubleUnion(lower_bound_as_int - 1).d;
|
|
}
|
|
else if (expected < 0.)
|
|
{
|
|
// Same logic/math as above, but reversed variable name order
|
|
uint64_t lower_bound_as_int = expected_as_int + targeted_bit;
|
|
lower_bound = test::DoubleUnion(lower_bound_as_int).d;
|
|
past_lower_bound = test::DoubleUnion(lower_bound_as_int + 1).d;
|
|
min_signal_too_low = expected;
|
|
min_signal_enables_passing = test::DoubleUnion(lower_bound_as_int + 2).d;
|
|
|
|
uint64_t upper_bound_as_int = expected_as_int - targeted_bit;
|
|
upper_bound = test::DoubleUnion(upper_bound_as_int).d;
|
|
past_upper_bound = test::DoubleUnion(upper_bound_as_int - 1).d;
|
|
}
|
|
else // (expected == 0.) || (expected == -0.)
|
|
{
|
|
// Special handling of 0 / -0 which get same bounds
|
|
uint64_t upper_bound_as_int = targeted_bit;
|
|
upper_bound = test::DoubleUnion(upper_bound_as_int).d;
|
|
uint64_t past_upper_bound_as_int = upper_bound_as_int + 1;
|
|
past_upper_bound = test::DoubleUnion(past_upper_bound_as_int).d;
|
|
min_signal_too_low = expected;
|
|
min_signal_enables_passing = test::DoubleUnion(upper_bound_as_int + 2).d;
|
|
|
|
lower_bound = test::DoubleUnion(upper_bound_as_int | 0x8000000000000000).d;
|
|
past_lower_bound = test::DoubleUnion(past_upper_bound_as_int | 0x8000000000000000).d;
|
|
}
|
|
}
|
|
|
|
double expected{0};
|
|
int tolerance_bits{0};
|
|
double upper_bound;
|
|
double lower_bound;
|
|
double past_upper_bound;
|
|
double past_lower_bound;
|
|
double min_signal_too_low{0};
|
|
double min_signal_enables_passing{0};
|
|
};
|
|
|
|
TEST_P(all_close_f_double_param_test, test_boundaries)
|
|
{
|
|
if (getenv_bool("NGRAPH_GTEST_INFO"))
|
|
{
|
|
// Print short string documenting which test is being run
|
|
std::cout << "[ INFO ] Test params: (" << expected << ", " << tolerance_bits << ")\n";
|
|
}
|
|
|
|
// Format verbose info to only print out in case of test failure
|
|
stringstream ss;
|
|
ss << "Testing target of: " << expected << " (" << test::double_to_bits(expected) << ")\n";
|
|
ss << "Matching to targets with: " << tolerance_bits << " tolerance_bits\n";
|
|
ss << "upper_bound: " << upper_bound << " (" << test::double_to_bits(upper_bound) << ")\n";
|
|
ss << "lower_bound: " << lower_bound << " (" << test::double_to_bits(lower_bound) << ")\n";
|
|
ss << "past_upper_bound: " << past_upper_bound << " (" << test::double_to_bits(past_upper_bound)
|
|
<< ")\n";
|
|
ss << "past_lower_bound: " << past_lower_bound << " (" << test::double_to_bits(past_lower_bound)
|
|
<< ")\n";
|
|
|
|
EXPECT_TRUE(test::close_f(expected, upper_bound, tolerance_bits)) << ss.str();
|
|
EXPECT_TRUE(test::all_close_f(
|
|
vector<double>({expected}), vector<double>({upper_bound}), tolerance_bits))
|
|
<< ss.str();
|
|
EXPECT_TRUE(test::close_f(expected, lower_bound, tolerance_bits)) << ss.str();
|
|
EXPECT_TRUE(test::all_close_f(
|
|
vector<double>({expected}), vector<double>({lower_bound}), tolerance_bits))
|
|
<< ss.str();
|
|
EXPECT_FALSE(test::close_f(expected, past_upper_bound, tolerance_bits)) << ss.str();
|
|
EXPECT_FALSE(test::close_f(expected, past_upper_bound, tolerance_bits, min_signal_too_low))
|
|
<< ss.str();
|
|
EXPECT_TRUE(
|
|
test::close_f(expected, past_upper_bound, tolerance_bits, min_signal_enables_passing))
|
|
<< ss.str();
|
|
EXPECT_FALSE(test::all_close_f(
|
|
vector<double>({expected}), vector<double>({past_upper_bound}), tolerance_bits))
|
|
<< ss.str();
|
|
EXPECT_FALSE(test::all_close_f(vector<double>({expected}),
|
|
vector<double>({past_upper_bound}),
|
|
tolerance_bits,
|
|
min_signal_too_low))
|
|
<< ss.str();
|
|
EXPECT_TRUE(test::all_close_f(vector<double>({expected}),
|
|
vector<double>({past_upper_bound}),
|
|
tolerance_bits,
|
|
min_signal_enables_passing))
|
|
<< ss.str();
|
|
EXPECT_FALSE(test::close_f(expected, past_lower_bound, tolerance_bits)) << ss.str();
|
|
EXPECT_FALSE(test::close_f(expected, past_lower_bound, tolerance_bits, min_signal_too_low))
|
|
<< ss.str();
|
|
EXPECT_TRUE(
|
|
test::close_f(expected, past_lower_bound, tolerance_bits, min_signal_enables_passing))
|
|
<< ss.str();
|
|
EXPECT_FALSE(test::all_close_f(
|
|
vector<double>({expected}), vector<double>({past_lower_bound}), tolerance_bits))
|
|
<< ss.str();
|
|
EXPECT_FALSE(test::all_close_f(vector<double>({expected}),
|
|
vector<double>({past_lower_bound}),
|
|
tolerance_bits,
|
|
min_signal_too_low))
|
|
<< ss.str();
|
|
EXPECT_TRUE(test::all_close_f(vector<double>({expected}),
|
|
vector<double>({past_lower_bound}),
|
|
tolerance_bits,
|
|
min_signal_enables_passing))
|
|
<< ss.str();
|
|
}
|
|
|
|
INSTANTIATE_TEST_CASE_P(
|
|
test_simple_doubles_with_range_of_precisions,
|
|
all_close_f_double_param_test,
|
|
testing::Combine(
|
|
testing::Values(
|
|
0., -0., 1., -1., 10., -10., 0.75, -0.75, 0.5, -0.5, 0.25, -0.25, 0.125, -0.125),
|
|
testing::Range(0, 17)), );
|
|
|
|
// Test the exact bounds near +0.f
|
|
//
|
|
// With tolerance_bits = 18
|
|
// (equivalent to testing bfloat precision with 2 bits tolerance)
|
|
//
|
|
// Targeted bit
|
|
// |
|
|
// v
|
|
// 2 3 4 5 6 (error allowed in 6th bit or later, w/ implicit leading bit)
|
|
// s e e e e e e e e m m m m m m m m m m m m m m m m m m m m m m m
|
|
// =>| 8 | (8 w/ implicit leading bit)
|
|
// ^
|
|
// | 2 |<=
|
|
//
|
|
// [Upper bound]
|
|
// Add 1 at this bit
|
|
// |
|
|
// v
|
|
// 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
|
// + 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
|
// ---------------------------------------------------------------
|
|
// 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
|
//
|
|
// [Lower bound]
|
|
// Minus 1 at this bit
|
|
// |
|
|
// v
|
|
// 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
|
// - 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
|
// ---------------------------------------------------------------
|
|
// 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
|
//
|
|
// Convert to 2's compliment
|
|
// 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
|
//
|
|
// Mask the sign bit
|
|
// 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
|
TEST(all_close_f, mantissa_8_near_0)
|
|
{
|
|
constexpr int tolerance_bits = (FLOAT_MANTISSA_BITS - BFLOAT_MANTISSA_BITS + 2);
|
|
|
|
// 0.f, the ground-truth value
|
|
float expected = test::bits_to_float("0 00000000 000 0000 0000 0000 0000 0000");
|
|
float computed;
|
|
float min_signal_too_low = test::bits_to_float("0 00000000 000 0100 0000 0000 0000 0001");
|
|
float min_signal_enables_passing =
|
|
test::bits_to_float("0 00000000 000 0100 0000 0000 0000 0010");
|
|
|
|
// ~3.67342E-40, the exact upper bound
|
|
computed = test::bits_to_float("0 00000000 000 0100 0000 0000 0000 0000");
|
|
EXPECT_TRUE(test::close_f(expected, computed, tolerance_bits));
|
|
EXPECT_TRUE(
|
|
test::all_close_f(vector<float>({expected}), vector<float>({computed}), tolerance_bits));
|
|
|
|
// ~3.67343E-40, the next representable number bigger than upper bound
|
|
computed = test::bits_to_float("0 00000000 000 0100 0000 0000 0000 0001");
|
|
EXPECT_FALSE(test::close_f(expected, computed, tolerance_bits));
|
|
EXPECT_FALSE(test::close_f(expected, computed, tolerance_bits, min_signal_too_low));
|
|
EXPECT_TRUE(test::close_f(expected, computed, tolerance_bits, min_signal_enables_passing));
|
|
EXPECT_FALSE(
|
|
test::all_close_f(vector<float>({expected}), vector<float>({computed}), tolerance_bits));
|
|
EXPECT_FALSE(test::all_close_f(
|
|
vector<float>({expected}), vector<float>({computed}), tolerance_bits, min_signal_too_low));
|
|
EXPECT_TRUE(test::all_close_f(vector<float>({expected}),
|
|
vector<float>({computed}),
|
|
tolerance_bits,
|
|
min_signal_enables_passing));
|
|
|
|
// ~-3.67342E-40, the exact lower bound
|
|
computed = test::bits_to_float("1 00000000 000 0100 0000 0000 0000 0000");
|
|
EXPECT_TRUE(test::close_f(expected, computed, tolerance_bits));
|
|
EXPECT_TRUE(
|
|
test::all_close_f(vector<float>({expected}), vector<float>({computed}), tolerance_bits));
|
|
|
|
// ~-3.67343E-40, the next representable number smaller than lower bound
|
|
computed = test::bits_to_float("1 00000000 000 0100 0000 0000 0000 0001");
|
|
EXPECT_FALSE(test::close_f(expected, computed, tolerance_bits));
|
|
EXPECT_FALSE(test::close_f(expected, computed, tolerance_bits, min_signal_too_low));
|
|
EXPECT_TRUE(test::close_f(expected, computed, tolerance_bits, min_signal_enables_passing));
|
|
EXPECT_FALSE(
|
|
test::all_close_f(vector<float>({expected}), vector<float>({computed}), tolerance_bits));
|
|
EXPECT_FALSE(test::all_close_f(
|
|
vector<float>({expected}), vector<float>({computed}), tolerance_bits, min_signal_too_low));
|
|
EXPECT_TRUE(test::all_close_f(vector<float>({expected}),
|
|
vector<float>({computed}),
|
|
tolerance_bits,
|
|
min_signal_enables_passing));
|
|
}
|
|
|
|
// Test the exact bounds near -0.f
|
|
//
|
|
// With tolerance_bits = 18
|
|
// (equivalent to testing bfloat precision with 2 bits tolerance)
|
|
//
|
|
// Targeted bit
|
|
// |
|
|
// v
|
|
// 2 3 4 5 6 (error allowed in 6th bit or later, w/ implicit leading bit)
|
|
// s e e e e e e e e m m m m m m m m m m m m m m m m m m m m m m m
|
|
// =>| 8 | (8 w/ implicit leading bit)
|
|
// ^
|
|
// | 2 |<=
|
|
//
|
|
// [Upper bound]
|
|
// Minus 1 at this bit
|
|
// |
|
|
// v
|
|
// 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
|
// - 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
|
// ---------------------------------------------------------------
|
|
// 0 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
|
//
|
|
// Convert to 2's compliment
|
|
// 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
|
//
|
|
// Mask off sign bit
|
|
// 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
|
//
|
|
// [Lower bound]
|
|
// Add 1 at this bit
|
|
// |
|
|
// v
|
|
// 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
|
// + 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
|
// ---------------------------------------------------------------
|
|
// 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
|
TEST(all_close_f, mantissa_8_near_n0)
|
|
{
|
|
constexpr int tolerance_bits = (FLOAT_MANTISSA_BITS - BFLOAT_MANTISSA_BITS + 2);
|
|
|
|
// 0.f, the ground-truth value
|
|
float expected = test::bits_to_float("1 00000000 000 0000 0000 0000 0000 0000");
|
|
float computed;
|
|
float min_signal_too_low = test::bits_to_float("0 00000000 000 0100 0000 0000 0000 0001");
|
|
float min_signal_enables_passing =
|
|
test::bits_to_float("0 00000000 000 0100 0000 0000 0000 0010");
|
|
|
|
// ~3.67342E-40, the exact upper bound
|
|
computed = test::bits_to_float("0 00000000 000 0100 0000 0000 0000 0000");
|
|
EXPECT_TRUE(test::close_f(expected, computed, tolerance_bits));
|
|
EXPECT_TRUE(
|
|
test::all_close_f(vector<float>({expected}), vector<float>({computed}), tolerance_bits));
|
|
|
|
// ~3.67343E-40, the next representable number bigger than upper bound
|
|
computed = test::bits_to_float("0 00000000 000 0100 0000 0000 0000 0001");
|
|
EXPECT_FALSE(test::close_f(expected, computed, tolerance_bits));
|
|
EXPECT_FALSE(test::close_f(expected, computed, tolerance_bits, min_signal_too_low));
|
|
EXPECT_TRUE(test::close_f(expected, computed, tolerance_bits, min_signal_enables_passing));
|
|
EXPECT_FALSE(
|
|
test::all_close_f(vector<float>({expected}), vector<float>({computed}), tolerance_bits));
|
|
EXPECT_FALSE(test::all_close_f(
|
|
vector<float>({expected}), vector<float>({computed}), tolerance_bits, min_signal_too_low));
|
|
EXPECT_TRUE(test::all_close_f(vector<float>({expected}),
|
|
vector<float>({computed}),
|
|
tolerance_bits,
|
|
min_signal_enables_passing));
|
|
|
|
// ~-3.67342E-40, the exact lower bound
|
|
computed = test::bits_to_float("1 00000000 000 0100 0000 0000 0000 0000");
|
|
EXPECT_TRUE(test::close_f(expected, computed, tolerance_bits));
|
|
EXPECT_TRUE(
|
|
test::all_close_f(vector<float>({expected}), vector<float>({computed}), tolerance_bits));
|
|
|
|
// ~-3.67343E-40, the next representable number smaller than lower bound
|
|
computed = test::bits_to_float("1 00000000 000 0100 0000 0000 0000 0001");
|
|
EXPECT_FALSE(test::close_f(expected, computed, tolerance_bits));
|
|
EXPECT_FALSE(test::close_f(expected, computed, tolerance_bits, min_signal_too_low));
|
|
EXPECT_TRUE(test::close_f(expected, computed, tolerance_bits, min_signal_enables_passing));
|
|
EXPECT_FALSE(
|
|
test::all_close_f(vector<float>({expected}), vector<float>({computed}), tolerance_bits));
|
|
EXPECT_FALSE(test::all_close_f(
|
|
vector<float>({expected}), vector<float>({computed}), tolerance_bits, min_signal_too_low));
|
|
EXPECT_TRUE(test::all_close_f(vector<float>({expected}),
|
|
vector<float>({computed}),
|
|
tolerance_bits,
|
|
min_signal_enables_passing));
|
|
}
|
|
|
|
// Test the exact bounds near 1.f
|
|
//
|
|
// With tolerance_bits = 18
|
|
// (equivalent to testing bfloat precision with 2 bits tolerance)
|
|
//
|
|
// Targeted bit
|
|
// |
|
|
// v
|
|
// 2 3 4 5 6 (error allowed in 6th bit or later, w/ implicit leading bit)
|
|
// s e e e e e e e e m m m m m m m m m m m m m m m m m m m m m m m
|
|
// =>| 8 | (8 w/ implicit leading bit)
|
|
// ^
|
|
// | 2 |<=
|
|
//
|
|
// [Upper bound]
|
|
// Add 1 at this bit to get upper bound
|
|
// |
|
|
// v
|
|
// 0 0 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
|
// + 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
|
// ---------------------------------------------------------------
|
|
// 0 0 1 1 1 1 1 1 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
|
//
|
|
// [Lower bound]
|
|
// Minus 1 at this bit to get lower bound
|
|
// |
|
|
// v
|
|
// 0 0 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
|
// - 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
|
// ---------------------------------------------------------------
|
|
// 0 0 1 1 1 1 1 1 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
|
TEST(all_close_f, mantissa_8_near_1)
|
|
{
|
|
constexpr int tolerance_bits = (FLOAT_MANTISSA_BITS - BFLOAT_MANTISSA_BITS + 2);
|
|
|
|
// 1.f, the ground-truth value
|
|
float expected = test::bits_to_float("0 01111111 000 0000 0000 0000 0000 0000");
|
|
float computed;
|
|
|
|
// 1.03125f, the exact upper bound
|
|
computed = test::bits_to_float("0 01111111 000 0100 0000 0000 0000 0000");
|
|
EXPECT_TRUE(test::close_f(expected, computed, tolerance_bits));
|
|
EXPECT_TRUE(
|
|
test::all_close_f(vector<float>({expected}), vector<float>({computed}), tolerance_bits));
|
|
|
|
// 1.031250119f, the next representable number bigger than upper bound
|
|
computed = test::bits_to_float("0 01111111 000 0100 0000 0000 0000 0001");
|
|
EXPECT_FALSE(test::close_f(expected, computed, tolerance_bits));
|
|
EXPECT_FALSE(
|
|
test::all_close_f(vector<float>({expected}), vector<float>({computed}), tolerance_bits));
|
|
|
|
// 0.984375f, the exact lower bound
|
|
computed = test::bits_to_float("0 01111110 111 1100 0000 0000 0000 0000");
|
|
EXPECT_TRUE(test::close_f(expected, computed, tolerance_bits));
|
|
EXPECT_TRUE(
|
|
test::all_close_f(vector<float>({expected}), vector<float>({computed}), tolerance_bits));
|
|
|
|
// 0.9843749404f, the next representable number smaller than lower bound
|
|
computed = test::bits_to_float("0 01111110 111 1011 1111 1111 1111 1111");
|
|
EXPECT_FALSE(test::close_f(expected, computed, tolerance_bits));
|
|
EXPECT_FALSE(
|
|
test::all_close_f(vector<float>({expected}), vector<float>({computed}), tolerance_bits));
|
|
}
|
|
|
|
// Test the exact bounds near -1.f
|
|
//
|
|
// With tolerance_bits = 18
|
|
// (equivalent to testing bfloat precision with 2 bits tolerance)
|
|
//
|
|
// Targeted bit
|
|
// |
|
|
// v
|
|
// 2 3 4 5 6 (error allowed in 6th bit or later, w/ implicit leading bit)
|
|
// s e e e e e e e e m m m m m m m m m m m m m m m m m m m m m m m
|
|
// =>| 8 | (8 w/ implicit leading bit)
|
|
// ^
|
|
// | 2 |<=
|
|
//
|
|
// [Upper bound]
|
|
// Minus 1 at this bit
|
|
// |
|
|
// v
|
|
// 1 0 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
|
// - 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
|
// ---------------------------------------------------------------
|
|
// 1 0 1 1 1 1 1 1 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
|
//
|
|
// [Lower bound]
|
|
// Add 1 at this bit
|
|
// |
|
|
// v
|
|
// 1 0 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
|
// + 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
|
// ---------------------------------------------------------------
|
|
// 1 0 1 1 1 1 1 1 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
|
TEST(all_close_f, mantissa_8_near_n1)
|
|
{
|
|
constexpr int tolerance_bits = (FLOAT_MANTISSA_BITS - BFLOAT_MANTISSA_BITS + 2);
|
|
|
|
// -1.f, the ground-truth value
|
|
float expected = test::bits_to_float("1 01111111 000 0000 0000 0000 0000 0000");
|
|
float computed;
|
|
|
|
// -0.984375f, the exact upper bound
|
|
computed = test::bits_to_float("1 01111110 111 1100 0000 0000 0000 0000");
|
|
EXPECT_TRUE(test::close_f(expected, computed, tolerance_bits));
|
|
EXPECT_TRUE(
|
|
test::all_close_f(vector<float>({expected}), vector<float>({computed}), tolerance_bits));
|
|
|
|
// -0.984374940395355224609375f, the next representable number bigger than upper bound
|
|
computed = test::bits_to_float("1 01111110 111 1011 1111 1111 1111 1111");
|
|
EXPECT_FALSE(test::close_f(expected, computed, tolerance_bits));
|
|
EXPECT_FALSE(
|
|
test::all_close_f(vector<float>({expected}), vector<float>({computed}), tolerance_bits));
|
|
|
|
// -1.03125f, the exact lower bound
|
|
computed = test::bits_to_float("1 01111111 000 0100 0000 0000 0000 0000");
|
|
EXPECT_TRUE(test::close_f(expected, computed, tolerance_bits));
|
|
EXPECT_TRUE(
|
|
test::all_close_f(vector<float>({expected}), vector<float>({computed}), tolerance_bits));
|
|
|
|
// -1.03125011920928955078125f, the next representable number smaller than lower bound
|
|
computed = test::bits_to_float("1 01111111 000 0100 0000 0000 0000 0001");
|
|
EXPECT_FALSE(test::close_f(expected, computed, tolerance_bits));
|
|
EXPECT_FALSE(
|
|
test::all_close_f(vector<float>({expected}), vector<float>({computed}), tolerance_bits));
|
|
}
|
|
|
|
// For intuitive understanding of tightness of bounds in decimal
|
|
// Test bounds near 0, 1, 10, 100, 1000 with tolerance_bits = 18
|
|
//
|
|
// Targeted bit
|
|
// |
|
|
// v
|
|
// 2 3 4 5 6 (error allowed in 6th bit or later, w/ implicit leading bit)
|
|
// s e e e e e e e e m m m m m m m m m m m m m m m m m m m m m m m
|
|
// =>| 8 | (8 w/ implicit leading bit)
|
|
// ^
|
|
// | 2 |<=
|
|
TEST(all_close_f, mantissa_8_near_0_1_10_100_1000)
|
|
{
|
|
constexpr int tolerance_bits = (FLOAT_MANTISSA_BITS - BFLOAT_MANTISSA_BITS + 2);
|
|
|
|
float expected;
|
|
float upper_bound;
|
|
float bigger_than_upper_bound;
|
|
float lower_bound;
|
|
float smaller_than_lower_bound;
|
|
|
|
// Bounds around 0: 0 +- 3.67e-40
|
|
expected = 0.f; // 0 00000000 000 0000 0000 0000 0000 0000
|
|
upper_bound = 3.67342e-40f; // 0 00000000 000 0100 0000 0000 0000 0000, approximated
|
|
bigger_than_upper_bound =
|
|
3.67343e-40f; // 0 00000000 000 0100 0000 0000 0000 0001, approximated
|
|
lower_bound = -3.67342e-40f; // 1 00000000 000 0100 0000 0000 0000 0000, approximated
|
|
smaller_than_lower_bound =
|
|
3.67343e-40f; // 1 00000000 000 0100 0000 0000 0000 0001, approximated
|
|
EXPECT_TRUE(test::close_f(expected, upper_bound, tolerance_bits));
|
|
EXPECT_TRUE(
|
|
test::all_close_f(vector<float>({expected}), vector<float>({upper_bound}), tolerance_bits));
|
|
EXPECT_FALSE(test::close_f(expected, bigger_than_upper_bound, tolerance_bits));
|
|
EXPECT_FALSE(test::all_close_f(
|
|
vector<float>({expected}), vector<float>({bigger_than_upper_bound}), tolerance_bits));
|
|
EXPECT_TRUE(test::close_f(expected, lower_bound, tolerance_bits));
|
|
EXPECT_TRUE(
|
|
test::all_close_f(vector<float>({expected}), vector<float>({lower_bound}), tolerance_bits));
|
|
EXPECT_FALSE(test::close_f(expected, smaller_than_lower_bound, tolerance_bits));
|
|
EXPECT_FALSE(test::all_close_f(
|
|
vector<float>({expected}), vector<float>({smaller_than_lower_bound}), tolerance_bits));
|
|
|
|
// Bounds around 1: 1 +- 0.03
|
|
expected = 1.f; // 0 01111111 000 0000 0000 0000 0000 0000
|
|
upper_bound = 1.03125f; // 0 01111111 000 0100 0000 0000 0000 0000
|
|
bigger_than_upper_bound = 1.031250119f; // 0 01111111 000 0100 0000 0000 0000 0001
|
|
lower_bound = 0.984375f; // 0 01111110 111 1100 0000 0000 0000 0000
|
|
smaller_than_lower_bound = 0.9843749404f; // 0 01111110 111 1011 1111 1111 1111 1111
|
|
EXPECT_TRUE(test::close_f(expected, upper_bound, tolerance_bits));
|
|
EXPECT_TRUE(
|
|
test::all_close_f(vector<float>({expected}), vector<float>({upper_bound}), tolerance_bits));
|
|
EXPECT_FALSE(test::close_f(expected, bigger_than_upper_bound, tolerance_bits));
|
|
EXPECT_FALSE(test::all_close_f(
|
|
vector<float>({expected}), vector<float>({bigger_than_upper_bound}), tolerance_bits));
|
|
EXPECT_TRUE(test::close_f(expected, lower_bound, tolerance_bits));
|
|
EXPECT_TRUE(
|
|
test::all_close_f(vector<float>({expected}), vector<float>({lower_bound}), tolerance_bits));
|
|
EXPECT_FALSE(test::close_f(expected, smaller_than_lower_bound, tolerance_bits));
|
|
EXPECT_FALSE(test::all_close_f(
|
|
vector<float>({expected}), vector<float>({smaller_than_lower_bound}), tolerance_bits));
|
|
|
|
// Bounds around 10: 10 +- 0.25
|
|
expected = 10.f; // 0 10000010 010 0000 0000 0000 0000 0000
|
|
upper_bound = 10.25f; // 0 10000010 010 0100 0000 0000 0000 0000
|
|
bigger_than_upper_bound = 10.25000095367431640625f; // 0 10000010 010 0100 0000 0000 0000 0001
|
|
lower_bound = 9.75f; // 0 10000010 001 1100 0000 0000 0000 0000
|
|
smaller_than_lower_bound = 9.74999904632568359375f; // 0 10000010 001 1011 1111 1111 1111 1111
|
|
EXPECT_TRUE(test::close_f(expected, upper_bound, tolerance_bits));
|
|
EXPECT_TRUE(
|
|
test::all_close_f(vector<float>({expected}), vector<float>({upper_bound}), tolerance_bits));
|
|
EXPECT_FALSE(test::close_f(expected, bigger_than_upper_bound, tolerance_bits));
|
|
EXPECT_FALSE(test::all_close_f(
|
|
vector<float>({expected}), vector<float>({bigger_than_upper_bound}), tolerance_bits));
|
|
EXPECT_TRUE(test::close_f(expected, lower_bound, tolerance_bits));
|
|
EXPECT_TRUE(
|
|
test::all_close_f(vector<float>({expected}), vector<float>({lower_bound}), tolerance_bits));
|
|
EXPECT_FALSE(test::close_f(expected, smaller_than_lower_bound, tolerance_bits));
|
|
EXPECT_FALSE(test::all_close_f(
|
|
vector<float>({expected}), vector<float>({smaller_than_lower_bound}), tolerance_bits));
|
|
|
|
// Bounds around 100: 100 +- 2
|
|
expected = 100.f; // 0 10000101 100 1000 0000 0000 0000 0000
|
|
upper_bound = 102.f; // 0 10000101 100 1100 0000 0000 0000 0000
|
|
bigger_than_upper_bound = 102.00000762939453125f; // 0 10000101 100 1100 0000 0000 0000 0001
|
|
lower_bound = 98.0f; // 0 10000101 100 0100 0000 0000 0000 0000
|
|
smaller_than_lower_bound = 97.99999237060546875f; // 0 10000101 100 0011 1111 1111 1111 1111
|
|
EXPECT_TRUE(test::close_f(expected, upper_bound, tolerance_bits));
|
|
EXPECT_TRUE(
|
|
test::all_close_f(vector<float>({expected}), vector<float>({upper_bound}), tolerance_bits));
|
|
EXPECT_FALSE(test::close_f(expected, bigger_than_upper_bound, tolerance_bits));
|
|
EXPECT_FALSE(test::all_close_f(
|
|
vector<float>({expected}), vector<float>({bigger_than_upper_bound}), tolerance_bits));
|
|
EXPECT_TRUE(test::close_f(expected, lower_bound, tolerance_bits));
|
|
EXPECT_TRUE(
|
|
test::all_close_f(vector<float>({expected}), vector<float>({lower_bound}), tolerance_bits));
|
|
EXPECT_FALSE(test::close_f(expected, smaller_than_lower_bound, tolerance_bits));
|
|
EXPECT_FALSE(test::all_close_f(
|
|
vector<float>({expected}), vector<float>({smaller_than_lower_bound}), tolerance_bits));
|
|
|
|
// Bounds around 1000: 1000 +- 16
|
|
expected = 1000.f; // 0 10001000 111 1010 0000 0000 0000 0000
|
|
upper_bound = 1016.f; // 0 10001000 111 1110 0000 0000 0000 0000
|
|
bigger_than_upper_bound = 1016.00006103515625f; // 0 10001000 111 1110 0000 0000 0000 0001
|
|
lower_bound = 984.0f; // 0 10001000 111 0110 0000 0000 0000 0000
|
|
smaller_than_lower_bound = 983.99993896484375f; // 0 10001000 111 0101 1111 1111 1111 1111
|
|
EXPECT_TRUE(test::close_f(expected, upper_bound, tolerance_bits));
|
|
EXPECT_TRUE(
|
|
test::all_close_f(vector<float>({expected}), vector<float>({upper_bound}), tolerance_bits));
|
|
EXPECT_FALSE(test::close_f(expected, bigger_than_upper_bound, tolerance_bits));
|
|
EXPECT_FALSE(test::all_close_f(
|
|
vector<float>({expected}), vector<float>({bigger_than_upper_bound}), tolerance_bits));
|
|
EXPECT_TRUE(test::close_f(expected, lower_bound, tolerance_bits));
|
|
EXPECT_TRUE(
|
|
test::all_close_f(vector<float>({expected}), vector<float>({lower_bound}), tolerance_bits));
|
|
EXPECT_FALSE(test::close_f(expected, smaller_than_lower_bound, tolerance_bits));
|
|
EXPECT_FALSE(test::all_close_f(
|
|
vector<float>({expected}), vector<float>({smaller_than_lower_bound}), tolerance_bits));
|
|
}
|
|
|
|
// For intuitive understanding of tightness of bounds in decimal
|
|
// Test bounds near 0, 1, 10, 100, 1000 with tolerance_bits = 2
|
|
//
|
|
// Targeted bit
|
|
// |
|
|
// (22 bits must match, w/ implicit leading bit) v
|
|
// 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2
|
|
// s e e e e e e e e m m m m m m m m m m m m m m m m m m m m m m m
|
|
// =>| 24 (w/ implicit leading bit) |
|
|
// ^
|
|
// | 2 |<=
|
|
TEST(all_close_f, mantissa_24_near_0_1_10_100_1000)
|
|
{
|
|
constexpr int tolerance_bits = 2;
|
|
|
|
float expected;
|
|
float upper_bound;
|
|
float bigger_than_upper_bound;
|
|
float lower_bound;
|
|
float smaller_than_lower_bound;
|
|
|
|
// Bounds around 0: 0 +- 5.6e-45
|
|
expected = 0.f;
|
|
upper_bound = test::bits_to_float("0 00000000 000 0000 0000 0000 0000 0100");
|
|
bigger_than_upper_bound = test::bits_to_float("0 00000000 000 0000 0000 0000 0000 0101");
|
|
lower_bound = test::bits_to_float("1 00000000 000 0000 0000 0000 0000 0100");
|
|
smaller_than_lower_bound = test::bits_to_float("1 00000000 000 0000 0000 0000 0000 0101");
|
|
EXPECT_TRUE(test::close_f(expected, upper_bound, tolerance_bits));
|
|
EXPECT_TRUE(
|
|
test::all_close_f(vector<float>({expected}), vector<float>({upper_bound}), tolerance_bits));
|
|
EXPECT_FALSE(test::close_f(expected, bigger_than_upper_bound, tolerance_bits));
|
|
EXPECT_FALSE(test::all_close_f(
|
|
vector<float>({expected}), vector<float>({bigger_than_upper_bound}), tolerance_bits));
|
|
EXPECT_TRUE(test::close_f(expected, lower_bound, tolerance_bits));
|
|
EXPECT_TRUE(
|
|
test::all_close_f(vector<float>({expected}), vector<float>({lower_bound}), tolerance_bits));
|
|
EXPECT_FALSE(test::close_f(expected, smaller_than_lower_bound, tolerance_bits));
|
|
EXPECT_FALSE(test::all_close_f(
|
|
vector<float>({expected}), vector<float>({smaller_than_lower_bound}), tolerance_bits));
|
|
|
|
// Bounds around 1: 1 +- 4.77e-7
|
|
expected = 1.f;
|
|
upper_bound = test::bits_to_float("0 01111111 000 0000 0000 0000 0000 0100");
|
|
bigger_than_upper_bound = test::bits_to_float("0 01111111 000 0000 0000 0000 0000 0101");
|
|
lower_bound = test::bits_to_float("0 01111110 111 1111 1111 1111 1111 1100");
|
|
smaller_than_lower_bound = test::bits_to_float("0 01111110 111 1111 1111 1111 1111 1011");
|
|
EXPECT_TRUE(test::close_f(expected, upper_bound, tolerance_bits));
|
|
EXPECT_TRUE(
|
|
test::all_close_f(vector<float>({expected}), vector<float>({upper_bound}), tolerance_bits));
|
|
EXPECT_FALSE(test::close_f(expected, bigger_than_upper_bound, tolerance_bits));
|
|
EXPECT_FALSE(test::all_close_f(
|
|
vector<float>({expected}), vector<float>({bigger_than_upper_bound}), tolerance_bits));
|
|
EXPECT_TRUE(test::close_f(expected, lower_bound, tolerance_bits));
|
|
EXPECT_TRUE(
|
|
test::all_close_f(vector<float>({expected}), vector<float>({lower_bound}), tolerance_bits));
|
|
EXPECT_FALSE(test::close_f(expected, smaller_than_lower_bound, tolerance_bits));
|
|
EXPECT_FALSE(test::all_close_f(
|
|
vector<float>({expected}), vector<float>({smaller_than_lower_bound}), tolerance_bits));
|
|
|
|
// Bounds around 10: 10 +- 3.81e-6
|
|
expected = 10.f;
|
|
upper_bound = test::bits_to_float("0 10000010 010 0000 0000 0000 0000 0100");
|
|
bigger_than_upper_bound = test::bits_to_float("0 10000010 010 0000 0000 0000 0000 0101");
|
|
lower_bound = test::bits_to_float("0 10000010 001 1111 1111 1111 1111 1100");
|
|
smaller_than_lower_bound = test::bits_to_float("0 10000010 001 1111 1111 1111 1111 1011");
|
|
EXPECT_TRUE(test::close_f(expected, upper_bound, tolerance_bits));
|
|
EXPECT_TRUE(
|
|
test::all_close_f(vector<float>({expected}), vector<float>({upper_bound}), tolerance_bits));
|
|
EXPECT_FALSE(test::close_f(expected, bigger_than_upper_bound, tolerance_bits));
|
|
EXPECT_FALSE(test::all_close_f(
|
|
vector<float>({expected}), vector<float>({bigger_than_upper_bound}), tolerance_bits));
|
|
EXPECT_TRUE(test::close_f(expected, lower_bound, tolerance_bits));
|
|
EXPECT_TRUE(
|
|
test::all_close_f(vector<float>({expected}), vector<float>({lower_bound}), tolerance_bits));
|
|
EXPECT_FALSE(test::close_f(expected, smaller_than_lower_bound, tolerance_bits));
|
|
EXPECT_FALSE(test::all_close_f(
|
|
vector<float>({expected}), vector<float>({smaller_than_lower_bound}), tolerance_bits));
|
|
|
|
// Bounds around 100: 100 +- 3.05e-5
|
|
expected = 100.f;
|
|
upper_bound = test::bits_to_float("0 10000101 100 1000 0000 0000 0000 0100");
|
|
bigger_than_upper_bound = test::bits_to_float("0 10000101 100 1000 0000 0000 0000 0101");
|
|
lower_bound = test::bits_to_float("0 10000101 100 0111 1111 1111 1111 1100");
|
|
smaller_than_lower_bound = test::bits_to_float("0 10000101 100 0111 1111 1111 1111 1011");
|
|
EXPECT_TRUE(test::close_f(expected, upper_bound, tolerance_bits));
|
|
EXPECT_TRUE(
|
|
test::all_close_f(vector<float>({expected}), vector<float>({upper_bound}), tolerance_bits));
|
|
EXPECT_FALSE(test::close_f(expected, bigger_than_upper_bound, tolerance_bits));
|
|
EXPECT_FALSE(test::all_close_f(
|
|
vector<float>({expected}), vector<float>({bigger_than_upper_bound}), tolerance_bits));
|
|
EXPECT_TRUE(test::close_f(expected, lower_bound, tolerance_bits));
|
|
EXPECT_TRUE(
|
|
test::all_close_f(vector<float>({expected}), vector<float>({lower_bound}), tolerance_bits));
|
|
EXPECT_FALSE(test::close_f(expected, smaller_than_lower_bound, tolerance_bits));
|
|
EXPECT_FALSE(test::all_close_f(
|
|
vector<float>({expected}), vector<float>({smaller_than_lower_bound}), tolerance_bits));
|
|
|
|
// Bounds around 1000: 1000 +- 2.44e-4
|
|
expected = 1000.f;
|
|
upper_bound = test::bits_to_float("0 10001000 111 1010 0000 0000 0000 0100");
|
|
bigger_than_upper_bound = test::bits_to_float("0 10001000 111 1010 0000 0000 0000 0101");
|
|
lower_bound = test::bits_to_float("0 10001000 111 1001 1111 1111 1111 1100");
|
|
smaller_than_lower_bound = test::bits_to_float("0 10001000 111 1001 1111 1111 1111 1011");
|
|
EXPECT_TRUE(test::close_f(expected, upper_bound, tolerance_bits));
|
|
EXPECT_TRUE(
|
|
test::all_close_f(vector<float>({expected}), vector<float>({upper_bound}), tolerance_bits));
|
|
EXPECT_FALSE(test::close_f(expected, bigger_than_upper_bound, tolerance_bits));
|
|
EXPECT_FALSE(test::all_close_f(
|
|
vector<float>({expected}), vector<float>({bigger_than_upper_bound}), tolerance_bits));
|
|
EXPECT_TRUE(test::close_f(expected, lower_bound, tolerance_bits));
|
|
EXPECT_TRUE(
|
|
test::all_close_f(vector<float>({expected}), vector<float>({lower_bound}), tolerance_bits));
|
|
EXPECT_FALSE(test::close_f(expected, smaller_than_lower_bound, tolerance_bits));
|
|
EXPECT_FALSE(test::all_close_f(
|
|
vector<float>({expected}), vector<float>({smaller_than_lower_bound}), tolerance_bits));
|
|
}
|
|
|
|
TEST(all_close_f, inf_nan)
|
|
{
|
|
float zero = 0.f;
|
|
float infinity = numeric_limits<float>::infinity();
|
|
float neg_infinity = -numeric_limits<float>::infinity();
|
|
float quiet_nan = numeric_limits<float>::quiet_NaN();
|
|
float signaling_nan = numeric_limits<float>::signaling_NaN();
|
|
|
|
EXPECT_FALSE(test::close_f(zero, infinity));
|
|
EXPECT_FALSE(test::all_close_f(vector<float>({zero}), vector<float>({infinity})));
|
|
EXPECT_FALSE(test::close_f(zero, neg_infinity));
|
|
EXPECT_FALSE(test::all_close_f(vector<float>({zero}), vector<float>({neg_infinity})));
|
|
EXPECT_FALSE(test::close_f(zero, quiet_nan));
|
|
EXPECT_FALSE(test::all_close_f(vector<float>({zero}), vector<float>({quiet_nan})));
|
|
EXPECT_FALSE(test::close_f(zero, signaling_nan));
|
|
EXPECT_FALSE(test::all_close_f(vector<float>({zero}), vector<float>({signaling_nan})));
|
|
|
|
EXPECT_TRUE(test::close_f(infinity, infinity));
|
|
EXPECT_TRUE(test::all_close_f(vector<float>({infinity}), vector<float>({infinity})));
|
|
EXPECT_TRUE(test::close_f(neg_infinity, neg_infinity));
|
|
EXPECT_TRUE(test::all_close_f(vector<float>({neg_infinity}), vector<float>({neg_infinity})));
|
|
EXPECT_TRUE(test::close_f(quiet_nan, quiet_nan));
|
|
EXPECT_TRUE(test::all_close_f(vector<float>({quiet_nan}), vector<float>({quiet_nan})));
|
|
EXPECT_TRUE(test::close_f(signaling_nan, signaling_nan));
|
|
EXPECT_TRUE(test::all_close_f(vector<float>({signaling_nan}), vector<float>({signaling_nan})));
|
|
}
|
|
|
|
TEST(all_close_f, double_inf_nan)
|
|
{
|
|
double zero = 0;
|
|
double infinity = numeric_limits<double>::infinity();
|
|
double neg_infinity = -numeric_limits<double>::infinity();
|
|
double quiet_nan = numeric_limits<double>::quiet_NaN();
|
|
double signaling_nan = numeric_limits<double>::signaling_NaN();
|
|
|
|
EXPECT_FALSE(test::close_f(zero, infinity));
|
|
EXPECT_FALSE(test::all_close_f(vector<double>({zero}), vector<double>({infinity})));
|
|
EXPECT_FALSE(test::close_f(zero, neg_infinity));
|
|
EXPECT_FALSE(test::all_close_f(vector<double>({zero}), vector<double>({neg_infinity})));
|
|
EXPECT_FALSE(test::close_f(zero, quiet_nan));
|
|
EXPECT_FALSE(test::all_close_f(vector<double>({zero}), vector<double>({quiet_nan})));
|
|
EXPECT_FALSE(test::close_f(zero, signaling_nan));
|
|
EXPECT_FALSE(test::all_close_f(vector<double>({zero}), vector<double>({signaling_nan})));
|
|
|
|
EXPECT_TRUE(test::close_f(infinity, infinity));
|
|
EXPECT_TRUE(test::all_close_f(vector<double>({infinity}), vector<double>({infinity})));
|
|
EXPECT_TRUE(test::close_f(neg_infinity, neg_infinity));
|
|
EXPECT_TRUE(test::all_close_f(vector<double>({neg_infinity}), vector<double>({neg_infinity})));
|
|
EXPECT_TRUE(test::close_f(quiet_nan, quiet_nan));
|
|
EXPECT_TRUE(test::all_close_f(vector<double>({quiet_nan}), vector<double>({quiet_nan})));
|
|
EXPECT_TRUE(test::close_f(signaling_nan, signaling_nan));
|
|
EXPECT_TRUE(
|
|
test::all_close_f(vector<double>({signaling_nan}), vector<double>({signaling_nan})));
|
|
}
|