#define GEMMLOWP_ENABLE_FIXEDPOINT_CONSTANTS_CHECKS #include "test.h" #include "../internal/fixedpoint.h" using namespace gemmlowp; template void test_convert(FixedPoint x) { typedef FixedPoint F; F y = ToFixedPoint(ToDouble(x)); Check(y == x); } template void test_Rescale(FixedPoint a) { FixedPoint actual = Rescale(a); FixedPoint expected = ToFixedPoint(ToDouble(a)); Check(actual == expected); } template void test_Rescale(const std::vector& testvals_int32) { for (auto a : testvals_int32) { FixedPoint aq; aq.raw() = a; test_Rescale(aq); } } template void test_mul(FixedPoint a, FixedPoint b) { static const int IntegerBits_ab = tIntegerBits_a + tIntegerBits_b; FixedPoint ab; ab = a * b; double a_double = ToDouble(a); double b_double = ToDouble(b); double ab_double = a_double * b_double; FixedPoint expected = ToFixedPoint(ab_double); int64_t diff = int64_t(ab.raw()) - int64_t(expected.raw()); Check(std::abs(diff) <= 1); } template void test_mul(const std::vector& testvals_int32) { for (auto a : testvals_int32) { for (auto b : testvals_int32) { FixedPoint aq; FixedPoint bq; aq.raw() = a; bq.raw() = b; test_mul(aq, bq); } } } template void test_ExactMulByPot(FixedPoint a) { double x = ToDouble(a) * std::pow(2.0, tExponent); double y = ToDouble(ExactMulByPot(a)); Check(x == y); } template void test_ExactMulByPot(const std::vector& testvals_int32) { for (auto a : testvals_int32) { FixedPoint aq; aq.raw() = a; test_ExactMulByPot(aq); } } void test_exp_on_interval_between_negative_one_quarter_and_0_excl( FixedPoint 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& testvals_int32) { for (auto a : testvals_int32) { typedef FixedPoint F; F aq = SaturatingRoundingMultiplyByPOT<-3>(F::FromRaw(a)) - F::ConstantPOT<-3>(); test_exp_on_interval_between_negative_one_quarter_and_0_excl(aq); } } template void test_exp_on_negative_values(FixedPoint 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 void test_exp_on_negative_values(const std::vector& testvals_int32) { for (auto a : testvals_int32) { if (a < 0) { FixedPoint 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 a) { double a_double = ToDouble(a); double expected = (1 - a_double) / (1 + a_double); FixedPoint 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& testvals_int32) { for (auto a : testvals_int32) { if (a > 0) { FixedPoint aq; aq.raw() = a; test_one_minus_x_over_one_plus_x_for_x_in_0_1(aq); } } } template void test_tanh(FixedPoint 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 void test_tanh(const std::vector& testvals_int32) { for (auto a : testvals_int32) { FixedPoint aq; aq.raw() = a; test_tanh(aq); } } #ifdef GEMMLOWP_NEON void test_int32x4(const std::vector& testvals_int32) { size_t n = testvals_int32.size(); size_t n4 = n - (n % 4); std::vector results_int32(n4); std::vector results_int32x4(n4); for (size_t i = 0; i < n4; i++) { results_int32[i] = tanh(FixedPoint::FromRaw(testvals_int32[i])).raw(); } for (size_t i = 0; i < n4; i++) { vst1q_s32( &results_int32x4[i], tanh(FixedPoint::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 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::min()); testvals_int32.push_back(std::numeric_limits::min() + 1); testvals_int32.push_back(std::numeric_limits::min() + 2); testvals_int32.push_back(std::numeric_limits::max() - 2); testvals_int32.push_back(std::numeric_limits::max() - 1); testvals_int32.push_back(std::numeric_limits::max()); uint32_t random = 1; for (int i = 0; i < 1000; i++) { random = random * 1664525 + 1013904223; testvals_int32.push_back(static_cast(random)); } std::sort(testvals_int32.begin(), testvals_int32.end()); for (auto a : testvals_int32) { FixedPoint 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; }