Home | History | Annotate | Download | only in libmpdec
      1 /*
      2  * Copyright (c) 2008-2016 Stefan Krah. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  *
      8  * 1. Redistributions of source code must retain the above copyright
      9  *    notice, this list of conditions and the following disclaimer.
     10  *
     11  * 2. Redistributions in binary form must reproduce the above copyright
     12  *    notice, this list of conditions and the following disclaimer in the
     13  *    documentation and/or other materials provided with the distribution.
     14  *
     15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
     16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     25  * SUCH DAMAGE.
     26  */
     27 
     28 
     29 #include "mpdecimal.h"
     30 #include <stdio.h>
     31 #include <string.h>
     32 #include <signal.h>
     33 
     34 
     35 void
     36 mpd_dflt_traphandler(mpd_context_t *ctx UNUSED)
     37 {
     38     raise(SIGFPE);
     39 }
     40 
     41 void (* mpd_traphandler)(mpd_context_t *) = mpd_dflt_traphandler;
     42 
     43 
     44 /* Set guaranteed minimum number of coefficient words. The function may
     45    be used once at program start. Setting MPD_MINALLOC to out-of-bounds
     46    values is a catastrophic error, so in that case the function exits rather
     47    than relying on the user to check a return value. */
     48 void
     49 mpd_setminalloc(mpd_ssize_t n)
     50 {
     51     static int minalloc_is_set = 0;
     52 
     53     if (minalloc_is_set) {
     54         mpd_err_warn("mpd_setminalloc: ignoring request to set "
     55                      "MPD_MINALLOC a second time\n");
     56         return;
     57     }
     58     if (n < MPD_MINALLOC_MIN || n > MPD_MINALLOC_MAX) {
     59         mpd_err_fatal("illegal value for MPD_MINALLOC"); /* GCOV_NOT_REACHED */
     60     }
     61     MPD_MINALLOC = n;
     62     minalloc_is_set = 1;
     63 }
     64 
     65 void
     66 mpd_init(mpd_context_t *ctx, mpd_ssize_t prec)
     67 {
     68     mpd_ssize_t ideal_minalloc;
     69 
     70     mpd_defaultcontext(ctx);
     71 
     72     if (!mpd_qsetprec(ctx, prec)) {
     73         mpd_addstatus_raise(ctx, MPD_Invalid_context);
     74         return;
     75     }
     76 
     77     ideal_minalloc = 2 * ((prec+MPD_RDIGITS-1) / MPD_RDIGITS);
     78     if (ideal_minalloc < MPD_MINALLOC_MIN) ideal_minalloc = MPD_MINALLOC_MIN;
     79     if (ideal_minalloc > MPD_MINALLOC_MAX) ideal_minalloc = MPD_MINALLOC_MAX;
     80 
     81     mpd_setminalloc(ideal_minalloc);
     82 }
     83 
     84 void
     85 mpd_maxcontext(mpd_context_t *ctx)
     86 {
     87     ctx->prec=MPD_MAX_PREC;
     88     ctx->emax=MPD_MAX_EMAX;
     89     ctx->emin=MPD_MIN_EMIN;
     90     ctx->round=MPD_ROUND_HALF_EVEN;
     91     ctx->traps=MPD_Traps;
     92     ctx->status=0;
     93     ctx->newtrap=0;
     94     ctx->clamp=0;
     95     ctx->allcr=1;
     96 }
     97 
     98 void
     99 mpd_defaultcontext(mpd_context_t *ctx)
    100 {
    101     ctx->prec=2*MPD_RDIGITS;
    102     ctx->emax=MPD_MAX_EMAX;
    103     ctx->emin=MPD_MIN_EMIN;
    104     ctx->round=MPD_ROUND_HALF_UP;
    105     ctx->traps=MPD_Traps;
    106     ctx->status=0;
    107     ctx->newtrap=0;
    108     ctx->clamp=0;
    109     ctx->allcr=1;
    110 }
    111 
    112 void
    113 mpd_basiccontext(mpd_context_t *ctx)
    114 {
    115     ctx->prec=9;
    116     ctx->emax=MPD_MAX_EMAX;
    117     ctx->emin=MPD_MIN_EMIN;
    118     ctx->round=MPD_ROUND_HALF_UP;
    119     ctx->traps=MPD_Traps|MPD_Clamped;
    120     ctx->status=0;
    121     ctx->newtrap=0;
    122     ctx->clamp=0;
    123     ctx->allcr=1;
    124 }
    125 
    126 int
    127 mpd_ieee_context(mpd_context_t *ctx, int bits)
    128 {
    129     if (bits <= 0 || bits > MPD_IEEE_CONTEXT_MAX_BITS || bits % 32) {
    130         return -1;
    131     }
    132 
    133     ctx->prec = 9 * (bits/32) - 2;
    134     ctx->emax = 3 * ((mpd_ssize_t)1<<(bits/16+3));
    135     ctx->emin = 1 - ctx->emax;
    136     ctx->round=MPD_ROUND_HALF_EVEN;
    137     ctx->traps=0;
    138     ctx->status=0;
    139     ctx->newtrap=0;
    140     ctx->clamp=1;
    141     ctx->allcr=1;
    142 
    143     return 0;
    144 }
    145 
    146 mpd_ssize_t
    147 mpd_getprec(const mpd_context_t *ctx)
    148 {
    149     return ctx->prec;
    150 }
    151 
    152 mpd_ssize_t
    153 mpd_getemax(const mpd_context_t *ctx)
    154 {
    155     return ctx->emax;
    156 }
    157 
    158 mpd_ssize_t
    159 mpd_getemin(const mpd_context_t *ctx)
    160 {
    161     return ctx->emin;
    162 }
    163 
    164 int
    165 mpd_getround(const mpd_context_t *ctx)
    166 {
    167     return ctx->round;
    168 }
    169 
    170 uint32_t
    171 mpd_gettraps(const mpd_context_t *ctx)
    172 {
    173     return ctx->traps;
    174 }
    175 
    176 uint32_t
    177 mpd_getstatus(const mpd_context_t *ctx)
    178 {
    179     return ctx->status;
    180 }
    181 
    182 int
    183 mpd_getclamp(const mpd_context_t *ctx)
    184 {
    185     return ctx->clamp;
    186 }
    187 
    188 int
    189 mpd_getcr(const mpd_context_t *ctx)
    190 {
    191     return ctx->allcr;
    192 }
    193 
    194 
    195 int
    196 mpd_qsetprec(mpd_context_t *ctx, mpd_ssize_t prec)
    197 {
    198     if (prec <= 0 || prec > MPD_MAX_PREC) {
    199         return 0;
    200     }
    201     ctx->prec = prec;
    202     return 1;
    203 }
    204 
    205 int
    206 mpd_qsetemax(mpd_context_t *ctx, mpd_ssize_t emax)
    207 {
    208     if (emax < 0 || emax > MPD_MAX_EMAX) {
    209         return 0;
    210     }
    211     ctx->emax = emax;
    212     return 1;
    213 }
    214 
    215 int
    216 mpd_qsetemin(mpd_context_t *ctx, mpd_ssize_t emin)
    217 {
    218     if (emin > 0 || emin < MPD_MIN_EMIN) {
    219         return 0;
    220     }
    221     ctx->emin = emin;
    222     return 1;
    223 }
    224 
    225 int
    226 mpd_qsetround(mpd_context_t *ctx, int round)
    227 {
    228     if (!(0 <= round && round < MPD_ROUND_GUARD)) {
    229         return 0;
    230     }
    231     ctx->round = round;
    232     return 1;
    233 }
    234 
    235 int
    236 mpd_qsettraps(mpd_context_t *ctx, uint32_t traps)
    237 {
    238     if (traps > MPD_Max_status) {
    239         return 0;
    240     }
    241     ctx->traps = traps;
    242     return 1;
    243 }
    244 
    245 int
    246 mpd_qsetstatus(mpd_context_t *ctx, uint32_t flags)
    247 {
    248     if (flags > MPD_Max_status) {
    249         return 0;
    250     }
    251     ctx->status = flags;
    252     return 1;
    253 }
    254 
    255 int
    256 mpd_qsetclamp(mpd_context_t *ctx, int c)
    257 {
    258     if (c != 0 && c != 1) {
    259         return 0;
    260     }
    261     ctx->clamp = c;
    262     return 1;
    263 }
    264 
    265 int
    266 mpd_qsetcr(mpd_context_t *ctx, int c)
    267 {
    268     if (c != 0 && c != 1) {
    269         return 0;
    270     }
    271     ctx->allcr = c;
    272     return 1;
    273 }
    274 
    275 
    276 void
    277 mpd_addstatus_raise(mpd_context_t *ctx, uint32_t flags)
    278 {
    279     ctx->status |= flags;
    280     if (flags&ctx->traps) {
    281         ctx->newtrap = (flags&ctx->traps);
    282         mpd_traphandler(ctx);
    283     }
    284 }
    285 
    286 
    287