Power function for mpf_class numbers in gmpxx

gmp library provides the function void mpf_pow_ui (mpf_t rop, const mpf_t op1, unsigned long int op2) to raise op1 to the power op2 (according to https://gmplib.org/manual/Float-Arithmetic#index-Powering-functions-1).

But the documentation seems to say nothing about it in the c++ interface. I've tried with names such as pow, pow_iu, power but none of them are defined.

Is there the way to raise a float to an exponent (either float or integer) using gmpxx?


gmpxx.h contains interfaces to some mathematical operations like sqrt (see line 3341)

__GMP_DEFINE_UNARY_FUNCTION_1(mpf_t, sqrt, __gmp_sqrt_function)

where the caps-named macro depends on a general evaluation class template named __gmp_expr<T, U>, which in turn allows for the eval of expressions with mixed native and arbitray-precision types, and that's what makes the C++ GMP interface much easier to use.

But there's no such definition for pow. As Marc Glisse pointed out, you must convert your C++ objects to the C types using the mpf_class::get_mpf_t function.

The following is an example code. Name it, say, test.cpp.

#include <iostream>
#include <gmpxx.h>
using namespace std;

int main (void) {
    mpf_class a = 12.3;
    unsigned long int b = 123UL;
    mpf_t c;
    mpf_set_default_prec(100000);
    mpf_init(c);
    mpf_pow_ui(c, a.get_mpf_t(), b);
    gmp_printf("c = %.50Ff\n", c);
    return 0;
}

And compile with

g++ test.cpp -o test -lgmpxx -lgmp

Which produces the output:

114374367934618002778643226182707594198913258409535335775583252201365538178632825702225459029661601216944929436371688246107986574246790.32099077871758646985223686110515186972735931183764

Unfortunately, even when increasing mpf precision, I can't make this agree further than 14 digits with the answer from WolframAlpha:

114374367934617190099880295228066276746218078451850229775887975052369504785666896446606568365201542169649974727730628842345343196581134.89591994282087444983721209947664895835902379607854

Note that if you want to raise an arbitrary-precision float to an arbitrary-precision float you'll need to use the function mpfr_pow from the MPFR library, which by the way is recommended library to handle arbitrary-precision float:

New projects should consider using the GMP extension library MPFR (http://mpfr.org) instead. MPFR provides well-defined precision and accurate rounding, and thereby naturally extends IEEE P754.

EDIT: Due to the discrepancy between GMP and WolframAlpha (which, by the way, uses GMP internally) I've posted this question.

EDIT2: As mentioned in this and in this comments, the discrepancy is expected, since when using the mpf_pow_ui function the compiler converts 12.3 into a double, which is not exactly representable in binary, while Mathematica uses arbitrary precision for that value, so its more accurate in this particular case.

EDIT3: GMP can actually match the result from WolframAlpha, as explained by John Bollinger in his answer.

The issue with my original code is in using the mpf_set_d function to set the value 12.3, because it converts to double and thus looses precision. John modified the code to use the mpf_set_str function instead, which, converted to C++, becomes:

#include <iostream>
#include <gmpxx.h>
using namespace std;

int main (void) {
    mpf_class a("12.3",2000);
    unsigned long int b = 123UL;
    mpf_t c;
    mpf_set_default_prec(2000);
    mpf_init(c);
    mpf_pow_ui(c, a.get_mpf_t(), b);
    gmp_printf("c = %.50Ff\n", c);
    return 0;
}

And this outputs the fully correct answer (with last digit rounded to '5' since that digit was a '4' followed by '9'):

114374367934617190099880295228066276746218078451850229775887975052369504785666896446606568365201542169649974727730628842345343196581134.89591994282087444983721209947664895835902379607855