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.
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;
32-bit 64-bit MPD_MAX_PREC 425000000 999999999999999999 MPD_MAX_EMAX 425000000 999999999999999999 MPD_MIN_EMIN -425000000 -999999999999999999
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.
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
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.
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.
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.
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 |
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 |
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.
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.