BWAPI
|
00001 // Copyright (c) 1998-2008 Utrecht University (The Netherlands), 00002 // ETH Zurich (Switzerland), Freie Universitaet Berlin (Germany), 00003 // INRIA Sophia-Antipolis (France), Martin-Luther-University Halle-Wittenberg 00004 // (Germany), Max-Planck-Institute Saarbruecken (Germany), RISC Linz (Austria), 00005 // and Tel-Aviv University (Israel). All rights reserved. 00006 // 00007 // This file is part of CGAL (www.cgal.org); you can redistribute it and/or 00008 // modify it under the terms of the GNU Lesser General Public License as 00009 // published by the Free Software Foundation; version 2.1 of the License. 00010 // See the file LICENSE.LGPL distributed with CGAL. 00011 // 00012 // Licensees holding a valid commercial license may use this file in 00013 // accordance with the commercial license agreement provided with the software. 00014 // 00015 // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE 00016 // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 00017 // 00018 // $URL: svn+ssh://scm.gforge.inria.fr/svn/cgal/branches/CGAL-3.5-branch/Number_types/include/CGAL/FPU.h $ 00019 // $Id: FPU.h 47204 2008-12-03 14:43:43Z spion $ 00020 // 00021 // 00022 // Author(s) : Sylvain Pion 00023 00024 #ifndef CGAL_FPU_H 00025 #define CGAL_FPU_H 00026 00027 #include <CGAL/number_type_basic.h> 00028 00029 #ifndef __INTEL_COMPILER 00030 #include <cmath> // for HUGE_VAL 00031 #endif 00032 00033 // This file specifies some platform dependant functions, regarding the FPU 00034 // directed rounding modes. There is only support for double precision. 00035 // 00036 // It also contains the definition of the Protect_FPU_rounding<> class, 00037 // which helps to protect blocks of code needing a particular rounding mode. 00038 00039 #if defined __alpha__ && defined __linux__ 00040 extern "C" { 00041 # include <fenv.h> 00042 } 00043 #elif defined __powerpc__ 00044 # include <fpu_control.h> 00045 #elif defined __SUNPRO_CC && defined __sun 00046 # include <ieeefp.h> 00047 #elif defined __osf || defined __osf__ 00048 # ifdef __GNUG__ 00049 // GCC seems to remove (fixincludes) read_rnd/write_rnd... 00050 # include "/usr/include/float.h" 00051 # else 00052 # include <cfloat> 00053 # endif 00054 #elif defined _MSC_VER || defined __sparc__ || \ 00055 (defined __i386__ && !defined __PGI && !defined __SUNPRO_CC) 00056 // Nothing to include. 00057 #else 00058 // By default we use the ISO C99 version. 00059 # include <fenv.h> 00060 #endif 00061 00062 00063 // Some useful constants 00064 00065 #if defined CGAL_CFG_NO_LIMITS 00066 # if defined CGAL_CFG_DENORMALS_COMPILE_BUG 00067 // For compilers crashing when dealing with denormalized values. 00068 // So we have to generate it at run time instead. 00069 # define CGAL_IA_MIN_DOUBLE (CGAL::CGALi::minimin) 00070 # else 00071 # define CGAL_IA_MIN_DOUBLE (5e-324) 00072 # endif 00073 # define CGAL_IA_MAX_DOUBLE (1.7976931348623157081e+308) 00074 #else 00075 # include <limits> 00076 # define CGAL_IA_MIN_DOUBLE std::numeric_limits<double>::denorm_min() 00077 # define CGAL_IA_MAX_DOUBLE (std::numeric_limits<double>::max)() 00078 #endif 00079 00080 00081 // Pure and safe SSE2 mode (g++ -mfpmath=sse && (-msse2 || -march=pentium4)) 00082 // can be detected by : 00083 // TODO : see what Intel and VC++ have to say about this. 00084 #if defined __FLT_EVAL_METHOD__ && defined __SSE2_MATH__ && \ 00085 (__FLT_EVAL_METHOD__ == 0 || __FLT_EVAL_METHOD__ == 1) 00086 # define CGAL_SAFE_SSE2 00087 # include <xmmintrin.h> 00088 #endif 00089 00090 // We do not handle -mfpmath=387,sse yet. 00091 #if defined __SSE2_MATH__ && \ 00092 ! (__FLT_EVAL_METHOD__ == 0 || __FLT_EVAL_METHOD__ == 1) 00093 # warning Unsafe SSE2 mode : not supported yet. 00094 #endif 00095 00096 // The CGAL_FPU_HAS_EXCESS_PRECISION macro is defined if some computations with 00097 // double can use more than the 53bits of precision of IEEE754, and/or if the 00098 // exponent has a wider range. This can produce double rounding effects and 00099 // other bad things that we need to protect against. 00100 // The typical offender is the traditional FPU of x86 (SSE2-only mode is not affected). 00101 // Are there others? 00102 #if (defined __i386__ && !defined CGAL_SAFE_SSE2) || defined _MSC_VER 00103 # define CGAL_FPU_HAS_EXCESS_PRECISION 00104 #endif 00105 00106 CGAL_BEGIN_NAMESPACE 00107 00108 namespace CGALi { 00109 00110 #ifdef CGAL_CFG_DENORMALS_COMPILE_BUG 00111 extern double minimin; 00112 #endif 00113 00114 #ifdef __INTEL_COMPILER 00115 const double infinity = std::numeric_limits<double>::infinity(); 00116 #else 00117 const double infinity = HUGE_VAL; 00118 #endif 00119 00120 } // namespace CGALi 00121 00122 00123 // Inline function to stop compiler optimization. 00124 inline double IA_force_to_double(double x) 00125 { 00126 #if defined __GNUG__ && !defined __INTEL_COMPILER 00127 // Intel does not emulate GCC perfectly... 00128 asm("" : "=m"(x) : "m"(x)); 00129 // asm("" : "+m"(x) ); 00130 return x; 00131 #else 00132 volatile double e = x; 00133 return e; 00134 #endif 00135 } 00136 00137 // Interval arithmetic needs to protect against double-rounding effects 00138 // caused by excess FPU precision, even if it forces the 53bit mantissa 00139 // precision, because there is no way to fix the problem for the exponent 00140 // which has the same problem. This affects underflow and overflow cases. 00141 // In case one does not care about such "extreme" situations, one can 00142 // set CGAL_IA_NO_X86_OVER_UNDER_FLOW_PROTECT. 00143 #if defined CGAL_FPU_HAS_EXCESS_PRECISION && \ 00144 !defined CGAL_IA_NO_X86_OVER_UNDER_FLOW_PROTECT 00145 # define CGAL_IA_FORCE_TO_DOUBLE(x) CGAL::IA_force_to_double(x) 00146 #else 00147 # define CGAL_IA_FORCE_TO_DOUBLE(x) (x) 00148 #endif 00149 00150 // We sometimes need to stop constant propagation, 00151 // because operations are done with a wrong rounding mode at compile time. 00152 #ifndef CGAL_IA_DONT_STOP_CONSTANT_PROPAGATION 00153 # define CGAL_IA_STOP_CPROP(x) CGAL::IA_force_to_double(x) 00154 #else 00155 # define CGAL_IA_STOP_CPROP(x) (x) 00156 #endif 00157 00158 // std::sqrt(double) on VC++ and CygWin is buggy when not optimizing. 00159 #if defined ( _MSC_VER ) && ! defined ( _WIN64 ) 00160 inline double IA_bug_sqrt(double d) 00161 { 00162 _asm 00163 { 00164 fld d 00165 fsqrt 00166 fstp d 00167 } 00168 return d; 00169 } 00170 00171 # define CGAL_BUG_SQRT(d) IA_bug_sqrt(d) 00172 00173 00174 #elif defined __SSE2_MATH__ 00175 // For SSE2, we need to call __builtin_sqrt() instead of libc's sqrt(). 00176 # define CGAL_BUG_SQRT(d) __builtin_sqrt(d) 00177 #elif defined __CYGWIN__ 00178 inline double IA_bug_sqrt(double d) 00179 { 00180 double r; 00181 asm volatile ("fsqrt" : "=t"(r) : "0"(d)); 00182 return r; 00183 } 00184 # define CGAL_BUG_SQRT(d) IA_bug_sqrt(d) 00185 #else 00186 # define CGAL_BUG_SQRT(d) std::sqrt(d) 00187 #endif 00188 00189 // Here are the operator macros that make use of the above. 00190 // With GCC, we can do slightly better : test with __builtin_constant_p() 00191 // that both arguments are constant before stopping one of them. 00192 // Use inline functions instead ? 00193 #define CGAL_IA_ADD(a,b) CGAL_IA_FORCE_TO_DOUBLE((a)+CGAL_IA_STOP_CPROP(b)) 00194 #define CGAL_IA_SUB(a,b) CGAL_IA_FORCE_TO_DOUBLE((a)-CGAL_IA_STOP_CPROP(b)) 00195 #define CGAL_IA_MUL(a,b) CGAL_IA_FORCE_TO_DOUBLE((a)*CGAL_IA_STOP_CPROP(b)) 00196 #define CGAL_IA_DIV(a,b) CGAL_IA_FORCE_TO_DOUBLE((a)/CGAL_IA_STOP_CPROP(b)) 00197 #define CGAL_IA_SQUARE(a) CGAL_IA_MUL(a,a) 00198 #define CGAL_IA_SQRT(a) \ 00199 CGAL_IA_FORCE_TO_DOUBLE(CGAL_BUG_SQRT(CGAL_IA_STOP_CPROP(a))) 00200 00201 00202 #if defined __i386__ && !defined __PGI && !defined __SUNPRO_CC 00203 00204 # if defined CGAL_SAFE_SSE2 00205 00206 #define CGAL_IA_SETFPCW(CW) _MM_SET_ROUNDING_MODE(CW) 00207 #define CGAL_IA_GETFPCW(CW) CW = _MM_GET_ROUNDING_MODE() 00208 typedef unsigned int FPU_CW_t; 00209 #define CGAL_FE_TONEAREST _MM_ROUND_NEAREST 00210 #define CGAL_FE_TOWARDZERO _MM_ROUND_TOWARD_ZERO 00211 #define CGAL_FE_UPWARD _MM_ROUND_UP 00212 #define CGAL_FE_DOWNWARD _MM_ROUND_DOWN 00213 00214 # else 00215 // The GNU libc version (cf powerpc) is nicer, but doesn't work on libc 5 :( 00216 // This one also works with CygWin. 00217 // Note that the ISO C99 version may not be enough because of the extended 00218 // mantissa issue on x86 (may be required by some kinds of computation, but 00219 // as far as CGAL::Interval_nt<> is concerned, the double-rounding issues 00220 // are taking care of there). 00221 #define CGAL_IA_SETFPCW(CW) asm volatile ("fldcw %0" : :"m" (CW)) 00222 #define CGAL_IA_GETFPCW(CW) asm volatile ("fnstcw %0" : "=m" (CW)) 00223 typedef unsigned short FPU_CW_t; 00224 #define CGAL_FE_TONEAREST (0x000 | 0x127f) 00225 #define CGAL_FE_TOWARDZERO (0xc00 | 0x127f) 00226 #define CGAL_FE_UPWARD (0x800 | 0x127f) 00227 #define CGAL_FE_DOWNWARD (0x400 | 0x127f) 00228 00229 # endif 00230 00231 #elif defined __powerpc__ 00232 #define CGAL_IA_SETFPCW(CW) _FPU_SETCW(CW) 00233 #define CGAL_IA_GETFPCW(CW) _FPU_GETCW(CW) 00234 typedef fpu_control_t FPU_CW_t; 00235 #define CGAL_FE_TONEAREST (_FPU_RC_NEAREST | _FPU_DEFAULT) 00236 #define CGAL_FE_TOWARDZERO (_FPU_RC_ZERO | _FPU_DEFAULT) 00237 #define CGAL_FE_UPWARD (_FPU_RC_UP | _FPU_DEFAULT) 00238 #define CGAL_FE_DOWNWARD (_FPU_RC_DOWN | _FPU_DEFAULT) 00239 00240 #elif defined __SUNPRO_CC && defined __sun 00241 #define CGAL_IA_SETFPCW(CW) fpsetround(fp_rnd(CW)) 00242 #define CGAL_IA_GETFPCW(CW) CW = fpgetround() 00243 typedef unsigned int FPU_CW_t; 00244 #define CGAL_FE_TONEAREST FP_RN 00245 #define CGAL_FE_TOWARDZERO FP_RZ 00246 #define CGAL_FE_UPWARD FP_RP 00247 #define CGAL_FE_DOWNWARD FP_RM 00248 00249 #elif defined __sparc__ 00250 #define CGAL_IA_SETFPCW(CW) asm volatile ("ld %0,%%fsr" : :"m" (CW)) 00251 #define CGAL_IA_GETFPCW(CW) asm volatile ("st %%fsr,%0" : "=m" (CW)) 00252 typedef unsigned int FPU_CW_t; 00253 #define CGAL_FE_TONEAREST (0x0 | 0x20000000 | 0x1f) 00254 #define CGAL_FE_TOWARDZERO (0x40000000 | 0x20000000 | 0x1f) 00255 #define CGAL_FE_UPWARD (0x80000000 | 0x20000000 | 0x1f) 00256 #define CGAL_FE_DOWNWARD (0xc0000000 | 0x20000000 | 0x1f) 00257 00258 #elif defined __mips__ 00259 #define CGAL_IA_SETFPCW(CW) asm volatile ("ctc1 %0,$31" : :"r" (CW)) 00260 #define CGAL_IA_GETFPCW(CW) asm volatile ("cfc1 %0,$31" : "=r" (CW)) 00261 typedef unsigned int FPU_CW_t; 00262 #define CGAL_FE_TONEAREST (0x0) 00263 #define CGAL_FE_TOWARDZERO (0x1) 00264 #define CGAL_FE_UPWARD (0x2) 00265 #define CGAL_FE_DOWNWARD (0x3) 00266 00267 #elif defined __osf || defined __osf__ // Not yet supported. 00268 #define CGAL_IA_SETFPCW(CW) write_rnd(CW) 00269 #define CGAL_IA_GETFPCW(CW) CW = read_rnd() 00270 typedef unsigned int FPU_CW_t; 00271 #define CGAL_FE_TONEAREST FP_RND_RN 00272 #define CGAL_FE_TOWARDZERO FP_RND_RZ 00273 #define CGAL_FE_UPWARD FP_RND_RP 00274 #define CGAL_FE_DOWNWARD FP_RND_RM 00275 00276 #elif defined ( _MSC_VER ) 00277 #if ( _MSC_VER < 1400) 00278 #define CGAL_IA_SETFPCW(CW) _controlfp (CW, _MCW_RC ) 00279 #define CGAL_IA_GETFPCW(CW) CW = _controlfp (0, 0 ) & _MCW_RC 00280 typedef unsigned short FPU_CW_t; 00281 #else 00282 #define CGAL_IA_SETFPCW(CW) unsigned int dummy; _controlfp_s (&dummy, CW, _MCW_RC ) 00283 #define CGAL_IA_GETFPCW(CW)_controlfp_s (&CW, 0, 0 ); CW &= _MCW_RC 00284 typedef unsigned int FPU_CW_t; 00285 #endif 00286 00287 #define CGAL_FE_TONEAREST _RC_NEAR 00288 #define CGAL_FE_TOWARDZERO _RC_CHOP 00289 #define CGAL_FE_UPWARD _RC_UP 00290 #define CGAL_FE_DOWNWARD _RC_DOWN 00291 00292 #else 00293 // This is a version following the ISO C99 standard, which aims at portability. 00294 // The drawbacks are speed on one hand, and also, on x86, it doesn't fix the 00295 // extended mantissa issue (this is not a problem for IA, but it is one for 00296 // some future modular computations). 00297 #define CGAL_IA_SETFPCW(CW) fesetround(CW) 00298 #define CGAL_IA_GETFPCW(CW) CW = fegetround() 00299 typedef int FPU_CW_t; 00300 #define CGAL_FE_TONEAREST FE_TONEAREST 00301 #define CGAL_FE_TOWARDZERO FE_TOWARDZERO 00302 #define CGAL_FE_UPWARD FE_UPWARD 00303 #define CGAL_FE_DOWNWARD FE_DOWNWARD 00304 #endif 00305 00306 // User interface: 00307 00308 inline 00309 FPU_CW_t 00310 FPU_get_cw (void) 00311 { 00312 FPU_CW_t cw; 00313 CGAL_IA_GETFPCW(cw); 00314 return cw; 00315 } 00316 00317 inline 00318 void 00319 FPU_set_cw (FPU_CW_t cw) 00320 { 00321 CGAL_IA_SETFPCW(cw); 00322 } 00323 00324 inline 00325 FPU_CW_t 00326 FPU_get_and_set_cw (FPU_CW_t cw) 00327 { 00328 FPU_CW_t old = FPU_get_cw(); 00329 FPU_set_cw(cw); 00330 return old; 00331 } 00332 00333 00334 // A class whose constructor sets the FPU mode to +inf, saves a backup of it, 00335 // and whose destructor resets it back to the saved state. 00336 00337 template <bool Protected = true> struct Protect_FPU_rounding; 00338 00339 template <> 00340 struct Protect_FPU_rounding<true> 00341 { 00342 Protect_FPU_rounding(FPU_CW_t r = CGAL_FE_UPWARD) 00343 : backup( FPU_get_and_set_cw(r) ) {} 00344 00345 ~Protect_FPU_rounding() 00346 { 00347 FPU_set_cw(backup); 00348 } 00349 00350 private: 00351 FPU_CW_t backup; 00352 }; 00353 00354 template <> 00355 struct Protect_FPU_rounding<false> 00356 { 00357 Protect_FPU_rounding() {} 00358 Protect_FPU_rounding(FPU_CW_t /*= CGAL_FE_UPWARD*/) {} 00359 }; 00360 00361 00362 // A wrapper on top of the Protect_FPU_rounding to add "expensive" checks 00363 // of the rounding mode. It is used internally, to benefit from the 00364 // protector declarations to add checks in non-protected mode. 00365 00366 template <bool Protected = true> 00367 struct Checked_protect_FPU_rounding 00368 : Protect_FPU_rounding<Protected> 00369 { 00370 Checked_protect_FPU_rounding() 00371 { 00372 CGAL_expensive_assertion(FPU_get_cw() == CGAL_FE_UPWARD); 00373 } 00374 00375 Checked_protect_FPU_rounding(FPU_CW_t r) 00376 : Protect_FPU_rounding<Protected>(r) 00377 { 00378 CGAL_expensive_assertion(FPU_get_cw() == CGAL_FE_UPWARD); 00379 } 00380 }; 00381 00382 00383 // The class Set_ieee_double_precision forces the double precision (53bit mantissa), 00384 // to protect from double rounding effects on x86 FPU. 00385 // ( Note that it also sets the rounding mode to nearest. ) 00386 // Its destructor restores the FPU state as it was previously. 00387 // Note that this affects "long double" as well, and other potential side effects. 00388 // And note that it does not (cannot) "fix" the same problem for the exponent. 00389 00390 struct Set_ieee_double_precision 00391 #ifdef CGAL_FPU_HAS_EXCESS_PRECISION 00392 : public Protect_FPU_rounding<> 00393 { 00394 Set_ieee_double_precision() 00395 : Protect_FPU_rounding<>(CGAL_FE_TONEAREST) {} 00396 }; 00397 #else 00398 { 00399 Set_ieee_double_precision() {} // only to kill compiler warnings. 00400 }; 00401 #endif 00402 00403 00404 // The following function serves the same goal as Set_ieee_double_precision but 00405 // does the change globally (no destructor resets the previous behavior). 00406 inline void force_ieee_double_precision() 00407 { 00408 #ifdef CGAL_FPU_HAS_EXCESS_PRECISION 00409 FPU_set_cw(CGAL_FE_TONEAREST); 00410 #endif 00411 } 00412 00413 CGAL_END_NAMESPACE 00414 00415 #endif // CGAL_FPU_H