Generalize custom uniform generator for floating point data types with 16 bits

- Change name of uniform_real_distribution_fp16 to uniform_real_distribution_16bit, and make it also accept bfloat16 data type

Resolves: COMPMID-4057

Signed-off-by: Giorgio Arena <giorgio.arena@arm.com>
Change-Id: Id2f1a84b9c9f09cb260a0785add4fc5954d5853a
Reviewed-on: https://review.mlplatform.org/c/ml/ComputeLibrary/+/4768
Reviewed-by: Michele Di Giorgio <michele.digiorgio@arm.com>
Comments-Addressed: Arm Jenkins <bsgcomp@arm.com>
Tested-by: Arm Jenkins <bsgcomp@arm.com>
diff --git a/support/Random.h b/support/Random.h
index d5d372d..7658e6d 100644
--- a/support/Random.h
+++ b/support/Random.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019-2020 Arm Limited.
+ * Copyright (c) 2019-2021 Arm Limited.
  *
  * SPDX-License-Identifier: MIT
  *
@@ -44,10 +44,10 @@
 class RangedUniformDistribution
 {
 public:
-    static constexpr bool is_half     = std::is_same<T, half>::value;
-    static constexpr bool is_integral = std::is_integral<T>::value && !is_half;
+    static constexpr bool is_fp_16bit = std::is_same<T, half>::value || std::is_same<T, bfloat16>::value;
+    static constexpr bool is_integral = std::is_integral<T>::value && !is_fp_16bit;
 
-    using fp_dist     = typename std::conditional<is_half, arm_compute::utils::uniform_real_distribution_fp16, std::uniform_real_distribution<T>>::type;
+    using fp_dist     = typename std::conditional<is_fp_16bit, arm_compute::utils::uniform_real_distribution_16bit<T>, std::uniform_real_distribution<T>>::type;
     using DT          = typename std::conditional<is_integral, std::uniform_int_distribution<T>, fp_dist>::type;
     using result_type = T;
     using range_pair  = std::pair<result_type, result_type>;
diff --git a/tests/AssetsLibrary.h b/tests/AssetsLibrary.h
index f44c554..8230a93 100644
--- a/tests/AssetsLibrary.h
+++ b/tests/AssetsLibrary.h
@@ -776,14 +776,14 @@
         case DataType::BFLOAT16:
         {
             // It doesn't make sense to check [-inf, inf], so hard code it to a big number
-            std::uniform_real_distribution<float> distribution_bf16(-1000.f, 1000.f);
+            arm_compute::utils::uniform_real_distribution_16bit<bfloat16> distribution_bf16(-1000.f, 1000.f);
             fill(tensor, distribution_bf16, seed_offset);
             break;
         }
         case DataType::F16:
         {
             // It doesn't make sense to check [-inf, inf], so hard code it to a big number
-            arm_compute::utils::uniform_real_distribution_fp16 distribution_f16{ -100.f, 100.f };
+            arm_compute::utils::uniform_real_distribution_16bit<half> distribution_f16{ -100.f, 100.f };
             fill(tensor, distribution_f16, seed_offset);
             break;
         }
@@ -881,8 +881,8 @@
         case DataType::BFLOAT16:
         {
             // It doesn't make sense to check [-inf, inf], so hard code it to a big number
-            const auto                       converted_pairs = detail::convert_range_pair<float>(excluded_range_pairs);
-            RangedUniformDistribution<float> distribution_bf16(-1000.f, 1000.f, converted_pairs);
+            const auto                          converted_pairs = detail::convert_range_pair<bfloat16>(excluded_range_pairs);
+            RangedUniformDistribution<bfloat16> distribution_bf16(bfloat16(-1000.f), bfloat16(1000.f), converted_pairs);
             fill(tensor, distribution_bf16, seed_offset);
             break;
         }
@@ -974,13 +974,13 @@
         }
         case DataType::BFLOAT16:
         {
-            std::uniform_real_distribution<float> distribution_bf16(low, high);
+            arm_compute::utils::uniform_real_distribution_16bit<bfloat16> distribution_bf16(low, high);
             fill(tensor, distribution_bf16, seed_offset);
             break;
         }
         case DataType::F16:
         {
-            arm_compute::utils::uniform_real_distribution_fp16 distribution_f16{ float(low), float(high) };
+            arm_compute::utils::uniform_real_distribution_16bit<half> distribution_f16{ float(low), float(high) };
             fill(tensor, distribution_f16, seed_offset);
             break;
         }
