/* Copyright 2017 The TensorFlow Authors. All Rights Reserved.

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 "tensorflow/lite/kernels/internal/quantization_util.h"

#include "tensorflow/lite/micro/testing/micro_test.h"

namespace tflite {
namespace {

template <class FloatIn, class IntOut>
void RunSafeCastTests() {
  const IntOut imax = std::numeric_limits<IntOut>::max();
  TF_LITE_MICRO_EXPECT_GT(imax, 0);
  const IntOut imin = std::numeric_limits<IntOut>::min();
  const bool s = std::numeric_limits<IntOut>::is_signed;
  if (s) {
    TF_LITE_MICRO_EXPECT_LT(static_cast<IntOut>(imin), 0);
  } else {
    TF_LITE_MICRO_EXPECT_EQ(static_cast<IntOut>(0), imin);
  }

  // Some basic tests.
  TF_LITE_MICRO_EXPECT_EQ(SafeCast<IntOut>(static_cast<FloatIn>(0.0)),
                          static_cast<IntOut>(0));
  TF_LITE_MICRO_EXPECT_EQ(SafeCast<IntOut>(static_cast<FloatIn>(-0.0)),
                          static_cast<IntOut>(0));
  TF_LITE_MICRO_EXPECT_EQ(SafeCast<IntOut>(static_cast<FloatIn>(0.99)),
                          static_cast<IntOut>(0));
  TF_LITE_MICRO_EXPECT_EQ(SafeCast<IntOut>(static_cast<FloatIn>(1.0)),
                          static_cast<IntOut>(1));
  TF_LITE_MICRO_EXPECT_EQ(SafeCast<IntOut>(static_cast<FloatIn>(1.01)),
                          static_cast<IntOut>(1));
  TF_LITE_MICRO_EXPECT_EQ(SafeCast<IntOut>(static_cast<FloatIn>(1.99)),
                          static_cast<IntOut>(1));
  TF_LITE_MICRO_EXPECT_EQ(SafeCast<IntOut>(static_cast<FloatIn>(2.0)),
                          static_cast<IntOut>(2));
  TF_LITE_MICRO_EXPECT_EQ(SafeCast<IntOut>(static_cast<FloatIn>(2.01)),
                          static_cast<IntOut>(2));
  TF_LITE_MICRO_EXPECT_EQ(SafeCast<IntOut>(static_cast<FloatIn>(-0.99)),
                          static_cast<IntOut>(0));
  TF_LITE_MICRO_EXPECT_EQ(SafeCast<IntOut>(static_cast<FloatIn>(-1.0)),
                          s ? static_cast<IntOut>(-1) : static_cast<IntOut>(0));
  TF_LITE_MICRO_EXPECT_EQ(SafeCast<IntOut>(static_cast<FloatIn>(-1.01)),
                          s ? static_cast<IntOut>(-1) : static_cast<IntOut>(0));
  TF_LITE_MICRO_EXPECT_EQ(SafeCast<IntOut>(static_cast<FloatIn>(-1.99)),
                          s ? static_cast<IntOut>(-1) : static_cast<IntOut>(0));
  TF_LITE_MICRO_EXPECT_EQ(SafeCast<IntOut>(static_cast<FloatIn>(-2.0)),
                          s ? static_cast<IntOut>(-2) : static_cast<IntOut>(0));
  TF_LITE_MICRO_EXPECT_EQ(SafeCast<IntOut>(static_cast<FloatIn>(-2.01)),
                          s ? static_cast<IntOut>(-2) : static_cast<IntOut>(0));
  TF_LITE_MICRO_EXPECT_EQ(SafeCast<IntOut>(static_cast<FloatIn>(117.9)),
                          static_cast<IntOut>(117));
  TF_LITE_MICRO_EXPECT_EQ(SafeCast<IntOut>(static_cast<FloatIn>(118.0)),
                          static_cast<IntOut>(118));
  TF_LITE_MICRO_EXPECT_EQ(SafeCast<IntOut>(static_cast<FloatIn>(118.1)),
                          static_cast<IntOut>(118));
  TF_LITE_MICRO_EXPECT_EQ(
      SafeCast<IntOut>(static_cast<FloatIn>(-117.9)),
      s ? static_cast<IntOut>(-117) : static_cast<IntOut>(0));
  TF_LITE_MICRO_EXPECT_EQ(
      SafeCast<IntOut>(static_cast<FloatIn>(-118.0)),
      s ? static_cast<IntOut>(-118) : static_cast<IntOut>(0));
  TF_LITE_MICRO_EXPECT_EQ(
      SafeCast<IntOut>(static_cast<FloatIn>(-118.1)),
      s ? static_cast<IntOut>(-118) : static_cast<IntOut>(0));

  // Some edge cases.
  TF_LITE_MICRO_EXPECT_EQ(SafeCast<IntOut>(std::numeric_limits<FloatIn>::max()),
                          imax);
  TF_LITE_MICRO_EXPECT_EQ(
      SafeCast<IntOut>(std::numeric_limits<FloatIn>::lowest()), imin);
  TF_LITE_MICRO_EXPECT_EQ(
      SafeCast<IntOut>(std::numeric_limits<FloatIn>::infinity()), imax);
  TF_LITE_MICRO_EXPECT_EQ(
      SafeCast<IntOut>(-std::numeric_limits<FloatIn>::infinity()), imin);
  TF_LITE_MICRO_EXPECT_EQ(
      SafeCast<IntOut>(std::numeric_limits<FloatIn>::quiet_NaN()),
      static_cast<IntOut>(0));

  // Some larger numbers.
  if (sizeof(IntOut) >= static_cast<size_t>(4) &&
      sizeof(FloatIn) > static_cast<size_t>(4)) {
    TF_LITE_MICRO_EXPECT_EQ(SafeCast<IntOut>(static_cast<FloatIn>(0x76543210)),
                            static_cast<IntOut>(0x76543210));
  }

  if (sizeof(FloatIn) > sizeof(IntOut)) {
    // Check values near imax.
    TF_LITE_MICRO_EXPECT_EQ(
        SafeCast<IntOut>(static_cast<FloatIn>(static_cast<FloatIn>(imax) +
                                              static_cast<FloatIn>(0.1))),
        imax);
    TF_LITE_MICRO_EXPECT_EQ(
        SafeCast<IntOut>(static_cast<FloatIn>(static_cast<FloatIn>(imax) +
                                              static_cast<FloatIn>(0.99))),
        imax);
    TF_LITE_MICRO_EXPECT_EQ(
        SafeCast<IntOut>(static_cast<FloatIn>(static_cast<FloatIn>(imax) +
                                              static_cast<FloatIn>(1.0))),
        imax);
    TF_LITE_MICRO_EXPECT_EQ(
        SafeCast<IntOut>(static_cast<FloatIn>(static_cast<FloatIn>(imax) +
                                              static_cast<FloatIn>(1.99))),
        imax);
    TF_LITE_MICRO_EXPECT_EQ(
        SafeCast<IntOut>(static_cast<FloatIn>(static_cast<FloatIn>(imax) +
                                              static_cast<FloatIn>(2.0))),
        imax);
    TF_LITE_MICRO_EXPECT_EQ(
        SafeCast<IntOut>(static_cast<FloatIn>(static_cast<FloatIn>(imax) -
                                              static_cast<FloatIn>(0.1))),
        imax - 1);
    TF_LITE_MICRO_EXPECT_EQ(
        SafeCast<IntOut>(static_cast<FloatIn>(static_cast<FloatIn>(imax) -
                                              static_cast<FloatIn>(0.99))),
        imax - 1);
    TF_LITE_MICRO_EXPECT_EQ(
        SafeCast<IntOut>(static_cast<FloatIn>(static_cast<FloatIn>(imax) -
                                              static_cast<FloatIn>(1.0))),
        imax - 1);
    TF_LITE_MICRO_EXPECT_EQ(
        SafeCast<IntOut>(static_cast<FloatIn>(static_cast<FloatIn>(imax) -
                                              static_cast<FloatIn>(1.01))),
        imax - 2);
    TF_LITE_MICRO_EXPECT_EQ(
        SafeCast<IntOut>(static_cast<FloatIn>(static_cast<FloatIn>(imax) -
                                              static_cast<FloatIn>(1.99))),
        imax - 2);
    TF_LITE_MICRO_EXPECT_EQ(
        SafeCast<IntOut>(static_cast<FloatIn>(static_cast<FloatIn>(imax) -
                                              static_cast<FloatIn>(2.0))),
        imax - 2);
    TF_LITE_MICRO_EXPECT_EQ(
        SafeCast<IntOut>(static_cast<FloatIn>(static_cast<FloatIn>(imax) -
                                              static_cast<FloatIn>(2.01))),
        imax - 3);
  }

  // Check values considerably larger in magnitude than imin and imax
  TF_LITE_MICRO_EXPECT_EQ(
      SafeCast<IntOut>(static_cast<FloatIn>(static_cast<FloatIn>(imax) * 2)),
      imax);
  TF_LITE_MICRO_EXPECT_EQ(
      SafeCast<IntOut>(static_cast<FloatIn>(static_cast<FloatIn>(imax) * 20)),
      imax);
  TF_LITE_MICRO_EXPECT_EQ(
      SafeCast<IntOut>(static_cast<FloatIn>(static_cast<FloatIn>(imax) * 100)),
      imax);
  TF_LITE_MICRO_EXPECT_EQ(
      SafeCast<IntOut>(static_cast<FloatIn>(static_cast<FloatIn>(imin) * 2)),
      imin);
  TF_LITE_MICRO_EXPECT_EQ(
      SafeCast<IntOut>(static_cast<FloatIn>(static_cast<FloatIn>(imin) * 20)),
      imin);
  TF_LITE_MICRO_EXPECT_EQ(
      SafeCast<IntOut>(static_cast<FloatIn>(static_cast<FloatIn>(imin) * 100)),
      imin);
}

}  // namespace
}  // namespace tflite

TF_LITE_MICRO_TESTS_BEGIN

TF_LITE_MICRO_TEST(QuantizationUtilTest_SafeCast) {
  tflite::RunSafeCastTests<float, int8_t>();
  tflite::RunSafeCastTests<double, int8_t>();
  tflite::RunSafeCastTests<float, int16_t>();
  tflite::RunSafeCastTests<double, int16_t>();
  tflite::RunSafeCastTests<float, int32_t>();
  tflite::RunSafeCastTests<double, int32_t>();
  tflite::RunSafeCastTests<float, int64_t>();
  tflite::RunSafeCastTests<double, int64_t>();
  tflite::RunSafeCastTests<float, uint8_t>();
  tflite::RunSafeCastTests<double, uint8_t>();
  tflite::RunSafeCastTests<float, uint16_t>();
  tflite::RunSafeCastTests<double, uint16_t>();
  tflite::RunSafeCastTests<float, uint32_t>();
  tflite::RunSafeCastTests<double, uint32_t>();
  tflite::RunSafeCastTests<float, uint64_t>();
  tflite::RunSafeCastTests<double, uint64_t>();
}

// Example taken from http://www.tensorflow.org/performance/quantization
//
//  Quantized | Float
//  --------- | -----
//  0         | -10.0
//  255       | 30.0
//  128       | 10.0
TF_LITE_MICRO_TEST(QuantizationUtilTest_ChooseQuantizationParams) {
  tflite::QuantizationParams qp =
      tflite::ChooseQuantizationParams<uint8_t>(-10.0, 30.0);
  TF_LITE_MICRO_EXPECT_NEAR(qp.scale, 0.156863, 1e-5);
  TF_LITE_MICRO_EXPECT_EQ(qp.zero_point, 64);
}

TF_LITE_MICRO_TEST(
    QuantizationUtilTest_ChooseQuantizationParamsZeroPointOnMinBoundary) {
  tflite::QuantizationParams qp =
      tflite::ChooseQuantizationParams<uint8_t>(0.0, 30.0);
  TF_LITE_MICRO_EXPECT_NEAR(qp.scale, 0.117647, 1e-5);
  TF_LITE_MICRO_EXPECT_EQ(qp.zero_point, 0);
}

TF_LITE_MICRO_TEST(
    QuantizationUtilTest_ChooseQuantizationParamsEmptyRangeZero) {
  tflite::QuantizationParams qp =
      tflite::ChooseQuantizationParams<uint8_t>(0.0, 0.0);
  TF_LITE_MICRO_EXPECT_NEAR(qp.scale, 0.0, 1e-5);
  TF_LITE_MICRO_EXPECT_EQ(qp.zero_point, 0);
}

TF_LITE_MICRO_TEST(
    QuantizationUtilTest_ChooseQuantizationParamsZeroPointOnMaxBoundary) {
  tflite::QuantizationParams qp =
      tflite::ChooseQuantizationParams<uint8_t>(-10.0, 0.0);
  TF_LITE_MICRO_EXPECT_NEAR(qp.scale, 0.039216, 1e-5);
  TF_LITE_MICRO_EXPECT_EQ(qp.zero_point, 255);
}

TF_LITE_MICRO_TEST(QuantizationUtilTest_IntegerFrExp) {
  int shift;
  int64_t result = tflite::IntegerFrExp(0.0, &shift);
  TF_LITE_MICRO_EXPECT_EQ(0, result);
  TF_LITE_MICRO_EXPECT_EQ(0, shift);

  result = tflite::IntegerFrExp(1.0, &shift);
  TF_LITE_MICRO_EXPECT_NEAR(0x40000000, result, 1ll);
  TF_LITE_MICRO_EXPECT_EQ(1, shift);

  result = tflite::IntegerFrExp(0.25, &shift);
  TF_LITE_MICRO_EXPECT_NEAR(0x40000000, result, 1ll);
  TF_LITE_MICRO_EXPECT_EQ(-1, shift);

  result = tflite::IntegerFrExp(-1.0, &shift);
  TF_LITE_MICRO_EXPECT_NEAR(-(1 << 30), result, 1ll);
  TF_LITE_MICRO_EXPECT_EQ(1, shift);

  result = tflite::IntegerFrExp(123.45, &shift);
  TF_LITE_MICRO_EXPECT_NEAR(2071147315, result, 1ll);
  TF_LITE_MICRO_EXPECT_EQ(7, shift);

  result = tflite::IntegerFrExp(static_cast<double>(NAN), &shift);
  TF_LITE_MICRO_EXPECT_NEAR(0, result, 1);
  TF_LITE_MICRO_EXPECT_EQ(0x7fffffff, shift);

  result = tflite::IntegerFrExp(static_cast<double>(INFINITY), &shift);
  TF_LITE_MICRO_EXPECT_NEAR(std::numeric_limits<int64_t>::max(), result, 1);
  TF_LITE_MICRO_EXPECT_EQ(0x7fffffff, shift);

  result = tflite::IntegerFrExp(-static_cast<double>(INFINITY), &shift);
  TF_LITE_MICRO_EXPECT_NEAR(std::numeric_limits<int64_t>::min(), result, 1);
  TF_LITE_MICRO_EXPECT_EQ(0x7fffffff, shift);
}

TF_LITE_MICRO_TEST(QuantizationUtilTest_IntegerFrExpVersusDouble) {
  int shift;
  int32_t result = tflite::IntegerFrExp(0.0, &shift);
  TF_LITE_MICRO_EXPECT_EQ(result, 0);
  TF_LITE_MICRO_EXPECT_EQ(shift, 0);

  int double_shift;
  double double_result = std::frexp(0.0, &double_shift);
  TF_LITE_MICRO_EXPECT_EQ(double_result, 0);
  TF_LITE_MICRO_EXPECT_EQ(double_shift, 0);

  result = tflite::IntegerFrExp(1.0, &shift);
  TF_LITE_MICRO_EXPECT_NEAR(result, 0x40000000, 1);
  TF_LITE_MICRO_EXPECT_EQ(shift, 1);
  double_result = std::frexp(1.0, &double_shift);
  TF_LITE_MICRO_EXPECT_NEAR(double_result, 0.5, 1e-5);
  TF_LITE_MICRO_EXPECT_EQ(double_shift, 1);

  result = tflite::IntegerFrExp(0.25, &shift);
  TF_LITE_MICRO_EXPECT_NEAR(result, 0x40000000, 1);
  TF_LITE_MICRO_EXPECT_EQ(shift, -1);
  double_result = std::frexp(0.25, &double_shift);
  TF_LITE_MICRO_EXPECT_NEAR(double_result, 0.5, 1e-5);
  TF_LITE_MICRO_EXPECT_EQ(double_shift, -1);

  result = tflite::IntegerFrExp(-1.0, &shift);
  TF_LITE_MICRO_EXPECT_NEAR(result, -(1 << 30), 1);
  TF_LITE_MICRO_EXPECT_EQ(shift, 1);
  double_result = std::frexp(-1.0, &double_shift);
  TF_LITE_MICRO_EXPECT_NEAR(double_result, -0.5, 1e-5);
  TF_LITE_MICRO_EXPECT_EQ(double_shift, 1);

  result = tflite::IntegerFrExp(123.45, &shift);
  TF_LITE_MICRO_EXPECT_NEAR(result, (0.964453 * (1LL << 31)), 1000);
  TF_LITE_MICRO_EXPECT_EQ(shift, 7);
  double_result = std::frexp(123.45, &double_shift);
  TF_LITE_MICRO_EXPECT_NEAR(double_result, 0.964453, 1e-5);
  TF_LITE_MICRO_EXPECT_EQ(double_shift, 7);
}

TF_LITE_MICRO_TEST(QuantizationUtilTest_DoubleFromFractionAndShift) {
  double result = tflite::DoubleFromFractionAndShift(0, 0);
  TF_LITE_MICRO_EXPECT_EQ(0, result);

  result = tflite::DoubleFromFractionAndShift(0x40000000, 1);
  TF_LITE_MICRO_EXPECT_NEAR(1.0, result, 1e-5);

  result = tflite::DoubleFromFractionAndShift(0x40000000, 2);
  TF_LITE_MICRO_EXPECT_NEAR(2.0, result, 1e-5);

  int shift;
  int64_t fraction = tflite::IntegerFrExp(3.0, &shift);
  result = tflite::DoubleFromFractionAndShift(fraction, shift);
  TF_LITE_MICRO_EXPECT_NEAR(3.0, result, 1e-5);

  fraction = tflite::IntegerFrExp(123.45, &shift);
  result = tflite::DoubleFromFractionAndShift(fraction, shift);
  TF_LITE_MICRO_EXPECT_NEAR(123.45, result, 1e-5);

  fraction = tflite::IntegerFrExp(-23.232323, &shift);
  result = tflite::DoubleFromFractionAndShift(fraction, shift);
  TF_LITE_MICRO_EXPECT_NEAR(-23.232323, result, 1e-5);

  fraction = tflite::IntegerFrExp(static_cast<double>(NAN), &shift);
  result = tflite::DoubleFromFractionAndShift(fraction, shift);
  TF_LITE_MICRO_EXPECT_TRUE(std::isnan(result));

  fraction = tflite::IntegerFrExp(static_cast<double>(INFINITY), &shift);
  result = tflite::DoubleFromFractionAndShift(fraction, shift);
  TF_LITE_MICRO_EXPECT_FALSE(std::isfinite(result));
}

TF_LITE_MICRO_TEST(QuantizationUtilTest_IntegerDoubleMultiply) {
  TF_LITE_MICRO_EXPECT_NEAR(1.0, tflite::IntegerDoubleMultiply(1.0, 1.0), 1e-5);
  TF_LITE_MICRO_EXPECT_NEAR(2.0, tflite::IntegerDoubleMultiply(1.0, 2.0), 1e-5);
  TF_LITE_MICRO_EXPECT_NEAR(2.0, tflite::IntegerDoubleMultiply(2.0, 1.0), 1e-5);
  TF_LITE_MICRO_EXPECT_NEAR(4.0, tflite::IntegerDoubleMultiply(2.0, 2.0), 1e-5);
  TF_LITE_MICRO_EXPECT_NEAR(0.5, tflite::IntegerDoubleMultiply(1.0, 0.5), 1e-5);
  TF_LITE_MICRO_EXPECT_NEAR(0.25, tflite::IntegerDoubleMultiply(0.5, 0.5),
                            1e-5);
  TF_LITE_MICRO_EXPECT_NEAR(-1.0, tflite::IntegerDoubleMultiply(1.0, -1.0),
                            1e-5);
  TF_LITE_MICRO_EXPECT_NEAR(-1.0, tflite::IntegerDoubleMultiply(-1.0, 1.0),
                            1e-5);
  TF_LITE_MICRO_EXPECT_NEAR(1.0, tflite::IntegerDoubleMultiply(-1.0, -1.0),
                            1e-5);
  TF_LITE_MICRO_EXPECT_NEAR(
      15000000.0, tflite::IntegerDoubleMultiply(3000.0, 5000.0), 1e-5);
  TF_LITE_MICRO_EXPECT_TRUE(std::isnan(
      tflite::IntegerDoubleMultiply(static_cast<double>(NAN), 5000.0)));
  TF_LITE_MICRO_EXPECT_TRUE(std::isnan(
      tflite::IntegerDoubleMultiply(3000.0, static_cast<double>(NAN))));
}

TF_LITE_MICRO_TEST(QuantizationUtilTest_IntegerDoubleCompare) {
  TF_LITE_MICRO_EXPECT_EQ(-1, tflite::IntegerDoubleCompare(0.0, 1.0));
  TF_LITE_MICRO_EXPECT_EQ(1, tflite::IntegerDoubleCompare(1.0, 0.0));
  TF_LITE_MICRO_EXPECT_EQ(0, tflite::IntegerDoubleCompare(1.0, 1.0));
  TF_LITE_MICRO_EXPECT_EQ(0, tflite::IntegerDoubleCompare(0.0, 0.0));
  TF_LITE_MICRO_EXPECT_EQ(-1, tflite::IntegerDoubleCompare(-10.0, 10.0));
  TF_LITE_MICRO_EXPECT_EQ(1, tflite::IntegerDoubleCompare(123.45, 10.0));
  TF_LITE_MICRO_EXPECT_EQ(
      1, tflite::IntegerDoubleCompare(static_cast<double>(NAN),
                                      static_cast<double>(INFINITY)));
  TF_LITE_MICRO_EXPECT_EQ(
      1, tflite::IntegerDoubleCompare(static_cast<double>(INFINITY),
                                      static_cast<double>(NAN)));
}

TF_LITE_MICRO_TEST(QuantizationUtilTest_PreprocessSoftmaxScaling) {
  auto quantize = [](double beta, double scale, int integer_bits) {
    int32_t q;
    int s;
    tflite::PreprocessSoftmaxScaling(beta, scale, integer_bits, &q, &s);
    return std::pair<int32_t, int>{q, s};
  };

  // If beta * scale is greater than fits in the number of integer bits, the
  // result is move near the maximum. Otherwise they quantize as expected.
  // With 4 integer bits we can represent up to 16.0.

  auto r = quantize(1.0, 16.0, 4);
  TF_LITE_MICRO_EXPECT_EQ(r.first, 2147483647);
  TF_LITE_MICRO_EXPECT_EQ(r.second, 31);

  r = quantize(1.0, 8.0, 4);
  TF_LITE_MICRO_EXPECT_EQ(r.first, 1073741824);
  TF_LITE_MICRO_EXPECT_EQ(r.second, 31);

  // But with 5 bits we can go further.
  r = quantize(2.0, 16.0, 5);
  TF_LITE_MICRO_EXPECT_EQ(r.first, 2147483647);
  TF_LITE_MICRO_EXPECT_EQ(r.second, 31);

  r = quantize(2.0, 8.0, 5);
  TF_LITE_MICRO_EXPECT_EQ(r.first, 1073741824);
  TF_LITE_MICRO_EXPECT_EQ(r.second, 31);
}

TF_LITE_MICRO_TEST(QuantizationUtilTest_CalculateInputRadius) {
  TF_LITE_MICRO_EXPECT_EQ(tflite::CalculateInputRadius(4, 27), 15);
  TF_LITE_MICRO_EXPECT_EQ(tflite::CalculateInputRadius(3, 27), 14);
  TF_LITE_MICRO_EXPECT_EQ(tflite::CalculateInputRadius(3, 28), 7);
  TF_LITE_MICRO_EXPECT_EQ(tflite::CalculateInputRadius(4, 2), 503316480);
}

TF_LITE_MICRO_TEST(QuantizationUtilTest_QuantizeMultiplierArray) {
  const double weights[] = {-4,    -2,   -1,  -0.5, -0.25, -0.125, 0,
                            0.125, 0.25, 0.5, 1,    2,     4};

  const int size = 13;
  int32_t effective_scale_significand[size];
  int effective_scale_shift[size];
  tflite::QuantizeMultiplierArray(weights, size, effective_scale_significand,
                                  effective_scale_shift);
  const int32_t expected_effective_scale_significand[] = {
      -1073741824,  // float scale = -4
      -1073741824,  // float scale = -2
      -1073741824,  // float scale = -1
      -1073741824,  // float scale = -0.5
      -1073741824,  // float scale = -0.25
      -1073741824,  // float scale = -0.125
      0,            // float scale = 0
      1073741824,   // float scale = 0.125
      1073741824,   // float scale = 0.25
      1073741824,   // float scale = 0.5
      1073741824,   // float scale = 1
      1073741824,   // float scale = 2
      1073741824,   // float scale = 4
  };

  const int expected_effective_scale_shift[] = {
      3,   // float scale = -4
      2,   // float scale = -2
      1,   // float scale = -1
      0,   // float scale = -0.5
      -1,  // float scale = -0.25
      -2,  // float scale = -0.125
      0,   // float scale = 0
      -2,  // float scale = 0.125
      -1,  // float scale = 0.25
      0,   // float scale = 0.5
      1,   // float scale = 1
      2,   // float scale = 2
      3,   // float scale = 4
  };

  for (int i = 0; i < size; i++) {
    TF_LITE_MICRO_EXPECT_EQ(effective_scale_significand[i],
                            expected_effective_scale_significand[i]);
    TF_LITE_MICRO_EXPECT_EQ(effective_scale_shift[i],
                            expected_effective_scale_shift[i]);
  }
}

TF_LITE_MICRO_TESTS_END
