Chris@102
|
1 /////////////////////////////////////////////////////////////////////////////
|
Chris@102
|
2 //
|
Chris@102
|
3 // (C) Copyright Ion Gaztanaga 2014-2014
|
Chris@102
|
4 //
|
Chris@102
|
5 // Distributed under the Boost Software License, Version 1.0.
|
Chris@102
|
6 // (See accompanying file LICENSE_1_0.txt or copy at
|
Chris@102
|
7 // http://www.boost.org/LICENSE_1_0.txt)
|
Chris@102
|
8 //
|
Chris@102
|
9 // See http://www.boost.org/libs/intrusive for documentation.
|
Chris@102
|
10 //
|
Chris@102
|
11 /////////////////////////////////////////////////////////////////////////////
|
Chris@102
|
12
|
Chris@102
|
13 #ifndef BOOST_INTRUSIVE_DETAIL_MATH_HPP
|
Chris@102
|
14 #define BOOST_INTRUSIVE_DETAIL_MATH_HPP
|
Chris@102
|
15
|
Chris@102
|
16 #ifndef BOOST_CONFIG_HPP
|
Chris@102
|
17 # include <boost/config.hpp>
|
Chris@102
|
18 #endif
|
Chris@102
|
19
|
Chris@102
|
20 #if defined(BOOST_HAS_PRAGMA_ONCE)
|
Chris@102
|
21 # pragma once
|
Chris@102
|
22 #endif
|
Chris@102
|
23
|
Chris@102
|
24 #include <cstddef>
|
Chris@102
|
25 #include <climits>
|
Chris@102
|
26
|
Chris@102
|
27 namespace boost {
|
Chris@102
|
28 namespace intrusive {
|
Chris@102
|
29 namespace detail {
|
Chris@102
|
30
|
Chris@102
|
31 ///////////////////////////
|
Chris@102
|
32 // floor_log2 Dispatcher
|
Chris@102
|
33 ////////////////////////////
|
Chris@102
|
34
|
Chris@102
|
35 #if defined(_MSC_VER) && (_MSC_VER >= 1300)
|
Chris@102
|
36
|
Chris@102
|
37 }}} //namespace boost::intrusive::detail
|
Chris@102
|
38
|
Chris@102
|
39 //Use _BitScanReverseXX intrinsics
|
Chris@102
|
40
|
Chris@102
|
41 #if defined(_M_X64) || defined(_M_AMD64) || defined(_M_IA64) //64 bit target
|
Chris@102
|
42 #define BOOST_INTRUSIVE_BSR_INTRINSIC_64_BIT
|
Chris@102
|
43 #endif
|
Chris@102
|
44
|
Chris@102
|
45 #ifndef __INTRIN_H_ // Avoid including any windows system header
|
Chris@102
|
46 #ifdef __cplusplus
|
Chris@102
|
47 extern "C" {
|
Chris@102
|
48 #endif // __cplusplus
|
Chris@102
|
49
|
Chris@102
|
50 #if defined(BOOST_INTRUSIVE_BSR_INTRINSIC_64_BIT) //64 bit target
|
Chris@102
|
51 unsigned char _BitScanReverse64(unsigned long *index, unsigned __int64 mask);
|
Chris@102
|
52 #pragma intrinsic(_BitScanReverse64)
|
Chris@102
|
53 #else //32 bit target
|
Chris@102
|
54 unsigned char _BitScanReverse(unsigned long *index, unsigned long mask);
|
Chris@102
|
55 #pragma intrinsic(_BitScanReverse)
|
Chris@102
|
56 #endif
|
Chris@102
|
57
|
Chris@102
|
58 #ifdef __cplusplus
|
Chris@102
|
59 }
|
Chris@102
|
60 #endif // __cplusplus
|
Chris@102
|
61 #endif // __INTRIN_H_
|
Chris@102
|
62
|
Chris@102
|
63 #ifdef BOOST_INTRUSIVE_BSR_INTRINSIC_64_BIT
|
Chris@102
|
64 #define BOOST_INTRUSIVE_BSR_INTRINSIC _BitScanReverse64
|
Chris@102
|
65 #undef BOOST_INTRUSIVE_BSR_INTRINSIC_64_BIT
|
Chris@102
|
66 #else
|
Chris@102
|
67 #define BOOST_INTRUSIVE_BSR_INTRINSIC _BitScanReverse
|
Chris@102
|
68 #endif
|
Chris@102
|
69
|
Chris@102
|
70 namespace boost {
|
Chris@102
|
71 namespace intrusive {
|
Chris@102
|
72 namespace detail {
|
Chris@102
|
73
|
Chris@102
|
74 inline std::size_t floor_log2 (std::size_t x)
|
Chris@102
|
75 {
|
Chris@102
|
76 unsigned long log2;
|
Chris@102
|
77 BOOST_INTRUSIVE_BSR_INTRINSIC( &log2, (unsigned long)x );
|
Chris@102
|
78 return log2;
|
Chris@102
|
79 }
|
Chris@102
|
80
|
Chris@102
|
81 #undef BOOST_INTRUSIVE_BSR_INTRINSIC
|
Chris@102
|
82
|
Chris@102
|
83 #elif defined(__GNUC__) && ((__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) //GCC >=3.4
|
Chris@102
|
84
|
Chris@102
|
85 //Compile-time error in case of missing specialization
|
Chris@102
|
86 template<class Uint>
|
Chris@102
|
87 struct builtin_clz_dispatch;
|
Chris@102
|
88
|
Chris@102
|
89 #if defined(BOOST_HAS_LONG_LONG)
|
Chris@102
|
90 template<>
|
Chris@102
|
91 struct builtin_clz_dispatch< ::boost::ulong_long_type >
|
Chris@102
|
92 {
|
Chris@102
|
93 static ::boost::ulong_long_type call(::boost::ulong_long_type n)
|
Chris@102
|
94 { return __builtin_clzll(n); }
|
Chris@102
|
95 };
|
Chris@102
|
96 #endif
|
Chris@102
|
97
|
Chris@102
|
98 template<>
|
Chris@102
|
99 struct builtin_clz_dispatch<unsigned long>
|
Chris@102
|
100 {
|
Chris@102
|
101 static unsigned long call(unsigned long n)
|
Chris@102
|
102 { return __builtin_clzl(n); }
|
Chris@102
|
103 };
|
Chris@102
|
104
|
Chris@102
|
105 template<>
|
Chris@102
|
106 struct builtin_clz_dispatch<unsigned int>
|
Chris@102
|
107 {
|
Chris@102
|
108 static unsigned int call(unsigned int n)
|
Chris@102
|
109 { return __builtin_clz(n); }
|
Chris@102
|
110 };
|
Chris@102
|
111
|
Chris@102
|
112 inline std::size_t floor_log2(std::size_t n)
|
Chris@102
|
113 {
|
Chris@102
|
114 return sizeof(std::size_t)*CHAR_BIT - std::size_t(1) - builtin_clz_dispatch<std::size_t>::call(n);
|
Chris@102
|
115 }
|
Chris@102
|
116
|
Chris@102
|
117 #else //Portable methods
|
Chris@102
|
118
|
Chris@102
|
119 ////////////////////////////
|
Chris@102
|
120 // Generic method
|
Chris@102
|
121 ////////////////////////////
|
Chris@102
|
122
|
Chris@102
|
123 inline std::size_t floor_log2_get_shift(std::size_t n, true_ )//power of two size_t
|
Chris@102
|
124 { return n >> 1; }
|
Chris@102
|
125
|
Chris@102
|
126 inline std::size_t floor_log2_get_shift(std::size_t n, false_ )//non-power of two size_t
|
Chris@102
|
127 { return (n >> 1) + ((n & 1u) & (n != 1)); }
|
Chris@102
|
128
|
Chris@102
|
129 template<std::size_t N>
|
Chris@102
|
130 inline std::size_t floor_log2 (std::size_t x, integer<std::size_t, N>)
|
Chris@102
|
131 {
|
Chris@102
|
132 const std::size_t Bits = N;
|
Chris@102
|
133 const bool Size_t_Bits_Power_2= !(Bits & (Bits-1));
|
Chris@102
|
134
|
Chris@102
|
135 std::size_t n = x;
|
Chris@102
|
136 std::size_t log2 = 0;
|
Chris@102
|
137
|
Chris@102
|
138 std::size_t remaining_bits = Bits;
|
Chris@102
|
139 std::size_t shift = floor_log2_get_shift(remaining_bits, bool_<Size_t_Bits_Power_2>());
|
Chris@102
|
140 while(shift){
|
Chris@102
|
141 std::size_t tmp = n >> shift;
|
Chris@102
|
142 if (tmp){
|
Chris@102
|
143 log2 += shift, n = tmp;
|
Chris@102
|
144 }
|
Chris@102
|
145 shift = floor_log2_get_shift(shift, bool_<Size_t_Bits_Power_2>());
|
Chris@102
|
146 }
|
Chris@102
|
147
|
Chris@102
|
148 return log2;
|
Chris@102
|
149 }
|
Chris@102
|
150
|
Chris@102
|
151 ////////////////////////////
|
Chris@102
|
152 // DeBruijn method
|
Chris@102
|
153 ////////////////////////////
|
Chris@102
|
154
|
Chris@102
|
155 //Taken from:
|
Chris@102
|
156 //http://stackoverflow.com/questions/11376288/fast-computing-of-log2-for-64-bit-integers
|
Chris@102
|
157 //Thanks to Desmond Hume
|
Chris@102
|
158
|
Chris@102
|
159 inline std::size_t floor_log2 (std::size_t v, integer<std::size_t, 32>)
|
Chris@102
|
160 {
|
Chris@102
|
161 static const int MultiplyDeBruijnBitPosition[32] =
|
Chris@102
|
162 {
|
Chris@102
|
163 0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30,
|
Chris@102
|
164 8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31
|
Chris@102
|
165 };
|
Chris@102
|
166
|
Chris@102
|
167 v |= v >> 1;
|
Chris@102
|
168 v |= v >> 2;
|
Chris@102
|
169 v |= v >> 4;
|
Chris@102
|
170 v |= v >> 8;
|
Chris@102
|
171 v |= v >> 16;
|
Chris@102
|
172
|
Chris@102
|
173 return MultiplyDeBruijnBitPosition[(std::size_t)(v * 0x07C4ACDDU) >> 27];
|
Chris@102
|
174 }
|
Chris@102
|
175
|
Chris@102
|
176 inline std::size_t floor_log2 (std::size_t v, integer<std::size_t, 64>)
|
Chris@102
|
177 {
|
Chris@102
|
178 static const std::size_t MultiplyDeBruijnBitPosition[64] = {
|
Chris@102
|
179 63, 0, 58, 1, 59, 47, 53, 2,
|
Chris@102
|
180 60, 39, 48, 27, 54, 33, 42, 3,
|
Chris@102
|
181 61, 51, 37, 40, 49, 18, 28, 20,
|
Chris@102
|
182 55, 30, 34, 11, 43, 14, 22, 4,
|
Chris@102
|
183 62, 57, 46, 52, 38, 26, 32, 41,
|
Chris@102
|
184 50, 36, 17, 19, 29, 10, 13, 21,
|
Chris@102
|
185 56, 45, 25, 31, 35, 16, 9, 12,
|
Chris@102
|
186 44, 24, 15, 8, 23, 7, 6, 5};
|
Chris@102
|
187
|
Chris@102
|
188 v |= v >> 1;
|
Chris@102
|
189 v |= v >> 2;
|
Chris@102
|
190 v |= v >> 4;
|
Chris@102
|
191 v |= v >> 8;
|
Chris@102
|
192 v |= v >> 16;
|
Chris@102
|
193 v |= v >> 32;
|
Chris@102
|
194 return MultiplyDeBruijnBitPosition[((std::size_t)((v - (v >> 1))*0x07EDD5E59A4E28C2ULL)) >> 58];
|
Chris@102
|
195 }
|
Chris@102
|
196
|
Chris@102
|
197
|
Chris@102
|
198 inline std::size_t floor_log2 (std::size_t x)
|
Chris@102
|
199 {
|
Chris@102
|
200 const std::size_t Bits = sizeof(std::size_t)*CHAR_BIT;
|
Chris@102
|
201 return floor_log2(x, integer<std::size_t, Bits>());
|
Chris@102
|
202 }
|
Chris@102
|
203
|
Chris@102
|
204 #endif
|
Chris@102
|
205
|
Chris@102
|
206 //Thanks to Laurent de Soras in
|
Chris@102
|
207 //http://www.flipcode.com/archives/Fast_log_Function.shtml
|
Chris@102
|
208 inline float fast_log2 (float val)
|
Chris@102
|
209 {
|
Chris@102
|
210 union caster_t
|
Chris@102
|
211 {
|
Chris@102
|
212 unsigned x;
|
Chris@102
|
213 float val;
|
Chris@102
|
214 } caster;
|
Chris@102
|
215
|
Chris@102
|
216 caster.val = val;
|
Chris@102
|
217 unsigned x = caster.x;
|
Chris@102
|
218 const int log_2 = int((x >> 23) & 255) - 128;
|
Chris@102
|
219 x &= ~(unsigned(255u) << 23u);
|
Chris@102
|
220 x += unsigned(127) << 23u;
|
Chris@102
|
221 caster.x = x;
|
Chris@102
|
222 val = caster.val;
|
Chris@102
|
223 //1+log2(m), m ranging from 1 to 2
|
Chris@102
|
224 //3rd degree polynomial keeping first derivate continuity.
|
Chris@102
|
225 //For less precision the line can be commented out
|
Chris@102
|
226 val = ((-1.f/3.f) * val + 2.f) * val - (2.f/3.f);
|
Chris@102
|
227 return val + static_cast<float>(log_2);
|
Chris@102
|
228 }
|
Chris@102
|
229
|
Chris@102
|
230 inline std::size_t ceil_log2 (std::size_t x)
|
Chris@102
|
231 {
|
Chris@102
|
232 return static_cast<std::size_t>((x & (x-1)) != 0) + floor_log2(x);
|
Chris@102
|
233 }
|
Chris@102
|
234
|
Chris@102
|
235 template<class SizeType, std::size_t N>
|
Chris@102
|
236 struct numbits_eq
|
Chris@102
|
237 {
|
Chris@102
|
238 static const bool value = sizeof(SizeType)*CHAR_BIT == N;
|
Chris@102
|
239 };
|
Chris@102
|
240
|
Chris@102
|
241 template<class SizeType, class Enabler = void >
|
Chris@102
|
242 struct sqrt2_pow_max;
|
Chris@102
|
243
|
Chris@102
|
244 template <class SizeType>
|
Chris@102
|
245 struct sqrt2_pow_max<SizeType, typename enable_if< numbits_eq<SizeType, 32> >::type>
|
Chris@102
|
246 {
|
Chris@102
|
247 static const SizeType value = 0xb504f334;
|
Chris@102
|
248 static const std::size_t pow = 31;
|
Chris@102
|
249 };
|
Chris@102
|
250
|
Chris@102
|
251 #ifndef BOOST_NO_INT64_T
|
Chris@102
|
252
|
Chris@102
|
253 template <class SizeType>
|
Chris@102
|
254 struct sqrt2_pow_max<SizeType, typename enable_if< numbits_eq<SizeType, 64> >::type>
|
Chris@102
|
255 {
|
Chris@102
|
256 static const SizeType value = 0xb504f333f9de6484ull;
|
Chris@102
|
257 static const std::size_t pow = 63;
|
Chris@102
|
258 };
|
Chris@102
|
259
|
Chris@102
|
260 #endif //BOOST_NO_INT64_T
|
Chris@102
|
261
|
Chris@102
|
262 // Returns floor(pow(sqrt(2), x * 2 + 1)).
|
Chris@102
|
263 // Defined for X from 0 up to the number of bits in size_t minus 1.
|
Chris@102
|
264 inline std::size_t sqrt2_pow_2xplus1 (std::size_t x)
|
Chris@102
|
265 {
|
Chris@102
|
266 const std::size_t value = (std::size_t)sqrt2_pow_max<std::size_t>::value;
|
Chris@102
|
267 const std::size_t pow = (std::size_t)sqrt2_pow_max<std::size_t>::pow;
|
Chris@102
|
268 return (value >> (pow - x)) + 1;
|
Chris@102
|
269 }
|
Chris@102
|
270
|
Chris@102
|
271 } //namespace detail
|
Chris@102
|
272 } //namespace intrusive
|
Chris@102
|
273 } //namespace boost
|
Chris@102
|
274
|
Chris@102
|
275 #endif //BOOST_INTRUSIVE_DETAIL_MATH_HPP
|