diff --git a/tests/validation/fixtures/ArgMinMaxFixture.h b/tests/validation/fixtures/ArgMinMaxFixture.h
index fdf9ac4..f140c98 100644
--- a/tests/validation/fixtures/ArgMinMaxFixture.h
+++ b/tests/validation/fixtures/ArgMinMaxFixture.h
@@ -61,7 +61,7 @@
         {
             case DataType::F16:
             {
-                arm_compute::utils::uniform_real_distribution_fp16 distribution{ -1.0f, 1.0f };
+                arm_compute::utils::uniform_real_distribution_16bit<half> distribution{ -1.0f, 1.0f };
                 library->fill(tensor, distribution, 0);
                 break;
             }
diff --git a/tests/validation/fixtures/ConvertFullyConnectedWeightsFixture.h b/tests/validation/fixtures/ConvertFullyConnectedWeightsFixture.h
index a4705b1..d798483 100644
--- a/tests/validation/fixtures/ConvertFullyConnectedWeightsFixture.h
+++ b/tests/validation/fixtures/ConvertFullyConnectedWeightsFixture.h
@@ -67,7 +67,7 @@
             }
             case DataType::F16:
             {
-                arm_compute::utils::uniform_real_distribution_fp16 distribution{ -1.0f, 1.0f };
+                arm_compute::utils::uniform_real_distribution_16bit<half> distribution{ -1.0f, 1.0f };
                 library->fill(tensor, distribution, i);
                 break;
             }
diff --git a/tests/validation/fixtures/ConvolutionLayerFixture.h b/tests/validation/fixtures/ConvolutionLayerFixture.h
index 210afbe..006c5eb 100644
--- a/tests/validation/fixtures/ConvolutionLayerFixture.h
+++ b/tests/validation/fixtures/ConvolutionLayerFixture.h
@@ -141,9 +141,14 @@
                 break;
             }
             case DataType::BFLOAT16:
+            {
+                arm_compute::utils::uniform_real_distribution_16bit<bfloat16> distribution{ -1.0f, 1.0f };
+                library->fill(tensor, distribution, i);
+                break;
+            }
             case DataType::F16:
             {
-                arm_compute::utils::uniform_real_distribution_fp16 distribution{ -1.0f, 1.0f };
+                arm_compute::utils::uniform_real_distribution_16bit<half> distribution{ -1.0f, 1.0f };
                 library->fill(tensor, distribution, i);
                 break;
             }
diff --git a/tests/validation/fixtures/DeconvolutionLayerFixture.h b/tests/validation/fixtures/DeconvolutionLayerFixture.h
index 6394caf..6ea2335 100644
--- a/tests/validation/fixtures/DeconvolutionLayerFixture.h
+++ b/tests/validation/fixtures/DeconvolutionLayerFixture.h
@@ -91,7 +91,7 @@
             }
             case DataType::F16:
             {
-                arm_compute::utils::uniform_real_distribution_fp16 distribution{ -1.0f, 1.0f };
+                arm_compute::utils::uniform_real_distribution_16bit<half> distribution{ -1.0f, 1.0f };
                 library->fill(tensor, distribution, i);
                 break;
             }
diff --git a/tests/validation/fixtures/DepthwiseConvolutionLayerFixture.h b/tests/validation/fixtures/DepthwiseConvolutionLayerFixture.h
index 09f8cb4..bb1c105 100644
--- a/tests/validation/fixtures/DepthwiseConvolutionLayerFixture.h
+++ b/tests/validation/fixtures/DepthwiseConvolutionLayerFixture.h
@@ -99,7 +99,7 @@
             }
             case DataType::F16:
             {
-                arm_compute::utils::uniform_real_distribution_fp16 distribution{ -1.0f, 1.0f };
+                arm_compute::utils::uniform_real_distribution_16bit<half> distribution{ -1.0f, 1.0f };
                 library->fill(tensor, distribution, i);
                 break;
             }
@@ -354,7 +354,7 @@
             }
             case DataType::F16:
             {
-                arm_compute::utils::uniform_real_distribution_fp16 distribution{ -1.0f, 1.0f };
+                arm_compute::utils::uniform_real_distribution_16bit<half> distribution{ -1.0f, 1.0f };
                 library->fill(tensor, distribution, i);
                 break;
             }
diff --git a/tests/validation/fixtures/DirectConvolutionLayerFixture.h b/tests/validation/fixtures/DirectConvolutionLayerFixture.h
index 1967e8d..8e4de77 100644
--- a/tests/validation/fixtures/DirectConvolutionLayerFixture.h
+++ b/tests/validation/fixtures/DirectConvolutionLayerFixture.h
@@ -109,7 +109,7 @@
             }
             case DataType::F16:
             {
-                arm_compute::utils::uniform_real_distribution_fp16 distribution{ -1.0f, 1.0f };
+                arm_compute::utils::uniform_real_distribution_16bit<half> distribution{ -1.0f, 1.0f };
                 library->fill(tensor, distribution, i);
                 break;
             }
