blob: dc928a0e5d4fda75494e48d5553d1d2ff6055aae [file] [log] [blame]
Michalis Spyrou75d47332019-11-05 17:46:49 +00001/*
Pablo Marquez Tello732c1b22023-03-29 11:42:30 +01002 * Copyright (c) 2019-2021, 2023 Arm Limited.
Michalis Spyrou75d47332019-11-05 17:46:49 +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 */
24#ifndef ARM_COMPUTE_UTILS_MATH_SAFE_OPS
25#define ARM_COMPUTE_UTILS_MATH_SAFE_OPS
26
27#include "arm_compute/core/Error.h"
Pablo Marquez Tello732c1b22023-03-29 11:42:30 +010028#include "support/AclRequires.h"
Sang-Hoon Park68dd25f2020-10-19 16:00:11 +010029
30#include <limits>
Michalis Spyrou75d47332019-11-05 17:46:49 +000031
32namespace arm_compute
33{
34namespace utils
35{
36namespace math
37{
38/** Safe integer addition between two integers. In case of an overflow
39 * the numeric max limit is return. In case of an underflow numeric max
40 * limit is return.
41 *
42 * @tparam T Integer types to add
43 *
44 * @param[in] val_a First value to add
45 * @param[in] val_b Second value to add
46 *
47 * @return The addition result
48 */
Giorgio Arenac5a61392021-01-06 15:13:08 +000049template <typename T, ARM_COMPUTE_REQUIRES_TA(std::is_integral<T>::value)>
Michalis Spyrou75d47332019-11-05 17:46:49 +000050T safe_integer_add(T val_a, T val_b)
51{
52 T result = 0;
53
54 if((val_b > 0) && (val_a > std::numeric_limits<T>::max() - val_b))
55 {
56 result = std::numeric_limits<T>::max();
57 }
58 else if((val_b < 0) && (val_a < std::numeric_limits<T>::min() - val_b))
59 {
60 result = std::numeric_limits<T>::min();
61 }
62 else
63 {
64 result = val_a + val_b;
65 }
66
67 return result;
68}
69
70/** Safe integer subtraction between two integers. In case of an overflow
71 * the numeric max limit is return. In case of an underflow numeric max
72 * limit is return.
73 *
74 * @tparam T Integer types to subtract
75 *
76 * @param[in] val_a Value to subtract from
77 * @param[in] val_b Value to subtract
78 *
79 * @return The subtraction result
80 */
Giorgio Arenac5a61392021-01-06 15:13:08 +000081template <typename T, ARM_COMPUTE_REQUIRES_TA(std::is_integral<T>::value)>
Michalis Spyrou75d47332019-11-05 17:46:49 +000082T safe_integer_sub(T val_a, T val_b)
83{
84 T result = 0;
85
86 if((val_b < 0) && (val_a > std::numeric_limits<T>::max() + val_b))
87 {
88 result = std::numeric_limits<T>::max();
89 }
90 else if((val_b > 0) && (val_a < std::numeric_limits<T>::min() + val_b))
91 {
92 result = std::numeric_limits<T>::min();
93 }
94 else
95 {
96 result = val_a - val_b;
97 }
98
99 return result;
100}
101
102/** Safe integer multiplication between two integers. In case of an overflow
103 * the numeric max limit is return. In case of an underflow numeric max
104 * limit is return.
105 *
106 * @tparam T Integer types to multiply
107 *
108 * @param[in] val_a First value to multiply
109 * @param[in] val_b Second value to multiply
110 *
111 * @return The multiplication result
112 */
Giorgio Arenac5a61392021-01-06 15:13:08 +0000113template <typename T, ARM_COMPUTE_REQUIRES_TA(std::is_integral<T>::value)>
Michalis Spyrou75d47332019-11-05 17:46:49 +0000114T safe_integer_mul(T val_a, T val_b)
115{
116 T result = 0;
117
118 if(val_a > 0)
119 {
120 if((val_b > 0) && (val_a > (std::numeric_limits<T>::max() / val_b)))
121 {
122 result = std::numeric_limits<T>::max();
123 }
124 else if(val_b < (std::numeric_limits<T>::min() / val_a))
125 {
126 result = std::numeric_limits<T>::min();
127 }
128 else
129 {
130 result = val_a * val_b;
131 }
132 }
133 else
134 {
135 if((val_b > 0) && (val_a < (std::numeric_limits<T>::min() / val_b)))
136 {
137 result = std::numeric_limits<T>::max();
138 }
139 else if((val_a != 0) && (val_b < (std::numeric_limits<T>::max() / val_a)))
140 {
141 result = std::numeric_limits<T>::min();
142 }
143 else
144 {
145 result = val_a * val_b;
146 }
147 }
148
149 return result;
150}
151
152/** Safe integer division between two integers. In case of an overflow
153 * the numeric max limit is return. In case of an underflow numeric max
154 * limit is return.
155 *
156 * @tparam T Integer types to divide
157 *
158 * @param[in] val_a Dividend value
159 * @param[in] val_b Divisor value
160 *
161 * @return The quotient
162 */
Giorgio Arenac5a61392021-01-06 15:13:08 +0000163template <typename T, ARM_COMPUTE_REQUIRES_TA(std::is_integral<T>::value)>
Michalis Spyrou75d47332019-11-05 17:46:49 +0000164T safe_integer_div(T val_a, T val_b)
165{
166 T result = 0;
167
168 if((val_b == 0) || ((val_a == std::numeric_limits<T>::min()) && (val_b == -1)))
169 {
170 result = std::numeric_limits<T>::min();
171 }
172 else
173 {
174 result = val_a / val_b;
175 }
176
177 return result;
178}
179} // namespace cast
180} // namespace utils
181} // namespace arm_compute
182#endif /* ARM_COMPUTE_UTILS_MATH_SAFE_OPS */