| 82 | |
| 83 | template <class T> |
| 84 | float QuantizedToFloat(T input, float range_min, float range_max) { |
| 85 | if (std::is_same<T, float>::value) { |
| 86 | // Specialization for float. This is used in reference implementation |
| 87 | // for float which is useful to compare performance between float |
| 88 | // and quantized type. |
| 89 | return input; |
| 90 | } |
| 91 | if (range_min == range_max) { |
| 92 | return range_min; |
| 93 | } |
| 94 | const int number_of_bits = sizeof(T) * 8; |
| 95 | const int64 number_of_steps = static_cast<int64>(1) << number_of_bits; |
| 96 | const double range_adjust = (number_of_steps / (number_of_steps - 1.0)); |
| 97 | const double range = ((range_max - range_min) * range_adjust); |
| 98 | const double range_scale = (range / number_of_steps); |
| 99 | const int64 lowest_quantized = |
| 100 | static_cast<int64>(Eigen::NumTraits<T>::lowest()); |
| 101 | const double offset_input = static_cast<double>(input) - lowest_quantized; |
| 102 | // For compatibility with DEQUANTIZE_WITH_EIGEN, we should convert |
| 103 | // range_scale to a float, otherwise range_min_rounded might be slightly |
| 104 | // different. |
| 105 | const double range_min_rounded = |
| 106 | std::round(range_min / static_cast<float>(range_scale)) * |
| 107 | static_cast<float>(range_scale); |
| 108 | const double result = range_min_rounded + (offset_input * range_scale); |
| 109 | return static_cast<float>(result); |
| 110 | } |
| 111 | |
| 112 | template <class T> |
| 113 | float FloatForOneQuantizedLevel(float range_min, float range_max) { |