diff --git a/tests/validation/fixtures/DirectConvolutionLayerTensorShiftFixture.h b/tests/validation/fixtures/DirectConvolutionLayerTensorShiftFixture.h
index 7e891fe..f39595f 100644
--- a/tests/validation/fixtures/DirectConvolutionLayerTensorShiftFixture.h
+++ b/tests/validation/fixtures/DirectConvolutionLayerTensorShiftFixture.h
@@ -94,7 +94,7 @@
             }
             case DataType::F16:
             {
-                arm_compute::utils::uniform_real_distribution_fp16 distribution{ float(-1.0f), float(1.0f) };
+                arm_compute::utils::uniform_real_distribution_16bit<half> distribution{ float(-1.0f), float(1.0f) };
                 library->fill(tensor, distribution, i);
                 break;
             }
diff --git a/tests/validation/fixtures/ElementWiseUnaryFixture.h b/tests/validation/fixtures/ElementWiseUnaryFixture.h
index 26484be..f414daf 100644
--- a/tests/validation/fixtures/ElementWiseUnaryFixture.h
+++ b/tests/validation/fixtures/ElementWiseUnaryFixture.h
@@ -76,7 +76,7 @@
                 {
                     case DataType::F16:
                     {
-                        arm_compute::utils::uniform_real_distribution_fp16 distribution{ -2.0f, 2.0f };
+                        arm_compute::utils::uniform_real_distribution_16bit<half> distribution{ -2.0f, 2.0f };
                         library->fill(tensor, distribution, i);
                         break;
                     }
diff --git a/tests/validation/fixtures/FFTFixture.h b/tests/validation/fixtures/FFTFixture.h
index 37c2f2f..86a9727 100644
--- a/tests/validation/fixtures/FFTFixture.h
+++ b/tests/validation/fixtures/FFTFixture.h
@@ -63,7 +63,7 @@
         {
             case DataType::F16:
             {
-                arm_compute::utils::uniform_real_distribution_fp16 distribution{ -5.0f, 5.0f };
+                arm_compute::utils::uniform_real_distribution_16bit<half> distribution{ -5.0f, 5.0f };
                 library->fill(tensor, distribution, 0);
                 break;
             }
@@ -151,7 +151,7 @@
         {
             case DataType::F16:
             {
-                arm_compute::utils::uniform_real_distribution_fp16 distribution{ -1.0f, 1.0f };
+                arm_compute::utils::uniform_real_distribution_16bit<half> distribution{ -1.0f, 1.0f };
                 library->fill(tensor, distribution, i);
                 break;
             }
diff --git a/tests/validation/fixtures/GEMMFixture.h b/tests/validation/fixtures/GEMMFixture.h
index 0c2f0a4..192e77e 100644
--- a/tests/validation/fixtures/GEMMFixture.h
+++ b/tests/validation/fixtures/GEMMFixture.h
@@ -64,7 +64,7 @@
         {
             case DataType::F16:
             {
-                arm_compute::utils::uniform_real_distribution_fp16 distribution{ float(lo), float(hi) };
+                arm_compute::utils::uniform_real_distribution_16bit<half> distribution{ float(lo), float(hi) };
                 library->fill(tensor, distribution, i);
                 break;
             }
diff --git a/tests/validation/fixtures/GEMMInterleave4x4Fixture.h b/tests/validation/fixtures/GEMMInterleave4x4Fixture.h
index 30708e4..1ce0eaf 100644
--- a/tests/validation/fixtures/GEMMInterleave4x4Fixture.h
+++ b/tests/validation/fixtures/GEMMInterleave4x4Fixture.h
@@ -64,7 +64,7 @@
         {
             case DataType::F16:
             {
-                arm_compute::utils::uniform_real_distribution_fp16 distribution{ -1.0f, 1.0f };
+                arm_compute::utils::uniform_real_distribution_16bit<half> distribution{ -1.0f, 1.0f };
                 library->fill(tensor, distribution, i);
                 break;
             }
diff --git a/tests/validation/fixtures/GEMMLowpFixture.h b/tests/validation/fixtures/GEMMLowpFixture.h
index b9140eb..24c1a24 100644
--- a/tests/validation/fixtures/GEMMLowpFixture.h
+++ b/tests/validation/fixtures/GEMMLowpFixture.h
@@ -79,7 +79,7 @@
         }
         case DataType::F16:
         {
-            arm_compute::utils::uniform_real_distribution_fp16 distribution{ -1.0f, 1.0f };
+            arm_compute::utils::uniform_real_distribution_16bit<half> distribution{ -1.0f, 1.0f };
             library->fill(tensor, distribution, i);
             break;
         }
diff --git a/tests/validation/fixtures/GEMMTranspose1xWFixture.h b/tests/validation/fixtures/GEMMTranspose1xWFixture.h
index 3d6ac76..2d2e706 100644
--- a/tests/validation/fixtures/GEMMTranspose1xWFixture.h
+++ b/tests/validation/fixtures/GEMMTranspose1xWFixture.h
@@ -65,7 +65,7 @@
         {
             case DataType::F16:
             {
-                arm_compute::utils::uniform_real_distribution_fp16 distribution{ -1.0f, 1.0f };
+                arm_compute::utils::uniform_real_distribution_16bit<half> distribution{ -1.0f, 1.0f };
                 library->fill(tensor, distribution, i);
                 break;
             }
diff --git a/tests/validation/fixtures/WinogradConvolutionLayerFixture.h b/tests/validation/fixtures/WinogradConvolutionLayerFixture.h
index 5a40815..e1cc953 100644
--- a/tests/validation/fixtures/WinogradConvolutionLayerFixture.h
+++ b/tests/validation/fixtures/WinogradConvolutionLayerFixture.h
@@ -177,7 +177,7 @@
         {
             case DataType::F16:
             {
-                arm_compute::utils::uniform_real_distribution_fp16 distribution{ float(min), float(max) };
+                arm_compute::utils::uniform_real_distribution_16bit<half> distribution{ float(min), float(max) };
                 library->fill(tensor, distribution, i);
                 break;
             }
@@ -500,7 +500,7 @@
         {
             case DataType::F16:
             {
-                arm_compute::utils::uniform_real_distribution_fp16 distribution{ float(min), float(max) };
+                arm_compute::utils::uniform_real_distribution_16bit<half> distribution{ float(min), float(max) };
                 library->fill(tensor, distribution, i);
                 break;
             }
diff --git a/utils/Utils.h b/utils/Utils.h
index 9862514..9c9026e 100644
--- a/utils/Utils.h
+++ b/utils/Utils.h
@@ -294,16 +294,19 @@
  *  uniform_real_distribution<half> generates values that get rounded off to zero, causing
  *  differences between ACL and reference implementation
 */
-class uniform_real_distribution_fp16
+template <typename T>
+class uniform_real_distribution_16bit
 {
+    static_assert(std::is_same<T, half>::value || std::is_same<T, bfloat16>::value, "Only half and bfloat16 data types supported");
+
 public:
-    using result_type = half;
+    using result_type = T;
     /** Constructor
      *
      * @param[in] min Minimum value of the distribution
      * @param[in] max Maximum value of the distribution
      */
-    explicit uniform_real_distribution_fp16(float min = 0.f, float max = 1.0)
+    explicit uniform_real_distribution_16bit(float min = 0.f, float max = 1.0)
         : dist(min, max)
     {
     }
@@ -312,9 +315,9 @@
      *
      * @param[in] gen an uniform random bit generator object
      */
-    half operator()(std::mt19937 &gen)
+    T operator()(std::mt19937 &gen)
     {
-        return half(dist(gen));
+        return T(dist(gen));
     }
 
 private:
@@ -770,10 +773,10 @@
 template <typename T, typename TensorType>
 void fill_random_tensor(TensorType &tensor, std::random_device::result_type seed, T lower_bound = std::numeric_limits<T>::lowest(), T upper_bound = std::numeric_limits<T>::max())
 {
-    constexpr bool is_half     = std::is_same<T, half>::value;
-    constexpr bool is_integral = std::is_integral<T>::value && !is_half;
+    constexpr bool is_fp_16bit = std::is_same<T, half>::value || std::is_same<T, bfloat16>::value;
+    constexpr bool is_integral = std::is_integral<T>::value && !is_fp_16bit;
 
-    using fp_dist_type = typename std::conditional<is_half, arm_compute::utils::uniform_real_distribution_fp16, std::uniform_real_distribution<T>>::type;
+    using fp_dist_type = typename std::conditional<is_fp_16bit, arm_compute::utils::uniform_real_distribution_16bit<T>, std::uniform_real_distribution<T>>::type;
     using dist_type    = typename std::conditional<is_integral, std::uniform_int_distribution<T>, fp_dist_type>::type;
 
     std::mt19937 gen(seed);