xref: /aosp_15_r20/external/pigweed/pw_numeric/public/pw_numeric/integer_division.h (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1 // Copyright 2024 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 #pragma once
15 
16 #include <type_traits>
17 
18 namespace pw {
19 
20 /// Performs integer division and rounds to the nearest integer. Gives the same
21 /// result as `std::round(static_cast<double>(dividend) /
22 /// static_cast<double>(divisor))`, but requires no floating point operations
23 /// and is `constexpr`.
24 ///
25 /// @rst
26 /// .. warning::
27 ///
28 ///    ``signed`` or ``unsigned`` ``int``, ``long``, or ``long long`` operands
29 ///    overflow if:
30 ///
31 ///    - the quotient is positive and ``dividend + divisor/2`` overflows, or
32 ///    - the quotient is negative and ``dividend - divisor/2`` overflows.
33 ///
34 ///    To avoid overflow, do not use this function with very large
35 ///    operands, or cast ``int`` or ``long`` to a larger type first. Overflow
36 ///    cannot occur with types smaller than ``int`` because C++ implicitly
37 ///    converts them to ``int``.
38 /// @endrst
39 template <typename T>
IntegerDivisionRoundNearest(T dividend,T divisor)40 constexpr T IntegerDivisionRoundNearest(T dividend, T divisor) {
41   static_assert(std::is_integral_v<T> && !std::is_same_v<T, bool>);
42   // Integer division typically truncates towards zero, so change the direction
43   // of the bias when the quotient is negative.
44   if constexpr (std::is_signed_v<T>) {
45     if ((dividend < 0) != (divisor < 0)) {
46       return (dividend - divisor / T{2}) / divisor;
47     }
48   }
49 
50   return (dividend + divisor / T{2}) / divisor;
51 }
52 
53 }  // namespace pw
54