#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;
}