floating-pointprecisionmpfr

How to compute DECIMAL_DIG from value returned by mpfr_get_prec()?


Context: C standard has xxx_DECIMAL_DIG macros, which can be used in printf to maintain precision of floating-point value. Example for double:

printf("%.*g\n", DBL_DECIMAL_DIG, x); 

A simple question: how to compute the similar DECIMAL_DIG from value returned by mpfr_get_prec?

Example:

#include <stdio.h>
#include <mpfr.h>

#define PREC 128

int prec2decimal_dig(int prec)
{
    return prec / 3;    // example, not accurate
}

int main (void)
{
    mpfr_t x;

    mpfr_init2(x, PREC);
    mpfr_set_d(x, 2.0 / 3.0, MPFR_RNDN);
    mpfr_printf("%.*Rf\n", prec2decimal_dig(PREC), x);
    return 0;
}

$ gcc t78a.c -lmpfr -lgmp -oa && ./a
0.666666666666666629659232512494781985878944

What would be the precise implementation of prec2decimal_dig?


Extra: base-2: why DECIMAL_DIG - DIG == 2 or 3?.


Solution

  • In practice, the native floating-point numbers are almost always in radix 2 (i.e. FLT_RADIX = 2 and b = 2 in the description of DECIMAL_DIG in the C standard), like MPFR. In this case, you can use mpfr_get_str_ndigits with radix b = 10 (note that b in the C standard is the input radix, i.e. 2, and b in the MPFR manual is the output radix, i.e. 10 in this context). This function is described as:

    Return the minimal integer m such that any number of p bits, when output with m digits in radix b with rounding to nearest, can be recovered exactly when read again, still with rounding to nearest. More precisely, we have m = 1 + ceil(p × log(2)/log(b)), with p replaced by p − 1 if b is a power of 2.

    Note that if FLT_RADIX = 10 on your platform, DECIMAL_DIG is just p. And I don't know any other platform with another radix.