proxygen
Math.h
Go to the documentation of this file.
1 /*
2  * Copyright 2016-present Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
22 #pragma once
23 
24 #include <stdint.h>
25 
26 #include <limits>
27 #include <type_traits>
28 
29 namespace folly {
30 
31 namespace detail {
32 
33 template <typename T>
34 inline constexpr T divFloorBranchless(T num, T denom) {
35  // floor != trunc when the answer isn't exact and truncation went the
36  // wrong way (truncation went toward positive infinity). That happens
37  // when the true answer is negative, which happens when num and denom
38  // have different signs. The following code compiles branch-free on
39  // many platforms.
40  return (num / denom) +
41  ((num % denom) != 0 ? 1 : 0) *
42  (std::is_signed<T>::value && (num ^ denom) < 0 ? -1 : 0);
43 }
44 
45 template <typename T>
46 inline constexpr T divFloorBranchful(T num, T denom) {
47  // First case handles negative result by preconditioning numerator.
48  // Preconditioning decreases the magnitude of the numerator, which is
49  // itself sign-dependent. Second case handles zero or positive rational
50  // result, where trunc and floor are the same.
51  return std::is_signed<T>::value && (num ^ denom) < 0 && num != 0
52  ? (num + (num > 0 ? -1 : 1)) / denom - 1
53  : num / denom;
54 }
55 
56 template <typename T>
57 inline constexpr T divCeilBranchless(T num, T denom) {
58  // ceil != trunc when the answer isn't exact (truncation occurred)
59  // and truncation went away from positive infinity. That happens when
60  // the true answer is positive, which happens when num and denom have
61  // the same sign.
62  return (num / denom) +
63  ((num % denom) != 0 ? 1 : 0) *
64  (std::is_signed<T>::value && (num ^ denom) < 0 ? 0 : 1);
65 }
66 
67 template <typename T>
68 inline constexpr T divCeilBranchful(T num, T denom) {
69  // First case handles negative or zero rational result, where trunc and ceil
70  // are the same.
71  // Second case handles positive result by preconditioning numerator.
72  // Preconditioning decreases the magnitude of the numerator, which is
73  // itself sign-dependent.
74  return (std::is_signed<T>::value && (num ^ denom) < 0) || num == 0
75  ? num / denom
76  : (num + (num > 0 ? -1 : 1)) / denom + 1;
77 }
78 
79 template <typename T>
80 inline constexpr T divRoundAwayBranchless(T num, T denom) {
81  // away != trunc whenever truncation actually occurred, which is when
82  // there is a non-zero remainder. If the unrounded result is negative
83  // then fixup moves it toward negative infinity. If the unrounded
84  // result is positive then adjustment makes it larger.
85  return (num / denom) +
86  ((num % denom) != 0 ? 1 : 0) *
87  (std::is_signed<T>::value && (num ^ denom) < 0 ? -1 : 1);
88 }
89 
90 template <typename T>
91 inline constexpr T divRoundAwayBranchful(T num, T denom) {
92  // First case of second ternary operator handles negative rational
93  // result, which is the same as divFloor. Second case of second ternary
94  // operator handles positive result, which is the same as divCeil.
95  // Zero case is separated for simplicity.
96  return num == 0 ? 0
97  : (num + (num > 0 ? -1 : 1)) / denom +
98  (std::is_signed<T>::value && (num ^ denom) < 0 ? -1 : 1);
99 }
100 
101 template <typename N, typename D>
102 using IdivResultType = typename std::enable_if<
105  decltype(N{1} / D{1})>::type;
106 } // namespace detail
107 
108 #if defined(__arm__) && !FOLLY_AARCH64
109 constexpr auto kIntegerDivisionGivesRemainder = false;
110 #else
111 constexpr auto kIntegerDivisionGivesRemainder = true;
112 #endif
113 
131 template <typename N, typename D>
132 inline constexpr detail::IdivResultType<N, D> divFloor(N num, D denom) {
133  using R = decltype(num / denom);
135  kIntegerDivisionGivesRemainder && std::is_signed<R>::value
136  ? detail::divFloorBranchless<R>(num, denom)
137  : detail::divFloorBranchful<R>(num, denom));
138 }
139 
151 template <typename N, typename D>
152 inline constexpr detail::IdivResultType<N, D> divCeil(N num, D denom) {
153  using R = decltype(num / denom);
155  kIntegerDivisionGivesRemainder && std::is_signed<R>::value
156  ? detail::divCeilBranchless<R>(num, denom)
157  : detail::divCeilBranchful<R>(num, denom));
158 }
159 
177 template <typename N, typename D>
178 inline constexpr detail::IdivResultType<N, D> divTrunc(N num, D denom) {
179  return detail::IdivResultType<N, D>(num / denom);
180 }
181 
194 template <typename N, typename D>
195 inline constexpr detail::IdivResultType<N, D> divRoundAway(N num, D denom) {
196  using R = decltype(num / denom);
198  kIntegerDivisionGivesRemainder && std::is_signed<R>::value
199  ? detail::divRoundAwayBranchless<R>(num, denom)
200  : detail::divRoundAwayBranchful<R>(num, denom));
201 }
202 
203 } // namespace folly
typename std::enable_if< std::is_integral< N >::value &&std::is_integral< D >::value &&!std::is_same< N, bool >::value &&!std::is_same< D, bool >::value, decltype(N{1}/D{1})>::type IdivResultType
Definition: Math.h:105
constexpr T divRoundAwayBranchless(T num, T denom)
Definition: Math.h:80
constexpr T divFloorBranchful(T num, T denom)
Definition: Math.h:46
constexpr T divCeilBranchful(T num, T denom)
Definition: Math.h:68
PskType type
constexpr detail::IdivResultType< N, D > divTrunc(N num, D denom)
Definition: Math.h:178
folly::std T
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
constexpr detail::IdivResultType< N, D > divRoundAway(N num, D denom)
Definition: Math.h:195
constexpr detail::IdivResultType< N, D > divFloor(N num, D denom)
Definition: Math.h:132
constexpr detail::IdivResultType< N, D > divCeil(N num, D denom)
Definition: Math.h:152
#define D(name, bit)
Definition: CpuId.h:145
constexpr auto kIntegerDivisionGivesRemainder
Definition: Math.h:111
static const char *const value
Definition: Conv.cpp:50
constexpr T divRoundAwayBranchful(T num, T denom)
Definition: Math.h:91
constexpr T divCeilBranchless(T num, T denom)
Definition: Math.h:57
constexpr T divFloorBranchless(T num, T denom)
Definition: Math.h:34