diff options
Diffstat (limited to 'Modules/_decimal/libmpdec/context.c')
-rw-r--r-- | Modules/_decimal/libmpdec/context.c | 286 |
1 files changed, 286 insertions, 0 deletions
diff --git a/Modules/_decimal/libmpdec/context.c b/Modules/_decimal/libmpdec/context.c new file mode 100644 index 0000000..159f88c --- /dev/null +++ b/Modules/_decimal/libmpdec/context.c @@ -0,0 +1,286 @@ +/* + * Copyright (c) 2008-2012 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +#include "mpdecimal.h" +#include <stdio.h> +#include <string.h> +#include <signal.h> + + +void +mpd_dflt_traphandler(mpd_context_t *ctx UNUSED) +{ + raise(SIGFPE); +} + +void (* mpd_traphandler)(mpd_context_t *) = mpd_dflt_traphandler; + + +/* Set guaranteed minimum number of coefficient words. The function may + be used once at program start. Setting MPD_MINALLOC to out-of-bounds + values is a catastrophic error, so in that case the function exits rather + than relying on the user to check a return value. */ +void +mpd_setminalloc(mpd_ssize_t n) +{ + static int minalloc_is_set = 0; + + if (minalloc_is_set) { + mpd_err_warn("mpd_setminalloc: ignoring request to set " + "MPD_MINALLOC a second time\n"); + return; + } + if (n < MPD_MINALLOC_MIN || n > MPD_MINALLOC_MAX) { + mpd_err_fatal("illegal value for MPD_MINALLOC"); /* GCOV_NOT_REACHED */ + } + MPD_MINALLOC = n; + minalloc_is_set = 1; +} + +void +mpd_init(mpd_context_t *ctx, mpd_ssize_t prec) +{ + mpd_ssize_t ideal_minalloc; + + mpd_defaultcontext(ctx); + + if (!mpd_qsetprec(ctx, prec)) { + mpd_addstatus_raise(ctx, MPD_Invalid_context); + return; + } + + ideal_minalloc = 2 * ((prec+MPD_RDIGITS-1) / MPD_RDIGITS); + if (ideal_minalloc < MPD_MINALLOC_MIN) ideal_minalloc = MPD_MINALLOC_MIN; + if (ideal_minalloc > MPD_MINALLOC_MAX) ideal_minalloc = MPD_MINALLOC_MAX; + + mpd_setminalloc(ideal_minalloc); +} + +void +mpd_maxcontext(mpd_context_t *ctx) +{ + ctx->prec=MPD_MAX_PREC; + ctx->emax=MPD_MAX_EMAX; + ctx->emin=MPD_MIN_EMIN; + ctx->round=MPD_ROUND_HALF_EVEN; + ctx->traps=MPD_Traps; + ctx->status=0; + ctx->newtrap=0; + ctx->clamp=0; + ctx->allcr=1; +} + +void +mpd_defaultcontext(mpd_context_t *ctx) +{ + ctx->prec=2*MPD_RDIGITS; + ctx->emax=MPD_MAX_EMAX; + ctx->emin=MPD_MIN_EMIN; + ctx->round=MPD_ROUND_HALF_UP; + ctx->traps=MPD_Traps; + ctx->status=0; + ctx->newtrap=0; + ctx->clamp=0; + ctx->allcr=1; +} + +void +mpd_basiccontext(mpd_context_t *ctx) +{ + ctx->prec=9; + ctx->emax=MPD_MAX_EMAX; + ctx->emin=MPD_MIN_EMIN; + ctx->round=MPD_ROUND_HALF_UP; + ctx->traps=MPD_Traps|MPD_Clamped; + ctx->status=0; + ctx->newtrap=0; + ctx->clamp=0; + ctx->allcr=1; +} + +int +mpd_ieee_context(mpd_context_t *ctx, int bits) +{ + if (bits <= 0 || bits > MPD_IEEE_CONTEXT_MAX_BITS || bits % 32) { + return -1; + } + + ctx->prec = 9 * (bits/32) - 2; + ctx->emax = 3 * ((mpd_ssize_t)1<<(bits/16+3)); + ctx->emin = 1 - ctx->emax; + ctx->round=MPD_ROUND_HALF_EVEN; + ctx->traps=0; + ctx->status=0; + ctx->newtrap=0; + ctx->clamp=1; + ctx->allcr=1; + + return 0; +} + +mpd_ssize_t +mpd_getprec(const mpd_context_t *ctx) +{ + return ctx->prec; +} + +mpd_ssize_t +mpd_getemax(const mpd_context_t *ctx) +{ + return ctx->emax; +} + +mpd_ssize_t +mpd_getemin(const mpd_context_t *ctx) +{ + return ctx->emin; +} + +int +mpd_getround(const mpd_context_t *ctx) +{ + return ctx->round; +} + +uint32_t +mpd_gettraps(const mpd_context_t *ctx) +{ + return ctx->traps; +} + +uint32_t +mpd_getstatus(const mpd_context_t *ctx) +{ + return ctx->status; +} + +int +mpd_getclamp(const mpd_context_t *ctx) +{ + return ctx->clamp; +} + +int +mpd_getcr(const mpd_context_t *ctx) +{ + return ctx->allcr; +} + + +int +mpd_qsetprec(mpd_context_t *ctx, mpd_ssize_t prec) +{ + if (prec <= 0 || prec > MPD_MAX_PREC) { + return 0; + } + ctx->prec = prec; + return 1; +} + +int +mpd_qsetemax(mpd_context_t *ctx, mpd_ssize_t emax) +{ + if (emax < 0 || emax > MPD_MAX_EMAX) { + return 0; + } + ctx->emax = emax; + return 1; +} + +int +mpd_qsetemin(mpd_context_t *ctx, mpd_ssize_t emin) +{ + if (emin > 0 || emin < MPD_MIN_EMIN) { + return 0; + } + ctx->emin = emin; + return 1; +} + +int +mpd_qsetround(mpd_context_t *ctx, int round) +{ + if (!(0 <= round && round < MPD_ROUND_GUARD)) { + return 0; + } + ctx->round = round; + return 1; +} + +int +mpd_qsettraps(mpd_context_t *ctx, uint32_t traps) +{ + if (traps > MPD_Max_status) { + return 0; + } + ctx->traps = traps; + return 1; +} + +int +mpd_qsetstatus(mpd_context_t *ctx, uint32_t flags) +{ + if (flags > MPD_Max_status) { + return 0; + } + ctx->status = flags; + return 1; +} + +int +mpd_qsetclamp(mpd_context_t *ctx, int c) +{ + if (c != 0 && c != 1) { + return 0; + } + ctx->clamp = c; + return 1; +} + +int +mpd_qsetcr(mpd_context_t *ctx, int c) +{ + if (c != 0 && c != 1) { + return 0; + } + ctx->allcr = c; + return 1; +} + + +void +mpd_addstatus_raise(mpd_context_t *ctx, uint32_t flags) +{ + ctx->status |= flags; + if (flags&ctx->traps) { + ctx->newtrap = (flags&ctx->traps); + mpd_traphandler(ctx); + } +} + + |