Context

Most operations are affected by context. Usually, a pointer to the context is passed as the last parameter to signaling functions or the last but one parameter to quiet functions.

Data Type

The context is defined as a C struct:

#include <mpdecimal.h>


typedef struct mpd_context_t {
        mpd_ssize_t prec;   // precision
        mpd_ssize_t emax;   // max positive exp
        mpd_ssize_t emin;   // min negative exp
        uint32_t traps;     // status events that should be trapped
        uint32_t status;    // status flags
        uint32_t newtrap;   // set by mpd_addstatus_raise()
        int      round;     // rounding mode
        int      clamp;     // clamp mode
        int      allcr;     // all functions correctly rounded
} mpd_context_t;

Constants

  32-bit 64-bit
MPD_MAX_PREC 425000000 999999999999999999
MPD_MAX_EMAX 425000000 999999999999999999
MPD_MIN_EMIN -425000000 -999999999999999999

Precision and Exponents

prec [1, MPD_MAX_PREC]
emax [0, MPD_MAX_EMAX]
emin [MPD_MIN_EMIN, 0]

Apart from the limits, the following rules must be observed when setting the context manually:

  • prec <= emax
  • emin = 1 - emax or emin = -emax

The specification requires 5 x prec <= emax and recommends 10 x prec <= emax.

Rounding

The round field can take one of these values:

MPD_ROUND_UP round away from 0
MPD_ROUND_DOWN round toward 0 (truncate)
MPD_ROUND_CEILING round toward +infinity
MPD_ROUND_FLOOR round toward -infinity
MPD_ROUND_HALF_UP 0.5 is rounded up
MPD_ROUND_HALF_DOWN 0.5 is rounded down
MPD_ROUND_HALF_EVEN 0.5 is rounded to even
MPD_ROUND_05UP round zero or five away from 0
MPD_ROUND_TRUNC truncate, but set infinities

Signals and Conditions

The standard distinguishes between signals and conditions. In particular, the MPD_IEEE_Invalid_operation signal comprises several conditions.

In a signaling function, the status field of the context is updated with all conditions that occurred during the execution. It is never reset automatically, so at any point in a program it contains the cumulative status of all signaling functions.

The traps field determines which signals invoke the mpd_traphandler custom function. By default, this function raises SIGFPE.

If a trap occurs, the newtrap field is set to the value of the respective condition. This makes it possible to determine the latest error condition that occurred even when the status has already been “polluted” with previous error conditions.

Here are the possible signals and conditions:

Signals Conditions
MPD_IEEE_Invalid_operation MPD_Conversion_syntax
MPD_Division_impossible
MPD_Division_undefined
MPD_Invalid_context
MPD_Invalid_operation
MPD_Malloc_error
MPD_Clamped MPD_Clamped
MPD_Division_by_zero MPD_Division_by_zero
MPD_Fpu_error [1] MPD_Fpu_error
MPD_Inexact MPD_Inexact
MPD_Not_implemented [2] MPD_Not_implemented
MPD_Overflow MPD_Overflow
MPD_Rounded MPD_Rounded
MPD_Subnormal MPD_Subnormal
MPD_Underflow MPD_Underflow
[1]deprecated, might be renamed to a user-definable signal.
[2]unused, might be renamed to a user-definable signal.

Exponent Clamping

If the clamp field is set to 1, the maximum exponent is reduced to emax - prec + 1. This is compatible with the IEEE 754 decimal interchange formats.

Correct Rounding

Most functions are correctly-rounded by default. If allcr is set to 1, correct rounding is additionally enabled for mpd_exp, mpd_ln and mpd_log10.

In this case, all functions except mpd_pow and mpd_invroot return correctly rounded results.

Context Functions

Initialization

void mpd_init(mpd_context_t *ctx, mpd_ssize_t prec);

ctx is initialized by mpd_defaultcontext, using prec. At the same time, MPD_MINALLOC is initialized to the ideal value for the given precision. Note that memory usage increases by setting MPD_MINALLOC to higher values.

This function can only be used at program start.

