Mercurial > hg > vamp-build-and-test
comparison DEPENDENCIES/generic/include/boost/multiprecision/detail/generic_interconvert.hpp @ 101:c530137014c0
Update Boost headers (1.58.0)
author | Chris Cannam |
---|---|
date | Mon, 07 Sep 2015 11:12:49 +0100 |
parents | 2665513ce2d3 |
children |
comparison
equal
deleted
inserted
replaced
100:793467b5e61c | 101:c530137014c0 |
---|---|
6 #ifndef BOOST_MP_GENERIC_INTERCONVERT_HPP | 6 #ifndef BOOST_MP_GENERIC_INTERCONVERT_HPP |
7 #define BOOST_MP_GENERIC_INTERCONVERT_HPP | 7 #define BOOST_MP_GENERIC_INTERCONVERT_HPP |
8 | 8 |
9 #include <boost/multiprecision/detail/default_ops.hpp> | 9 #include <boost/multiprecision/detail/default_ops.hpp> |
10 | 10 |
11 #ifdef BOOST_MSVC | |
12 #pragma warning(push) | |
13 #pragma warning(disable:4127) | |
14 #endif | |
15 | |
11 namespace boost{ namespace multiprecision{ namespace detail{ | 16 namespace boost{ namespace multiprecision{ namespace detail{ |
17 | |
18 template <class To, class From> | |
19 inline To do_cast(const From & from) | |
20 { | |
21 return static_cast<To>(from); | |
22 } | |
23 template <class To, class B, ::boost::multiprecision::expression_template_option et> | |
24 inline To do_cast(const number<B, et>& from) | |
25 { | |
26 return from.template convert_to<To>(); | |
27 } | |
12 | 28 |
13 template <class To, class From> | 29 template <class To, class From> |
14 void generic_interconvert(To& to, const From& from, const mpl::int_<number_kind_floating_point>& /*to_type*/, const mpl::int_<number_kind_integer>& /*from_type*/) | 30 void generic_interconvert(To& to, const From& from, const mpl::int_<number_kind_floating_point>& /*to_type*/, const mpl::int_<number_kind_integer>& /*from_type*/) |
15 { | 31 { |
16 using default_ops::eval_get_sign; | 32 using default_ops::eval_get_sign; |
134 // | 150 // |
135 // First classify the input, then handle the special cases: | 151 // First classify the input, then handle the special cases: |
136 // | 152 // |
137 int c = eval_fpclassify(from); | 153 int c = eval_fpclassify(from); |
138 | 154 |
139 if(c == FP_ZERO) | 155 if(c == (int)FP_ZERO) |
140 { | 156 { |
141 to = ui_type(0); | 157 to = ui_type(0); |
142 return; | 158 return; |
143 } | 159 } |
144 else if(c == FP_NAN) | 160 else if(c == (int)FP_NAN) |
145 { | 161 { |
146 to = "nan"; | 162 to = static_cast<const char*>("nan"); |
147 return; | 163 return; |
148 } | 164 } |
149 else if(c == FP_INFINITE) | 165 else if(c == (int)FP_INFINITE) |
150 { | 166 { |
151 to = "inf"; | 167 to = static_cast<const char*>("inf"); |
152 if(eval_get_sign(from) < 0) | 168 if(eval_get_sign(from) < 0) |
153 to.negate(); | 169 to.negate(); |
154 return; | 170 return; |
155 } | 171 } |
156 | 172 |
175 eval_subtract(f, term); | 191 eval_subtract(f, term); |
176 } | 192 } |
177 typedef typename To::exponent_type to_exponent; | 193 typedef typename To::exponent_type to_exponent; |
178 if((e > (std::numeric_limits<to_exponent>::max)()) || (e < (std::numeric_limits<to_exponent>::min)())) | 194 if((e > (std::numeric_limits<to_exponent>::max)()) || (e < (std::numeric_limits<to_exponent>::min)())) |
179 { | 195 { |
180 to = "inf"; | 196 to = static_cast<const char*>("inf"); |
181 if(eval_get_sign(from) < 0) | 197 if(eval_get_sign(from) < 0) |
182 to.negate(); | 198 to.negate(); |
183 return; | 199 return; |
184 } | 200 } |
185 eval_ldexp(to, to, static_cast<to_exponent>(e)); | 201 eval_ldexp(to, to, static_cast<to_exponent>(e)); |
208 to_component_type n(t), d(1); | 224 to_component_type n(t), d(1); |
209 using default_ops::assign_components; | 225 using default_ops::assign_components; |
210 assign_components(to, n.backend(), d.backend()); | 226 assign_components(to, n.backend(), d.backend()); |
211 } | 227 } |
212 | 228 |
213 template <class To, class From> | 229 template <class R, class LargeInteger> |
214 void generic_interconvert(To& to, const From& from, const mpl::int_<number_kind_floating_point>& /*to_type*/, const mpl::int_<number_kind_rational>& /*from_type*/) | 230 R safe_convert_to_float(const LargeInteger& i) |
215 { | 231 { |
216 typedef typename component_type<number<From> >::type from_component_type; | 232 using std::ldexp; |
233 if(!i) | |
234 return R(0); | |
235 if(std::numeric_limits<R>::is_specialized && std::numeric_limits<R>::max_exponent) | |
236 { | |
237 LargeInteger val(i); | |
238 if(val.sign() < 0) | |
239 val = -val; | |
240 unsigned mb = msb(val); | |
241 if(mb >= std::numeric_limits<R>::max_exponent) | |
242 { | |
243 int scale_factor = (int)mb + 1 - std::numeric_limits<R>::max_exponent; | |
244 BOOST_ASSERT(scale_factor >= 1); | |
245 val >>= scale_factor; | |
246 R result = val.template convert_to<R>(); | |
247 if(std::numeric_limits<R>::digits == 0 || std::numeric_limits<R>::digits >= std::numeric_limits<R>::max_exponent) | |
248 { | |
249 // | |
250 // Calculate and add on the remainder, only if there are more | |
251 // digits in the mantissa that the size of the exponent, in | |
252 // other words if we are dropping digits in the conversion | |
253 // otherwise: | |
254 // | |
255 LargeInteger remainder(i); | |
256 remainder &= (LargeInteger(1) << scale_factor) - 1; | |
257 result += ldexp(safe_convert_to_float<R>(remainder), -scale_factor); | |
258 } | |
259 return i.sign() < 0 ? static_cast<R>(-result) : result; | |
260 } | |
261 } | |
262 return i.template convert_to<R>(); | |
263 } | |
264 | |
265 template <class To, class Integer> | |
266 inline typename disable_if_c<is_number<To>::value || is_floating_point<To>::value>::type | |
267 generic_convert_rational_to_float_imp(To& result, const Integer& n, const Integer& d, const mpl::true_&) | |
268 { | |
269 // | |
270 // If we get here, then there's something about one type or the other | |
271 // that prevents an exactly rounded result from being calculated | |
272 // (or at least it's not clear how to implement such a thing). | |
273 // | |
217 using default_ops::eval_divide; | 274 using default_ops::eval_divide; |
218 | 275 number<To> fn(safe_convert_to_float<number<To> >(n)), fd(safe_convert_to_float<number<To> >(d)); |
219 number<From> t(from); | 276 eval_divide(result, fn.backend(), fd.backend()); |
220 from_component_type n(numerator(t)), d(denominator(t)); | 277 } |
221 number<To> fn(n), fd(d); | 278 template <class To, class Integer> |
222 eval_divide(to, fn.backend(), fd.backend()); | 279 inline typename enable_if_c<is_number<To>::value || is_floating_point<To>::value>::type |
280 generic_convert_rational_to_float_imp(To& result, const Integer& n, const Integer& d, const mpl::true_&) | |
281 { | |
282 // | |
283 // If we get here, then there's something about one type or the other | |
284 // that prevents an exactly rounded result from being calculated | |
285 // (or at least it's not clear how to implement such a thing). | |
286 // | |
287 To fd(safe_convert_to_float<To>(d)); | |
288 result = safe_convert_to_float<To>(n); | |
289 result /= fd; | |
290 } | |
291 | |
292 template <class To, class Integer> | |
293 typename enable_if_c<is_number<To>::value || is_floating_point<To>::value>::type | |
294 generic_convert_rational_to_float_imp(To& result, Integer& num, Integer& denom, const mpl::false_&) | |
295 { | |
296 // | |
297 // If we get here, then the precision of type To is known, and the integer type is unbounded | |
298 // so we can use integer division plus manipulation of the remainder to get an exactly | |
299 // rounded result. | |
300 // | |
301 if(num == 0) | |
302 { | |
303 result = 0; | |
304 return; | |
305 } | |
306 bool s = false; | |
307 if(num < 0) | |
308 { | |
309 s = true; | |
310 num = -num; | |
311 } | |
312 int denom_bits = msb(denom); | |
313 int shift = std::numeric_limits<To>::digits + denom_bits - msb(num) + 1; | |
314 if(shift > 0) | |
315 num <<= shift; | |
316 else if(shift < 0) | |
317 denom <<= std::abs(shift); | |
318 Integer q, r; | |
319 divide_qr(num, denom, q, r); | |
320 int q_bits = msb(q); | |
321 if(q_bits == std::numeric_limits<To>::digits) | |
322 { | |
323 // | |
324 // Round up if 2 * r > denom: | |
325 // | |
326 r <<= 1; | |
327 int c = r.compare(denom); | |
328 if(c > 0) | |
329 ++q; | |
330 else if((c == 0) && (q & 1u)) | |
331 { | |
332 ++q; | |
333 } | |
334 } | |
335 else | |
336 { | |
337 BOOST_ASSERT(q_bits == 1 + std::numeric_limits<To>::digits); | |
338 // | |
339 // We basically already have the rounding info: | |
340 // | |
341 if(q & 1u) | |
342 { | |
343 if(r || (q & 2u)) | |
344 ++q; | |
345 } | |
346 } | |
347 using std::ldexp; | |
348 result = do_cast<To>(q); | |
349 result = ldexp(result, -shift); | |
350 if(s) | |
351 result = -result; | |
352 } | |
353 template <class To, class Integer> | |
354 inline typename disable_if_c<is_number<To>::value || is_floating_point<To>::value>::type | |
355 generic_convert_rational_to_float_imp(To& result, Integer& num, Integer& denom, const mpl::false_& tag) | |
356 { | |
357 number<To> t; | |
358 generic_convert_rational_to_float_imp(t, num, denom, tag); | |
359 result = t.backend(); | |
360 } | |
361 | |
362 template <class To, class From> | |
363 inline void generic_convert_rational_to_float(To& result, const From& f) | |
364 { | |
365 // | |
366 // Type From is always a Backend to number<>, or an | |
367 // instance of number<>, but we allow | |
368 // To to be either a Backend type, or a real number type, | |
369 // that way we can call this from generic conversions, and | |
370 // from specific conversions to built in types. | |
371 // | |
372 typedef typename mpl::if_c<is_number<From>::value, From, number<From> >::type actual_from_type; | |
373 typedef typename mpl::if_c<is_number<To>::value || is_floating_point<To>::value, To, number<To> >::type actual_to_type; | |
374 typedef typename component_type<actual_from_type>::type integer_type; | |
375 typedef mpl::bool_<!std::numeric_limits<integer_type>::is_specialized | |
376 || std::numeric_limits<integer_type>::is_bounded | |
377 || !std::numeric_limits<actual_to_type>::is_specialized | |
378 || !std::numeric_limits<actual_to_type>::is_bounded | |
379 || (std::numeric_limits<actual_to_type>::radix != 2)> dispatch_tag; | |
380 | |
381 integer_type n(numerator(static_cast<actual_from_type>(f))), d(denominator(static_cast<actual_from_type>(f))); | |
382 generic_convert_rational_to_float_imp(result, n, d, dispatch_tag()); | |
383 } | |
384 | |
385 template <class To, class From> | |
386 inline void generic_interconvert(To& to, const From& from, const mpl::int_<number_kind_floating_point>& /*to_type*/, const mpl::int_<number_kind_rational>& /*from_type*/) | |
387 { | |
388 generic_convert_rational_to_float(to, from); | |
389 } | |
390 | |
391 template <class To, class From> | |
392 void generic_interconvert_float2rational(To& to, const From& from, const mpl::int_<2>& /*radix*/) | |
393 { | |
394 typedef typename mpl::front<typename To::unsigned_types>::type ui_type; | |
395 static const int shift = std::numeric_limits<long long>::digits; | |
396 typename From::exponent_type e; | |
397 typename component_type<number<To> >::type num, denom; | |
398 number<From> val(from); | |
399 val = frexp(val, &e); | |
400 while(val) | |
401 { | |
402 val = ldexp(val, shift); | |
403 e -= shift; | |
404 long long ll = boost::math::lltrunc(val); | |
405 val -= ll; | |
406 num <<= shift; | |
407 num += ll; | |
408 } | |
409 denom = ui_type(1u); | |
410 if(e < 0) | |
411 denom <<= -e; | |
412 else if(e > 0) | |
413 num <<= e; | |
414 assign_components(to, num.backend(), denom.backend()); | |
415 } | |
416 | |
417 template <class To, class From, int Radix> | |
418 void generic_interconvert_float2rational(To& to, const From& from, const mpl::int_<Radix>& /*radix*/) | |
419 { | |
420 // | |
421 // This is almost the same as the binary case above, but we have to use | |
422 // scalbn and ilogb rather than ldexp and frexp, we also only extract | |
423 // one Radix digit at a time which is terribly inefficient! | |
424 // | |
425 typedef typename mpl::front<typename To::unsigned_types>::type ui_type; | |
426 typename From::exponent_type e; | |
427 typename component_type<To>::type num, denom; | |
428 number<From> val(from); | |
429 e = ilogb(val); | |
430 val = scalbn(val, -e); | |
431 while(val) | |
432 { | |
433 long long ll = boost::math::lltrunc(val); | |
434 val -= ll; | |
435 val = scalbn(val, 1); | |
436 num *= Radix; | |
437 num += ll; | |
438 --e; | |
439 } | |
440 ++e; | |
441 denom = ui_type(Radix); | |
442 denom = pow(denom, abs(e)); | |
443 if(e > 0) | |
444 { | |
445 num *= denom; | |
446 denom = 1; | |
447 } | |
448 assign_components(to, num, denom); | |
449 } | |
450 | |
451 template <class To, class From> | |
452 void generic_interconvert(To& to, const From& from, const mpl::int_<number_kind_rational>& /*to_type*/, const mpl::int_<number_kind_floating_point>& /*from_type*/) | |
453 { | |
454 generic_interconvert_float2rational(to, from, mpl::int_<std::numeric_limits<number<From> >::radix>()); | |
223 } | 455 } |
224 | 456 |
225 }}} // namespaces | 457 }}} // namespaces |
226 | 458 |
459 #ifdef BOOST_MSVC | |
460 #pragma warning(pop) | |
461 #endif | |
462 | |
227 #endif // BOOST_MP_GENERIC_INTERCONVERT_HPP | 463 #endif // BOOST_MP_GENERIC_INTERCONVERT_HPP |
228 | 464 |