Search code examples
c++gmp

How to serialize a GMP rational number?


Is there a way to serialize a GMP rational number in binary form? I only see functions for reading/writing to a FILE, but even there it is a text form. I could convert to numerator/denominator and use the integer functions, but again there only a FILE output is available. I need to be able to get the raw bytes or write to a C++ stream.


Solution

  • Using the mpz_export and mpz_import function (thanks to Marc for pointing that out), I came up with the below code. This is part of a number class that contains a mpz_class value.

    This really shows that GMP doesn't have a proper import/export functionality. The below is more of a workaround than use of a feature.

    void number::write( std::ostream & out ) const {
        int8_t neg = value.get_num() < 0;
        out.write( (char*)&neg, sizeof(neg) );
    
        size_t c;
        void * raw = mpz_export( nullptr, &c, 1, 1, 0, 0, value.get_num().get_mpz_t() );
        out.write( (char*)&c, sizeof(c) );
        out.write( (char*)raw, c );
        free(raw);
    
        raw = mpz_export( nullptr, &c, 1, 1, 0, 0, value.get_den().get_mpz_t() );
        out.write( (char*)&c, sizeof(c) );
        out.write( (char*)raw, c );
        free(raw);
    }
    
    void number::read( std::istream & in ) {
        mpz_class num, den;
        size_t s;
        std::vector<uint8_t> v;
    
        int8_t neg;
        in.read( (char*)&neg, sizeof(neg) );
    
        in.read( (char*)&s, sizeof(s) );
        v.resize(s);
        in.read( (char*)&v[0], s );
        mpz_import( num.get_mpz_t(), s, 1, 1, 0, 0, &v[0] );
    
        in.read( (char*)&s, sizeof(s) );
        v.resize(s);
        in.read( (char*)&v[0], s );
        mpz_import( den.get_mpz_t(), s, 1, 1, 0, 0, &v[0] );
    
        value = mpq_class(num) / mpq_class(den);
        if( neg ) {
            value = -value;
        }
    }