c++cgmp

Setting Big Integer Number with non-zero terminated string


There is a function to set a mpz number with a zero-terminated string.

int mpz_set_str (mpz_t rop, const char *str, int base);

But there is no functions for a non-zero terminated string, and I would like to do that avoiding allocations and changes on the string.

int mpz_set_strn (mpz_t rop, const char *str, size_t n, int base);

I found a similar discussion about this on gmp-discuss

In my case, I would like to use part of the string. I've tried to simulate what the mpz_set_str function does in the background, but it seems it didn't work.

#include <gmp.h>

int main(){

  const char * str_base16 = "354a546fde";

  mpz_t bn;
  mp_size_t xsize;
  mpz_init(bn);

  // setting bn with part of str_base16
  mpz_realloc2(bn, 8*4);
  xsize = mpn_set_str(bn->_mp_d, (unsigned char *)str_base16, 8, 16);
  bn->_mp_size = xsize;

  gmp_printf("%ZX\n", bn);
  
  return 0;
}

Output:

337637766


Solution

  • Looking at the source code for mpz_set_str(), it looks like you can use the low-level function mpn_set_str() directly, which takes a pointer and length to digits which start at 0 (not the ASCII character '0').

    #include <math.h>
    #include "gmp.h"
    
    // Convert the string of decimal digits dig[0..n-1], each in the range 0..9, to
    // the integer z. (n >= 1)
    void dtoz(mpz_t z, unsigned char const *dig, mp_size_t n) {
        while (n > 1 && *dig == 0)
            dig++, n--;
        mp_size_t s = (M_LN10 / M_LN2 / (8 * sizeof(mp_limb_t))) * n + 2;
        _mpz_realloc(z, s);
        z->_mp_size = mpn_set_str(z->_mp_d, dig, n, 10);
    }
    
    int main(void) {
        mpz_t z;
        mpz_init(z);
        unsigned char dig[] = {
            3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8, 9, 7, 9, 3, 2, 3, 8, 4, 6, 2, 6, 4,
            3, 3, 8, 3, 2, 7, 9, 5, 0, 2, 8, 8, 4, 1, 9, 7, 1, 6, 9, 3, 9, 9, 3, 7,
            5, 1, 0, 5, 8};
        dtoz(z, dig, sizeof(dig));
        gmp_printf("%Zd\n", z);
        dtoz(z, dig + 12, 12);
        gmp_printf("%Zd\n", z);
        return 0;
    }