Setting Big Integer Number with non-zero terminated string

116 Views Asked by At

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

1

There are 1 best solutions below

0
Mark Adler On BEST ANSWER

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;
}