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