tflite: Compute numbers in float16 to match the NPU behavior

If we compute numbers in float32, the error will accumulate, so there
are chances that it eventually exceed the threshold.

For example, when computing 0.375732 + 0.298828 - 0.641113 in float32,
the result is 0.0334473, but it will be 0.0336914 in float16.
Note that 0.375732 + 0.298828 = 0.674561(fp32) or 0.674805(fp16).

To address the issue, we compute numbers in float16 to mimic the same
calculation in NPU.

BUG=b:430326201
TEST=`./async_delegate_test --stable_delegate_settings_file=/etc/ml_core/stable_delegate_settings.json;` on screebo and hylia passes 3000 times.

Change-Id: Iea8c46ce83150cc592ddb8c114287b00f63ab67f
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/tflite/+/6719772
Auto-Submit: Tommy Chiang <ototot@google.com>
Commit-Queue: Shik Chen <shik@chromium.org>
Tested-by: Tommy Chiang <ototot@google.com>
Reviewed-by: Shik Chen <shik@chromium.org>
diff --git a/common/async_delegate_test.cc b/common/async_delegate_test.cc
index 2db4a1d..8015a97 100644
--- a/common/async_delegate_test.cc
+++ b/common/async_delegate_test.cc
@@ -6,6 +6,7 @@
 
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
+
 #include <vector>
 
 #include "absl/random/random.h"
@@ -112,10 +113,19 @@
     std::vector<float> c_data(n);
     std::vector<float> d_data(n);
     for (int i = 0; i < n; ++i) {
-      a_data[i] = absl::Uniform(gen, 0.0, 1.0);
-      b_data[i] = absl::Uniform(gen, 0.0, 1.0);
-      c_data[i] = absl::Uniform(gen, 0.0, 1.0);
-      d_data[i] = a_data[i] + b_data[i] - c_data[i];
+      // Limit the input precision to float16 since we are comparing the
+      // computation in fp16.
+      const _Float16 a = absl::Uniform(gen, 0.0, 1.0);
+      const _Float16 b = absl::Uniform(gen, 0.0, 1.0);
+      const _Float16 c = absl::Uniform(gen, 0.0, 1.0);
+      // If we do not cast back to float16 first, the result will be casted back
+      // to float16 only after the full computation.
+      const _Float16 d = static_cast<_Float16>(a + b) - c;
+
+      a_data[i] = a;
+      b_data[i] = b;
+      c_data[i] = c;
+      d_data[i] = d;
     }
     EXPECT_EQ(driver->SetInputTensorData("a", a_data), kTfLiteOk);
     EXPECT_EQ(driver->SetInputTensorData("b", b_data), kTfLiteOk);
diff --git a/common/sync_driver_test.cc b/common/sync_driver_test.cc
index e2efb2a..b75b307 100644
--- a/common/sync_driver_test.cc
+++ b/common/sync_driver_test.cc
@@ -6,6 +6,7 @@
 
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
+
 #include <vector>
 
 #include "absl/random/random.h"
@@ -84,10 +85,19 @@
     std::vector<float> c_data(n);
     std::vector<float> d_data(n);
     for (int i = 0; i < n; ++i) {
-      a_data[i] = absl::Uniform(gen, 0.0, 1.0);
-      b_data[i] = absl::Uniform(gen, 0.0, 1.0);
-      c_data[i] = absl::Uniform(gen, 0.0, 1.0);
-      d_data[i] = a_data[i] + b_data[i] - c_data[i];
+      // Limit the input precision to float16 since we are comparing the
+      // computation in fp16.
+      const _Float16 a = absl::Uniform(gen, 0.0, 1.0);
+      const _Float16 b = absl::Uniform(gen, 0.0, 1.0);
+      const _Float16 c = absl::Uniform(gen, 0.0, 1.0);
+      // If we do not cast back to float16 first, the result will be casted back
+      // to float16 only after the full computation.
+      const _Float16 d = static_cast<_Float16>(a + b) - c;
+
+      a_data[i] = a;
+      b_data[i] = b;
+      c_data[i] = c;
+      d_data[i] = d;
     }
     EXPECT_EQ(driver->SetInputTensorData("a", a_data), kTfLiteOk);
     EXPECT_EQ(driver->SetInputTensorData("b", b_data), kTfLiteOk);