mirror of https://github.com/CGAL/cgal
235 lines
6.7 KiB
C
235 lines
6.7 KiB
C
// ============================================================================
|
|
//
|
|
// Copyright (c) 1998,1999 The CGAL Consortium
|
|
//
|
|
// This software and related documentation is part of an INTERNAL release
|
|
// of the Computational Geometry Algorithms Library (CGAL). It is not
|
|
// intended for general use.
|
|
//
|
|
// ----------------------------------------------------------------------------
|
|
//
|
|
// release :
|
|
// release_date :
|
|
//
|
|
// file : include/CGAL/Interval_arithmetic/_FPU.h
|
|
// revision : $Revision$
|
|
// revision_date : $Date$
|
|
// package : Interval Arithmetic
|
|
// author(s) : Sylvain Pion <Sylvain.Pion@sophia.inria.fr>
|
|
//
|
|
// coordinator : INRIA Sophia-Antipolis <Mariette.Yvinec@sophia.inria.fr>
|
|
//
|
|
// ============================================================================
|
|
|
|
#ifndef CGAL_FPU_H
|
|
#define CGAL_FPU_H
|
|
|
|
// This file specifies some platform dependant functions, regarding the FPU
|
|
// directed rounding modes. There is only support for double precision.
|
|
|
|
// Some useful constants
|
|
|
|
#define CGAL_IA_MIN_DOUBLE (5e-324) // subnormal
|
|
#define CGAL_IA_MAX_DOUBLE (1.7976931348623157081e+308)
|
|
|
|
// Macro to stop compiler optimization.
|
|
#if defined(__GNUG__)
|
|
#define CGAL_IA_STOP_COMPILER_OPT(x) ({ volatile double y=(x);double z=y;z; })
|
|
#elif defined(_MSC_VER)
|
|
inline double cgal_ia_force_to_double(const double x)
|
|
{ volatile double e = x; return e; }
|
|
#define CGAL_IA_STOP_COMPILER_OPT(x) cgal_ia_force_to_double(x)
|
|
#endif
|
|
|
|
// The x87 keeps too wide exponents (15bits) in registers, even in double
|
|
// precision mode. This causes problems when the intervals overflow or
|
|
// underflow. To work around that, at every critical moment, we flush the
|
|
// register to memory, using the macro below.
|
|
// The other possible workaround is to use intervals of "long doubles"
|
|
// directly, but I think it would be much slower.
|
|
#if defined(__i386__) || defined(_MSC_VER)
|
|
#define CGAL_IA_FORCE_TO_DOUBLE(x) CGAL_IA_STOP_COMPILER_OPT(x)
|
|
#else
|
|
#define CGAL_IA_FORCE_TO_DOUBLE(x) (x)
|
|
#endif // __i386__
|
|
|
|
// We sometimes need to do the same thing to stop constant propagation.
|
|
#ifdef CGAL_IA_STOP_CONSTANT_PROPAGATION
|
|
#define CGAL_IA_STOP_CPROP(x) CGAL_IA_STOP_COMPILER_OPT(x)
|
|
#else
|
|
#define CGAL_IA_STOP_CPROP(x) (x)
|
|
#endif
|
|
|
|
#ifdef __linux__
|
|
#include <fpu_control.h>
|
|
#elif defined __SUNPRO_CC
|
|
#include <ieeefp.h>
|
|
#elif defined __osf || defined __osf__ || defined __BORLANDC__
|
|
#include <float.h>
|
|
#elif defined __sgi
|
|
// The 3 C functions do not work on IRIX 6.5 !!!!!
|
|
// So we use precompiled (by gcc) binaries linked into libCGAL.
|
|
// See revision 2.23 for the old code.
|
|
extern "C" {
|
|
void CGAL_workaround_IRIX_set_FPU_cw (int);
|
|
int CGAL_workaround_IRIX_get_FPU_cw (void);
|
|
}
|
|
#endif
|
|
|
|
CGAL_BEGIN_NAMESPACE
|
|
|
|
#ifdef __i386__
|
|
// The GNU libc version (cf powerpc) is nicer, but doesn't work on libc 5 :(
|
|
// This one also works with CygWin.
|
|
#define CGAL_IA_SETFPCW(CW) asm volatile ("fldcw %0" : :"m" (CW))
|
|
#define CGAL_IA_GETFPCW(CW) asm volatile ("fnstcw %0" : "=m" (CW))
|
|
typedef unsigned short FPU_CW_t;
|
|
enum {
|
|
FPU_cw_near = 0x000 | 0x127f,
|
|
FPU_cw_zero = 0xc00 | 0x127f,
|
|
FPU_cw_up = 0x800 | 0x127f,
|
|
FPU_cw_down = 0x400 | 0x127f
|
|
};
|
|
|
|
#elif defined __powerpc__
|
|
#define CGAL_IA_SETFPCW(CW) _FPU_SETCW(CW)
|
|
#define CGAL_IA_GETFPCW(CW) _FPU_GETCW(CW)
|
|
typedef fpu_control_t FPU_CW_t;
|
|
enum {
|
|
FPU_cw_near = _FPU_RC_NEAREST | _FPU_DEFAULT,
|
|
FPU_cw_zero = _FPU_RC_ZERO | _FPU_DEFAULT,
|
|
FPU_cw_up = _FPU_RC_UP | _FPU_DEFAULT,
|
|
FPU_cw_down = _FPU_RC_DOWN | _FPU_DEFAULT
|
|
};
|
|
|
|
#elif defined __SUNPRO_CC
|
|
#define CGAL_IA_GETFPCW(CW) CW = fpgetround()
|
|
#define CGAL_IA_SETFPCW(CW) fpsetround(fp_rnd(CW))
|
|
typedef unsigned int FPU_CW_t;
|
|
enum {
|
|
FPU_cw_near = FP_RN,
|
|
FPU_cw_zero = FP_RZ,
|
|
FPU_cw_up = FP_RP,
|
|
FPU_cw_down = FP_RM
|
|
};
|
|
|
|
#elif defined __sparc__
|
|
#define CGAL_IA_SETFPCW(CW) asm volatile ("ld %0,%%fsr" : :"m" (CW))
|
|
#define CGAL_IA_GETFPCW(CW) asm volatile ("st %%fsr,%0" : "=m" (CW))
|
|
typedef unsigned int FPU_CW_t;
|
|
enum { // rounding | precision | def.mask
|
|
FPU_cw_near = 0x0 | 0x20000000 | 0x1f,
|
|
FPU_cw_zero = 0x40000000 | 0x20000000 | 0x1f,
|
|
FPU_cw_up = 0x80000000 | 0x20000000 | 0x1f,
|
|
FPU_cw_down = 0xc0000000 | 0x20000000 | 0x1f
|
|
};
|
|
|
|
#elif defined __sgi
|
|
#define CGAL_IA_GETFPCW(CW) CW = CGAL_workaround_IRIX_get_FPU_cw()
|
|
#define CGAL_IA_SETFPCW(CW) CGAL_workaround_IRIX_set_FPU_cw(CW)
|
|
typedef unsigned int FPU_CW_t;
|
|
enum {
|
|
FPU_cw_near = 0x0,
|
|
FPU_cw_zero = 0x1,
|
|
FPU_cw_up = 0x2,
|
|
FPU_cw_down = 0x3
|
|
};
|
|
|
|
#elif defined __mips__ // && !defined __sgi
|
|
#define CGAL_IA_SETFPCW(CW) asm volatile ("ctc1 %0,$31" : :"r" (CW))
|
|
#define CGAL_IA_GETFPCW(CW) asm volatile ("cfc1 %0,$31" : "=r" (CW))
|
|
typedef unsigned int FPU_CW_t;
|
|
enum {
|
|
FPU_cw_near = 0x0,
|
|
FPU_cw_zero = 0x1,
|
|
FPU_cw_up = 0x2,
|
|
FPU_cw_down = 0x3
|
|
};
|
|
|
|
#elif defined __osf || defined __osf__ // Not yet supported.
|
|
#define CGAL_IA_GETFPCW(CW) CW = read_rnd()
|
|
#define CGAL_IA_SETFPCW(CW) write_rnd(CW)
|
|
typedef unsigned int FPU_CW_t;
|
|
enum {
|
|
FPU_cw_near = FP_RND_RN,
|
|
FPU_cw_zero = FP_RND_RZ,
|
|
FPU_cw_up = FP_RND_RP,
|
|
FPU_cw_down = FP_RND_RM
|
|
};
|
|
|
|
#elif defined __alpha__ // This one is not really supported [yet].
|
|
#define CGAL_IA_SETFPCW(CW) asm volatile ("mt_fpcr %0; excb" : :"f" (CW))
|
|
#define CGAL_IA_GETFPCW(CW) asm volatile ("excb; mf_fpcr %0" : "=f" (CW))
|
|
typedef unsigned long FPU_CW_t;
|
|
enum { // rounding
|
|
// I guess it won't work, because enum == int.
|
|
FPU_cw_near = 0x0800000000000000UL,
|
|
FPU_cw_zero = 0x0000000000000000UL,
|
|
FPU_cw_up = 0x0c00000000000000UL,
|
|
FPU_cw_down = 0x0400000000000000UL
|
|
};
|
|
|
|
#elif defined _MSC_VER
|
|
// Found in BIAS:
|
|
// #define CGAL_IA_SETFPCW(CW) _asm {fldcw word ptr ds:OFFSET CW}
|
|
// #define CGAL_IA_GETFPCW(CW) _asm {fstcw word ptr ds:OFFSET CW}
|
|
//
|
|
// Found in http://msdn.microsoft.com/library/sdkdoc/directx/imover_7410.htm :
|
|
#define CGAL_IA_SETFPCW(CW) __asm fldcw CW
|
|
#define CGAL_IA_GETFPCW(CW) __asm fstcw CW
|
|
typedef unsigned short FPU_CW_t;
|
|
enum {
|
|
FPU_cw_near = 0x0 | 0x127f,
|
|
FPU_cw_zero = 0xC00 | 0x127f,
|
|
FPU_cw_up = 0x800 | 0x127f,
|
|
FPU_cw_down = 0x400 | 0x127f
|
|
};
|
|
|
|
#elif defined __BORLANDC__
|
|
#define CGAL_IA_SETFPCW(CW) _control87(CW,~0)
|
|
#define CGAL_IA_GETFPCW(CW) CW = _control87(0,0)
|
|
typedef unsigned short FPU_CW_t;
|
|
enum {
|
|
FPU_cw_near = 0x0 | 0x127f,
|
|
FPU_cw_zero = 0xC00 | 0x127f,
|
|
FPU_cw_up = 0x800 | 0x127f,
|
|
FPU_cw_down = 0x400 | 0x127f
|
|
};
|
|
|
|
#else
|
|
#error Architecture not supported
|
|
#endif
|
|
|
|
// User interface:
|
|
|
|
inline
|
|
FPU_CW_t
|
|
FPU_get_cw (void)
|
|
{
|
|
FPU_CW_t cw;
|
|
CGAL_IA_GETFPCW(cw);
|
|
return cw;
|
|
}
|
|
|
|
inline
|
|
void
|
|
FPU_set_cw (FPU_CW_t cw)
|
|
{
|
|
CGAL_IA_SETFPCW(cw);
|
|
}
|
|
|
|
inline
|
|
FPU_CW_t
|
|
FPU_get_and_set_cw (FPU_CW_t cw)
|
|
{
|
|
FPU_CW_t old = FPU_get_cw();
|
|
FPU_set_cw(cw);
|
|
return old;
|
|
}
|
|
|
|
FPU_CW_t FPU_empiric_test(); // Only used for debug.
|
|
|
|
CGAL_END_NAMESPACE
|
|
|
|
#endif // CGAL_FPU_H
|