#define GEMMLOWP_ENABLE_FIXEDPOINT_CONSTANTS_CHECKS #include "test.h" #include "../internal/fixedpoint.h" using namespace gemmlowp; template <int tIntegerBits> void test_convert(FixedPoint<int32_t, tIntegerBits> x) { typedef FixedPoint<int32_t, tIntegerBits> F; F y = ToFixedPoint<int32_t, tIntegerBits>(ToDouble(x)); Check(y == x); } template <int tIntegerBits_a, int tIntegerBits_b> void test_Rescale(FixedPoint<int32_t, tIntegerBits_a> a) { FixedPoint<int32_t, tIntegerBits_b> actual = Rescale<tIntegerBits_b>(a); FixedPoint<int32_t, tIntegerBits_b> expected = ToFixedPoint<int32_t, tIntegerBits_b>(ToDouble(a)); Check(actual == expected); } template <int tIntegerBits_a, int tIntegerBits_b> void test_Rescale(const std::vector<int32_t>& testvals_int32) { for (auto a : testvals_int32) { FixedPoint<int32_t, tIntegerBits_a> aq; aq.raw() = a; test_Rescale<tIntegerBits_a, tIntegerBits_b>(aq); } } template <int tIntegerBits_a, int tIntegerBits_b> void test_mul(FixedPoint<int32_t, tIntegerBits_a> a, FixedPoint<int32_t, tIntegerBits_b> b) { static const int IntegerBits_ab = tIntegerBits_a + tIntegerBits_b; FixedPoint<int32_t, IntegerBits_ab> ab; ab = a * b; double a_double = ToDouble(a); double b_double = ToDouble(b); double ab_double = a_double * b_double; FixedPoint<int32_t, IntegerBits_ab> expected = ToFixedPoint<int32_t, IntegerBits_ab>(ab_double); int64_t diff = int64_t(ab.raw()) - int64_t(expected.raw()); Check(std::abs(diff) <= 1); } template <int tIntegerBits_a, int tIntegerBits_b> void test_mul(const std::vector<int32_t>& testvals_int32) { for (auto a : testvals_int32) { for (auto b : testvals_int32) { FixedPoint<int32_t, tIntegerBits_a> aq; FixedPoint<int32_t, tIntegerBits_b> bq; aq.raw() = a; bq.raw() = b; test_mul(aq, bq); } } } template <int tExponent, int tIntegerBits_a> void test_ExactMulByPot(FixedPoint<int32_t, tIntegerBits_a> a) { double x = ToDouble(a) * std::pow(2.0, tExponent); double y = ToDouble(ExactMulByPot<tExponent>(a)); Check(x == y); } template <int tExponent, int tIntegerBits_a> void test_ExactMulByPot(const std::vector<int32_t>& testvals_int32) { for (auto a : testvals_int32) { FixedPoint<int32_t, tIntegerBits_a> aq; aq.raw() = a; test_ExactMulByPot<tExponent, tIntegerBits_a>(aq); } } void test_exp_on_interval_between_negative_one_quarter_and_0_excl( FixedPoint<int32_t, 0> a) { double a_double = ToDouble(a); double expected = std::exp(a_double); double actual = ToDouble(exp_on_interval_between_negative_one_quarter_and_0_excl(a)); double error = expected - actual; Check(std::abs(error) < 3e-7); } void test_exp_on_interval_between_negative_one_quarter_and_0_excl( const std::vector<int32_t>& testvals_int32) { for (auto a : testvals_int32) { typedef FixedPoint<int32_t, 0> F; F aq = SaturatingRoundingMultiplyByPOT<-3>(F::FromRaw(a)) - F::ConstantPOT<-3>(); test_exp_on_interval_between_negative_one_quarter_and_0_excl(aq); } } template <int tIntegerBits> void test_exp_on_negative_values(FixedPoint<int32_t, tIntegerBits> a) { double a_double = ToDouble(a); double expected = std::exp(a_double); double actual = ToDouble(exp_on_negative_values(a)); double error = expected - actual; Check(std::abs(error) < 3e-7); } template <int tIntegerBits> void test_exp_on_negative_values(const std::vector<int32_t>& testvals_int32) { for (auto a : testvals_int32) { if (a < 0) { FixedPoint<int32_t, tIntegerBits> aq; aq.raw() = a; test_exp_on_negative_values(aq); } } } void test_one_minus_x_over_one_plus_x_for_x_in_0_1(FixedPoint<int32_t, 0> a) { double a_double = ToDouble(a); double expected = (1 - a_double) / (1 + a_double); FixedPoint<int32_t, 0> retval = one_minus_x_over_one_plus_x_for_x_in_0_1(a); double actual = ToDouble(retval); double error = expected - actual; Check(std::abs(error) < 6e-9); } void test_one_minus_x_over_one_plus_x_for_x_in_0_1( const std::vector<int32_t>& testvals_int32) { for (auto a : testvals_int32) { if (a > 0) { FixedPoint<int32_t, 0> aq; aq.raw() = a; test_one_minus_x_over_one_plus_x_for_x_in_0_1(aq); } } } template <int tIntegerBits> void test_tanh(FixedPoint<int32_t, tIntegerBits> a) { double a_double = ToDouble(a); double expected = std::tanh(a_double); double actual = ToDouble(tanh(a)); double error = expected - actual; Check(std::abs(error) < 1.5e-7); } template <int tIntegerBits> void test_tanh(const std::vector<int32_t>& testvals_int32) { for (auto a : testvals_int32) { FixedPoint<int32_t, tIntegerBits> aq; aq.raw() = a; test_tanh(aq); } } #ifdef GEMMLOWP_NEON void test_int32x4(const std::vector<int32_t>& testvals_int32) { size_t n = testvals_int32.size(); size_t n4 = n - (n % 4); std::vector<int32_t> results_int32(n4); std::vector<int32_t> results_int32x4(n4); for (size_t i = 0; i < n4; i++) { results_int32[i] = tanh(FixedPoint<int32_t, 4>::FromRaw(testvals_int32[i])).raw(); } for (size_t i = 0; i < n4; i++) { vst1q_s32( &results_int32x4[i], tanh(FixedPoint<int32x4_t, 4>::FromRaw(vld1q_s32(&testvals_int32[i]))) .raw()); } for (size_t i = 0; i < n4; i++) { Check(results_int32[i] == results_int32x4[i]); } } #endif // GEMMLOWP_NEON int main() { std::vector<int32_t> testvals_int32; for (int i = 0; i < 31; i++) { testvals_int32.push_back((1 << i) - 2); testvals_int32.push_back((1 << i) - 1); testvals_int32.push_back((1 << i)); testvals_int32.push_back((1 << i) + 1); testvals_int32.push_back((1 << i) + 2); testvals_int32.push_back(-(1 << i) - 2); testvals_int32.push_back(-(1 << i) - 1); testvals_int32.push_back(-(1 << i)); testvals_int32.push_back(-(1 << i) + 1); testvals_int32.push_back(-(1 << i) + 2); } testvals_int32.push_back(std::numeric_limits<int32_t>::min()); testvals_int32.push_back(std::numeric_limits<int32_t>::min() + 1); testvals_int32.push_back(std::numeric_limits<int32_t>::min() + 2); testvals_int32.push_back(std::numeric_limits<int32_t>::max() - 2); testvals_int32.push_back(std::numeric_limits<int32_t>::max() - 1); testvals_int32.push_back(std::numeric_limits<int32_t>::max()); uint32_t random = 1; for (int i = 0; i < 1000; i++) { random = random * 1664525 + 1013904223; testvals_int32.push_back(static_cast<int32_t>(random)); } std::sort(testvals_int32.begin(), testvals_int32.end()); for (auto a : testvals_int32) { FixedPoint<int32_t, 4> x; x.raw() = a; test_convert(x); } test_mul<0, 0>(testvals_int32); test_mul<0, 1>(testvals_int32); test_mul<2, 0>(testvals_int32); test_mul<1, 1>(testvals_int32); test_mul<4, 4>(testvals_int32); test_mul<3, 5>(testvals_int32); test_mul<7, 2>(testvals_int32); test_mul<14, 15>(testvals_int32); test_Rescale<0, 0>(testvals_int32); test_Rescale<0, 1>(testvals_int32); test_Rescale<2, 0>(testvals_int32); test_Rescale<4, 4>(testvals_int32); test_Rescale<4, 5>(testvals_int32); test_Rescale<6, 3>(testvals_int32); test_Rescale<13, 9>(testvals_int32); test_ExactMulByPot<0, 0>(testvals_int32); test_ExactMulByPot<0, 4>(testvals_int32); test_ExactMulByPot<1, 4>(testvals_int32); test_ExactMulByPot<3, 2>(testvals_int32); test_ExactMulByPot<-4, 5>(testvals_int32); test_ExactMulByPot<-2, 6>(testvals_int32); test_exp_on_interval_between_negative_one_quarter_and_0_excl(testvals_int32); test_exp_on_negative_values<1>(testvals_int32); test_exp_on_negative_values<2>(testvals_int32); test_exp_on_negative_values<3>(testvals_int32); test_exp_on_negative_values<4>(testvals_int32); test_exp_on_negative_values<5>(testvals_int32); test_exp_on_negative_values<6>(testvals_int32); test_one_minus_x_over_one_plus_x_for_x_in_0_1(testvals_int32); test_tanh<1>(testvals_int32); test_tanh<2>(testvals_int32); test_tanh<3>(testvals_int32); test_tanh<4>(testvals_int32); test_tanh<5>(testvals_int32); test_tanh<6>(testvals_int32); #ifdef GEMMLOWP_NEON test_int32x4(testvals_int32); #endif // GEMMLOWP_NEON std::cerr << "All tests passed." << std::endl; }