1 /* Boost interval/detail/msvc_rounding_control.hpp file 2 * 3 * Copyright 2000 Maarten Keijzer 4 * Copyright 2002 Herv� Br�nnimann, Guillaume Melquiond, Sylvain Pion 5 * 6 * Distributed under the Boost Software License, Version 1.0. 7 * (See accompanying file LICENSE_1_0.txt or 8 * copy at http://www.boost.org/LICENSE_1_0.txt) 9 */ 10 11 #ifndef BOOST_NUMERIC_INTERVAL_DETAIL_MSVC_ROUNDING_CONTROL_HPP 12 #define BOOST_NUMERIC_INTERVAL_DETAIL_MSVC_ROUNDING_CONTROL_HPP 13 14 #ifndef _MSC_VER 15 # error This header is only intended for MSVC, but might work for Borland as well 16 #endif 17 18 #include <float.h> // MSVC rounding control 19 20 // Although the function is called _control87, it seems to work for 21 // other FPUs too, so it does not have to be changed to _controlfp. 22 23 namespace boost { 24 namespace numeric { 25 namespace interval_lib { 26 namespace detail { 27 28 #if BOOST_MSVC < 1400 || defined(_WIN64) 29 extern "C" { double rint(double); } 30 #else 31 inline double rint(double x) 32 { 33 _asm FLD [x] ; 34 _asm FRNDINT ; 35 //_asm RET ; 36 } 37 #endif 38 39 struct x86_rounding 40 { hard2msvcboost::numeric::interval_lib::detail::x86_rounding41 static unsigned int hard2msvc(unsigned short m) { 42 unsigned int n = 0; 43 if (m & 0x01) n |= _EM_INVALID; 44 if (m & 0x02) n |= _EM_DENORMAL; 45 if (m & 0x04) n |= _EM_ZERODIVIDE; 46 if (m & 0x08) n |= _EM_OVERFLOW; 47 if (m & 0x10) n |= _EM_UNDERFLOW; 48 if (m & 0x20) n |= _EM_INEXACT; 49 switch (m & 0x300) { 50 case 0x000: n |= _PC_24; break; 51 case 0x200: n |= _PC_53; break; 52 case 0x300: n |= _PC_64; break; 53 } 54 switch (m & 0xC00) { 55 case 0x000: n |= _RC_NEAR; break; 56 case 0x400: n |= _RC_DOWN; break; 57 case 0x800: n |= _RC_UP; break; 58 case 0xC00: n |= _RC_CHOP; break; 59 } 60 if (m & 0x1000) n |= _IC_AFFINE; // only useful on 287 61 return n; 62 } 63 msvc2hardboost::numeric::interval_lib::detail::x86_rounding64 static unsigned short msvc2hard(unsigned int n) { 65 unsigned short m = 0; 66 if (n & _EM_INVALID) m |= 0x01; 67 if (n & _EM_DENORMAL) m |= 0x02; 68 if (n & _EM_ZERODIVIDE) m |= 0x04; 69 if (n & _EM_OVERFLOW) m |= 0x08; 70 if (n & _EM_UNDERFLOW) m |= 0x10; 71 if (n & _EM_INEXACT) m |= 0x20; 72 switch (n & _MCW_RC) { 73 case _RC_NEAR: m |= 0x000; break; 74 case _RC_DOWN: m |= 0x400; break; 75 case _RC_UP: m |= 0x800; break; 76 case _RC_CHOP: m |= 0xC00; break; 77 } 78 switch (n & _MCW_PC) { 79 case _PC_24: m |= 0x000; break; 80 case _PC_53: m |= 0x200; break; 81 case _PC_64: m |= 0x300; break; 82 } 83 if ((n & _MCW_IC) == _IC_AFFINE) m |= 0x1000; 84 return m; 85 } 86 87 typedef unsigned short rounding_mode; get_rounding_modeboost::numeric::interval_lib::detail::x86_rounding88 static void get_rounding_mode(rounding_mode& mode) 89 { mode = msvc2hard(_control87(0, 0)); } set_rounding_modeboost::numeric::interval_lib::detail::x86_rounding90 static void set_rounding_mode(const rounding_mode mode) 91 { 92 _control87(hard2msvc(mode), 93 _MCW_EM | _MCW_RC 94 #if !defined(_M_AMD64) && !defined(_M_ARM) 95 // x64 ignores _MCW_PC and _MCW_IC, and the Debug CRT library actually 96 // asserts when these are passed to _control87. 97 // MSDN says on '_control87' that changing precision (_MCW_PC) or 98 // infinity (_MCW_IC) handling is not supported on the ARM and x64 99 // architectures and that _control87 raises an assertion 100 // and the invalid parameter handler is invoked. 101 | _MCW_PC | _MCW_IC 102 #endif 103 ); 104 } to_intboost::numeric::interval_lib::detail::x86_rounding105 static double to_int(const double& x) { return rint(x); } 106 }; 107 108 } // namespace detail 109 } // namespace interval_lib 110 } // namespace numeric 111 } // namespace boost 112 113 #endif /* BOOST_NUMERIC_INTERVAL_DETAIL_MSVC_ROUNDING_CONTROL_HPP */ 114