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

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

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.