00001 /******************************************************************** 00002 * This file is part of the source code of the SYNAPS library. 00003 * Author(s): J.P. Pavone, GALAAD, INRIA 00004 * $Id: fpu.h,v 1.1 2005/07/11 09:15:23 mourrain Exp $ 00005 ********************************************************************/ 00006 #ifndef SYNAPS_NUMERICS_FPU_HPP 00007 #define SYNAPS_NUMERICS_FPU_HPP 00008 //-------------------------------------------------------------------- 00009 #include <fenv.h> 00010 #include <synaps/init.h> 00011 //-------------------------------------------------------------------- 00012 __BEGIN_NAMESPACE_SYNAPS 00013 //-------------------------------------------------------------------- 00014 namespace numerics 00015 { 00016 inline int get_cw() { return fegetround(); }; 00017 inline int get_rnd() { return fegetround(); }; 00018 inline void set_cw( int cw ) { fesetround(cw);}; 00019 inline static int rnd_up() { return FE_UPWARD;}; 00020 inline static int rnd_dw() { return FE_DOWNWARD;}; 00021 inline static int rnd_nr() { return FE_TONEAREST;}; 00022 inline static int rnd_z() { return FE_TOWARDZERO;}; 00023 template< typename T > struct LongVersion { typedef T result_t; }; 00024 template<> struct LongVersion<float> { typedef long double result_t; }; 00025 template<> struct LongVersion<double> { typedef long double result_t; }; 00026 template< typename T > struct fpu_rounding { 00027 static const int id = 0; 00028 typedef int rnd_t; 00029 inline static rnd_t getrnd() { return 0; }; 00030 inline static void setrnd( rnd_t r ) { }; 00031 inline static int rnd_up() { return 0; }; 00032 inline static int rnd_dw() { return 0; }; 00033 inline static int rnd_nr() { return 0; }; 00034 inline static int rnd_z() { return 0; }; 00035 fpu_rounding( int ){}; 00036 }; 00037 template<> struct fpu_rounding<long double> 00038 { 00039 typedef int rnd_t; 00040 inline static rnd_t getrnd() { return fegetround(); }; 00041 inline static void setrnd( rnd_t r ) { fesetround(r); }; 00042 inline static int rnd_up() { return FE_UPWARD;}; 00043 inline static int rnd_dw() { return FE_DOWNWARD;}; 00044 inline static int rnd_nr() { return FE_TONEAREST;}; 00045 inline static int rnd_z() { return FE_TOWARDZERO;}; 00046 static const int id = 1; 00047 rnd_t m_prev; 00048 bool m_chg; 00049 fpu_rounding( rnd_t rnd ) 00050 { 00051 m_chg = false; 00052 rnd_t m_prev = getrnd(); 00053 if ( m_prev != rnd ) 00054 { 00055 m_chg = true; 00056 setrnd(rnd); 00057 }; 00058 }; 00059 ~fpu_rounding() { 00060 if ( m_chg ) setrnd(m_prev); 00061 }; 00062 }; 00063 00064 template< typename T > 00065 struct rounding : fpu_rounding< typename LongVersion< T >::result_t > 00066 { rounding( int rnd ) : fpu_rounding< typename LongVersion< T >::result_t >( rnd ) {}; }; 00067 00068 template< typename T > inline T div_dw(const T& a, const T& b) { rounding<T> r(rnd_dw()); return a/b; }; 00069 template< typename T > inline T div_up(const T& a, const T& b) { rounding<T> r(rnd_up()); return a/b; }; 00070 template< typename T > inline T add_dw(const T& a, const T& b) { rounding<T> r(rnd_dw()); return a+b; }; 00071 template< typename T > inline T add_up(const T& a, const T& b) { rounding<T> r(rnd_up()); return a+b; }; 00072 template< typename T > inline T mul_dw(const T& a, const T& b) { rounding<T> r(rnd_dw()); return a*b; }; 00073 template< typename T > inline T mul_up(const T& a, const T& b) { rounding<T> r(rnd_up()); return a*b; }; 00074 template< typename T > inline T sub_dw(const T& a, const T& b) { rounding<T> r(rnd_dw()); return a-b; }; 00075 template< typename T > inline T sub_up(const T& a, const T& b) { rounding<T> r(rnd_up()); return a-b; }; 00076 }; 00077 00078 //-------------------------------------------------------------------- 00079 __END_NAMESPACE_SYNAPS 00080 /********************************************************************/ 00081 #endif //