blob: 5691a6680b4f56673c4ecd668c58cf7e49fff54e [file] [log] [blame]
Georgios Pinitas303f0db2018-11-19 11:56:51 +00001/*
Pablo Marquez Tello732c1b22023-03-29 11:42:30 +01002 * Copyright (c) 2018-2021, 2023 Arm Limited.
Georgios Pinitas303f0db2018-11-19 11:56:51 +00003 *
4 * SPDX-License-Identifier: MIT
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to
8 * deal in the Software without restriction, including without limitation the
9 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 * sell copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in all
14 * copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 */
Michalis Spyrouf4643372019-11-29 16:17:13 +000024#ifndef ARM_COMPUTE_UTILS_ROUNDING_H
25#define ARM_COMPUTE_UTILS_ROUNDING_H
Georgios Pinitas303f0db2018-11-19 11:56:51 +000026
27#include "arm_compute/core/Error.h"
Georgios Pinitas303f0db2018-11-19 11:56:51 +000028#include "arm_compute/core/utils/misc/Traits.h"
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +010029
Pablo Marquez Tello732c1b22023-03-29 11:42:30 +010030#include "support/AclRequires.h"
Georgios Pinitas303f0db2018-11-19 11:56:51 +000031#include "support/ToolchainSupport.h"
32
33#include <cmath>
34
35namespace arm_compute
36{
37namespace utils
38{
39namespace rounding
40{
41/** Rounding mode */
42enum class RoundingMode
43{
44 TO_ZERO, /**< Round towards zero */
45 AWAY_FROM_ZERO, /**< Round away from zero */
46 HALF_TO_ZERO, /**< Round half towards from zero */
47 HALF_AWAY_FROM_ZERO, /**< Round half away from zero */
48 HALF_UP, /**< Round half towards positive infinity */
49 HALF_DOWN, /**< Round half towards negative infinity */
50 HALF_EVEN /**< Round half towards nearest even */
51};
52
53/** Round floating-point value with round to zero
54 *
55 * @tparam T Parameter type. Should be of floating point type.
56 *
57 * @param[in] value floating-point value to be rounded.
58 *
59 * @return Floating-point value of rounded @p value.
60 */
Giorgio Arenac5a61392021-01-06 15:13:08 +000061template <typename T, ARM_COMPUTE_REQUIRES_TA(traits::is_floating_point<T>::value)>
Georgios Pinitas303f0db2018-11-19 11:56:51 +000062inline T round_to_zero(T value)
63{
64 T res = std::floor(std::fabs(value));
65 return (value < 0.f) ? -res : res;
66}
67
68/** Round floating-point value with round away from zero
69 *
70 * @tparam T Parameter type. Should be of floating point type.
71 *
72 * @param[in] value floating-point value to be rounded.
73 *
74 * @return Floating-point value of rounded @p value.
75 */
Giorgio Arenac5a61392021-01-06 15:13:08 +000076template <typename T, ARM_COMPUTE_REQUIRES_TA(traits::is_floating_point<T>::value)>
Georgios Pinitas303f0db2018-11-19 11:56:51 +000077inline T round_away_from_zero(T value)
78{
79 T res = std::ceil(std::fabs(value));
80 return (value < 0.f) ? -res : res;
81}
82
83/** Round floating-point value with half value rounding towards zero.
84 *
85 * @tparam T Parameter type. Should be of floating point type.
86 *
87 * @param[in] value floating-point value to be rounded.
88 *
89 * @return Floating-point value of rounded @p value.
90 */
Giorgio Arenac5a61392021-01-06 15:13:08 +000091template <typename T, ARM_COMPUTE_REQUIRES_TA(traits::is_floating_point<T>::value)>
Georgios Pinitas303f0db2018-11-19 11:56:51 +000092inline T round_half_to_zero(T value)
93{
94 T res = T(std::ceil(std::fabs(value) - 0.5f));
95 return (value < 0.f) ? -res : res;
96}
97
98/** Round floating-point value with half value rounding away from zero.
99 *
100 * @tparam T Parameter type. Should be of floating point type.
101 *
102 * @param[in] value floating-point value to be rounded.
103 *
104 * @return Floating-point value of rounded @p value.
105 */
Giorgio Arenac5a61392021-01-06 15:13:08 +0000106template <typename T, ARM_COMPUTE_REQUIRES_TA(traits::is_floating_point<T>::value)>
Georgios Pinitas303f0db2018-11-19 11:56:51 +0000107inline T round_half_away_from_zero(T value)
108{
109 T res = T(std::floor(std::fabs(value) + 0.5f));
110 return (value < 0.f) ? -res : res;
111}
112
113/** Round floating-point value with half value rounding to positive infinity.
114 *
115 * @tparam T Parameter type. Should be of floating point type.
116 *
117 * @param[in] value floating-point value to be rounded.
118 *
119 * @return Floating-point value of rounded @p value.
120 */
Giorgio Arenac5a61392021-01-06 15:13:08 +0000121template <typename T, ARM_COMPUTE_REQUIRES_TA(traits::is_floating_point<T>::value)>
Georgios Pinitas303f0db2018-11-19 11:56:51 +0000122inline T round_half_up(T value)
123{
124 return std::floor(value + 0.5f);
125}
126
127/** Round floating-point value with half value rounding to negative infinity.
128 *
129 * @tparam T Parameter type. Should be of floating point type.
130 *
131 * @param[in] value floating-point value to be rounded.
132 *
133 * @return Floating-point value of rounded @p value.
134 */
Giorgio Arenac5a61392021-01-06 15:13:08 +0000135template <typename T, ARM_COMPUTE_REQUIRES_TA(traits::is_floating_point<T>::value)>
Georgios Pinitas303f0db2018-11-19 11:56:51 +0000136inline T round_half_down(T value)
137{
138 return std::ceil(value - 0.5f);
139}
140
141/** Round floating-point value with half value rounding to nearest even.
142 *
143 * @tparam T Parameter type. Should be of floating point type.
144 *
145 * @param[in] value floating-point value to be rounded.
146 * @param[in] epsilon precision.
147 *
148 * @return Floating-point value of rounded @p value.
149 */
Giorgio Arenac5a61392021-01-06 15:13:08 +0000150template <typename T, ARM_COMPUTE_REQUIRES_TA(traits::is_floating_point<T>::value)>
Georgios Pinitas303f0db2018-11-19 11:56:51 +0000151inline T round_half_even(T value, T epsilon = std::numeric_limits<T>::epsilon())
152{
153 T positive_value = std::abs(value);
154 T ipart = 0;
155 std::modf(positive_value, &ipart);
156 // If 'value' is exactly halfway between two integers
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +0100157 if (std::abs(positive_value - (ipart + 0.5f)) < epsilon)
Georgios Pinitas303f0db2018-11-19 11:56:51 +0000158 {
159 // If 'ipart' is even then return 'ipart'
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +0100160 if (std::fmod(ipart, 2.f) < epsilon)
Georgios Pinitas303f0db2018-11-19 11:56:51 +0000161 {
162 return support::cpp11::copysign(ipart, value);
163 }
164 // Else return the nearest even integer
165 return support::cpp11::copysign(std::ceil(ipart + 0.5f), value);
166 }
167 // Otherwise use the usual round to closest
168 return support::cpp11::copysign(support::cpp11::round(positive_value), value);
169}
170
171/** Round floating-point value given a rounding mode
172 *
173 * @tparam T Parameter type. Should be of floating point type.
174 *
175 * @param[in] value floating-point value to be rounded.
176 * @param[in] rounding_mode Rounding mode to use.
177 *
178 * @return Floating-point value of rounded @p value.
179 */
Giorgio Arenac5a61392021-01-06 15:13:08 +0000180template <typename T, ARM_COMPUTE_REQUIRES_TA(traits::is_floating_point<T>::value)>
Georgios Pinitas303f0db2018-11-19 11:56:51 +0000181inline T round(T value, RoundingMode rounding_mode)
182{
Felix Thomasmathibalanafd38f02023-09-27 17:46:17 +0100183 switch (rounding_mode)
Georgios Pinitas303f0db2018-11-19 11:56:51 +0000184 {
185 case RoundingMode::TO_ZERO:
186 return round_to_zero(value);
187 case RoundingMode::AWAY_FROM_ZERO:
188 return round_away_from_zero(value);
189 case RoundingMode::HALF_TO_ZERO:
190 return round_half_to_zero(value);
191 case RoundingMode::HALF_AWAY_FROM_ZERO:
192 return round_half_away_from_zero(value);
193 case RoundingMode::HALF_UP:
194 return round_half_up(value);
195 case RoundingMode::HALF_DOWN:
196 return round_half_down(value);
197 case RoundingMode::HALF_EVEN:
198 return round_half_even(value);
199 default:
200 ARM_COMPUTE_ERROR("Unsupported rounding mode!");
201 }
202}
203} // namespace rounding
204} // namespace utils
205} // namespace arm_compute
Michalis Spyrouf4643372019-11-29 16:17:13 +0000206#endif /*ARM_COMPUTE_UTILS_ROUNDING_H */