GMP Fixed Bit Size Integers

Hey!

I've recently familiarized myself with GNU MPFR and GNU MP (arbitrarily large number libraries). So far, I need a specific requirement that I can only seem to find in MPFR.

When I perform operations on MPFR, the size in bits is known in advance, and the number will not grow if the result is too large. However, in GMP, the result grows in bits if the result is larger than the target to assign it to.

MPFR-style what I need, I do not need compile-time (template-based) sized integers, neither do I need growing integers. So I need a method to keep the bit-size static during normal arithmetic operations with integers in GMP. Currently, I'm thinking of implementing the constant size by appending a

mpz_add
by
mpz_realloc2

But this seems like a sub-optimal solution, as realloccing may be expensive (heap alloc). I would like to know a better solution.


Edit for any travelling googlers:

I've implemented my own solution without using the low level functions (mpn, tried that, but it doesn't provide much safety).

What the code basically does is that it checks if there are any 1s behind the last significant bit that we have specified as the last bit. If this is true, the number is nullified. It will work for negative values as well.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include <iostream>
#include <limits>
#include <gmp/gmp.h>


struct vint
{
    static std::size_t max;
};


std::size_t vint::max = std::numeric_limits<std::size_t>::max();


int main ( )
{
    constexpr const int bits = 4;

    mpz_t a, b;
    mpz_init2 (a, bits);
    mpz_init2 (b, bits);

    mpz_set_str (a, "1", 10);
    mpz_set_str (b, "1", 10);

    char *p (nullptr);

    p = mpz_get_str (p, 10, a);
    std::cout << p << '\n';

    while ( true )
    {
        mpz_add ( a, a, b );
        p = mpz_get_str(p, 10, a);
        std::cout << p << '\n';
        if ( mpz_scan1 (a, bits) != vint::max )
        {
            mpz_neg ( a, a );
            if ( mpz_scan1 (a, bits - 1) != vint::max )
            {
                std::cout << "Length of the number compromised. Setting it to 0\n";
                mpz_set_ui (a, 0);
            }
            else
            {
                mpz_neg ( a, a );
            }
        }
    }
}



EDIT2:

A C++ wrapper.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class Fix : public mpz_class
{
public:

    using mpz_class::mpz_class;

    void setBitCount ( std::size_t bits )
    {
        m_bitcnt = bits;
    }

    void limit ()
    {
        if ( mpz_scan1 (get_mpz_t(), m_bitcnt) != std::numeric_limits<std::size_t>::max() )
        {
            mpz_neg ( get_mpz_t(), get_mpz_t() );
            if ( mpz_scan1 (get_mpz_t(), m_bitcnt - 1) != std::numeric_limits<std::size_t>::max() )
            {
                mpz_set_ui (get_mpz_t(), 0);
            }
            else
            {
                mpz_neg ( get_mpz_t(), get_mpz_t() );
            }
        }
    }

    std::size_t m_bitcnt = 1;
};
Last edited on
Topic archived. No new replies allowed.