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 |
|
2 * |
9 |
emax |
|
|
|
emin |
|
|
|
round |
|
|
|
traps |
|
|
|
status |
0 |
0 |
0 |
newtrap |
0 |
0 |
0 |
clamp |
0 |
0 |
0 |
allcr |
1 |
1 |
1 |
libmpdec’s default context
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:
|
|
|
|
---|---|---|---|
prec |
7 |
16 |
34 |
emax |
96 |
384 |
6144 |
emin |
-95 |
-383 |
-6143 |
round |
|
|
|
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
.