IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    GMP Notes

    连城 (Lian, Cheng)发表于 2012-07-26 00:00:00
    love 0
    GNU Logo

    GMP (the GNU MP library) is a widely known library for arbitrary precision arithmetic on integers, rational numbers and floating-point numbers. When using GMP in C/C++ projects, one must face some subtleties.

    Using GMP in C

    According to GMP's official documentation:

    All declarations needed to use GMP are collected in the include file gmp.h. It is designed to work with both C and C++ compilers.

    #include 
    

    Note however that prototypes for GMP functions with FILE * parameters are only provided if is included too.

    #include 
    #include 
    

    Likewise (or ) is required for prototypes with va_list parameters, such as gmp_vprintf. And for prototypes with struct obstack parameters, such as gmp_obstack_printf, when available.

    (I wonder why GMP doesn't include these required header files itself?)


    Using GMP C API in C++

    When using GMP in C++, there are two API for choice: the original C API and the C++ wrapper API.

    For C++ projects, the C++ wrapper API is very handy, but sometimes we still need the C API. For example: our main project may be written in C, but we found out that the GTest C++ library is very handy to write unit test cases. Then we need to use GMP C API in our GTest test cases.

    In order to do so, first we must obey all the conventions above. Further more, must be included, i.e.:

    #include 
    
    extern "C" {
    
    #include 
    #include 
    
    }
    

    Note: only include doesn't work.

    Using GMP C++ wrapper API in C++

    When using the C++ wrapper API, although classes like mpz_class already overloaded various operators, there're still some subtleties to overcome when we need to treat mpz_class as builtin integer types. For example, using mpz_class with Boost.Rational:

    #include 
    #include rational.hpp>
    <span>
    int main (int argc, char* argv [])
    {
        typedef boost::rational<mpz_class> rational;
        rational r (mpz_class (0), mpz_class (1));
        return 0;
    }
    

    Compile this program with clang++ (g++ error reporting sucks) and you'll see:

    /usr/include/boost/rational.hpp|127 col 5| error: implicit instantiation of
    undefined template 'boost::STATIC_AS SERTION_FAILURE'
         BOOST_STATIC_ASSERT( ::std::numeric_limits::is_specialized);
         ^
    

    clearly, we need to specialize the std::numeric_limits template for mpz_class:

    #include 
    
    namespace std {
    
    template
    struct numeric_limits<mpz_class> {
    public:
        static const bool is_specialized = true;
    
        static mpz_class min() throw() {
            return mpz_class(0u);
        }
    
        static mpz_class max() throw() {
            return mpz_class(0u);
        }
    
        static const int  digits     = 0;
        static const int  digits10   = 0;
        static const bool is_signed  = true;
        static const bool is_integer = true;
        static const bool is_exact   = true;
        static const int  radix      = 2;
    
        static mpz_class epsilon() throw() {
            return mpz_class(0u);
        }
    
        static mpz_class round_error() throw() {
            return mpz_class(0u);
        }
    
        static const int  min_exponent   = 0;
        static const int  min_exponent10 = 0;
        static const int  max_exponent   = 0;
        static const int  max_exponent10 = 0;
    
        static const bool has_infinity      = false;
        static const bool has_quiet_NaN     = false;
        static const bool has_signaling_NaN = false;
    
        static const float_denorm_style has_denorm      = denorm_absent;
        static const bool               has_denorm_loss = false;
    
        static mpz_class infinity() throw() {
            return mpz_class(0U);
        }
    
        static mpz_class quiet_NaN() throw() {
            return mpz_class(0u);
        }
    
        static mpz_class signaling_NaN() throw() {
            return mpz_class(0u);
        }
    
        static mpz_class denorm_min() throw() {
            return mpz_class(0u);
        }
    
        static const bool is_iec559  = false;
        static const bool is_bounded = false;
        static const bool is_modulo  = false;
    
        static const bool traps                         = false;
        static const bool tinyness_before               = false;
        static const      float_round_style round_style = round_toward_zero;
    
    };  //  class numeric_limits
    
    }   //  namespace std
    

    With this template specialization, the code above can be compiled successfully (don't forget to link libgmp and libgmpxx).

    The second gotcha is that, GMP C++ classes are designed to support templated expressions. Suppose m and n are two mpz_class instances, then m + n will end up to be a certain expression template type internal to . For more information about GMP C++ API limitations, please refer to the official GMP manual.



沪ICP备19023445号-2号
友情链接