void mpd_maxcontext(mpd_context_t *ctx);
void mpd_defaultcontext(mpd_context_t *ctx);
void mpd_basiccontext(mpd_context_t *ctx);

Initialize the given context. The values for each function:

  maxcontext defaultcontext [3] basiccontext [4]
prec MPD_MAX_PREC 2*MPD_RDIGITS 9
emax MPD_MAX_EMAX MPD_MAX_EMAX MPD_MAX_EMAX
emin MPD_MIN_EMIN MPD_MIN_EMIN MPD_MIN_EMIN
round MPD_ROUND_HALF_EVEN MPD_ROUND_HALF_UP MPD_ROUND_HALF_UP
traps MPD_Traps MPD_Traps MPD_Traps|MPD_Clamped
status 0 0 0
newtrap 0 0 0
clamp 0 0 0
allcr 1 1 1
[3]libmpdec’s default context
[4]the specification’s basic default context

IEEE Interchange Formats

MPD_IEEE_CONTEXT_MAX_BITS
MPD_DECIMAL32
MPD_DECIMAL64
MPD_DECIMAL128

int mpd_ieee_context(mpd_context_t *ctx, int bits);

Initialize the context to the proper values for one of the IEEE interchange formats. The argument must be a multiple of 32 and less than IEEE_CONTEXT_MAX_BITS.

For the most common values, the following constants are provided:

  MPD_DECIMAL32 MPD_DECIMAL64 MPD_DECIMAL128
prec 7 16 34
emax 96 384 6144
emin -95 -383 -6143
round MPD_ROUND_HALF_EVEN MPD_ROUND_HALF_EVEN MPD_ROUND_HALF_EVEN
traps 0 0 0
status 0 0 0
newtrap 0 0 0
clamp 1 1 1
allcr 1 1 1

Getters and Setters

size_t mpd_getprec(const mpd_context_t *ctx);
mpd_ssize_t mpd_getemax(const mpd_context_t *ctx);
mpd_ssize_t mpd_getemin(const mpd_context_t *ctx);
int mpd_getround(const mpd_context_t *ctx);
uint32_t mpd_gettraps(const mpd_context_t *ctx);
uint32_t mpd_getstatus(const mpd_context_t *ctx);
int mpd_getclamp(const mpd_context_t *ctx);
int mpd_getcr(const mpd_context_t *ctx);

Get the individual values.

mpd_ssize_t mpd_etiny(const mpd_context_t *ctx);

Return the lowest possible exponent of a subnormal number: emin - prec + 1

mpd_ssize_t mpd_etop(const mpd_context_t *ctx);

Return the highest possible exponent of a normal number: emax - prec + 1

Only relevant if clamp is set to 1.

int mpd_qsetprec(mpd_context_t *ctx, mpd_ssize_t prec);
int mpd_qsetemax(mpd_context_t *ctx, mpd_ssize_t emax);
int mpd_qsetemin(mpd_context_t *ctx, mpd_ssize_t emin);
int mpd_qsetround(mpd_context_t *ctx, int newround);
int mpd_qsettraps(mpd_context_t *ctx, uint32_t flags);
int mpd_qsetstatus(mpd_context_t *ctx, uint32_t flags);
int mpd_qsetclamp(mpd_context_t *ctx, int c);
int mpd_qsetcr(mpd_context_t *ctx, int c);

Quietly set the individual values. These functions check the limits, but they are not foolproof: For example, they still allow setting a prec that does not agree with emax. The functions return 1 on success and 0 on failure. They are quiet since raising an MPD_Invalid_context condition would not make sense in most cases.

Calling the Trap Handler

extern void (* mpd_traphandler)(mpd_context_t *);
void mpd_dflt_traphandler(mpd_context_t *);

void mpd_addstatus_raise(mpd_context_t *ctx, uint32_t flags);

Add flags to the status field of ctx. If a condition is trapped, set newtrap to the condition and call mpd_traphandler. By default, mpd_traphandler is points to mpd_dflt_traphandler, which raises SIGFPE.