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 35void 36mpd_dflt_traphandler(mpd_context_t *ctx UNUSED) 37{ 38 raise(SIGFPE); 39} 40 41void (* 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. */ 48void 49mpd_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 65void 66mpd_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 84void 85mpd_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 98void 99mpd_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 112void 113mpd_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 126int 127mpd_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 146mpd_ssize_t 147mpd_getprec(const mpd_context_t *ctx) 148{ 149 return ctx->prec; 150} 151 152mpd_ssize_t 153mpd_getemax(const mpd_context_t *ctx) 154{ 155 return ctx->emax; 156} 157 158mpd_ssize_t 159mpd_getemin(const mpd_context_t *ctx) 160{ 161 return ctx->emin; 162} 163 164int 165mpd_getround(const mpd_context_t *ctx) 166{ 167 return ctx->round; 168} 169 170uint32_t 171mpd_gettraps(const mpd_context_t *ctx) 172{ 173 return ctx->traps; 174} 175 176uint32_t 177mpd_getstatus(const mpd_context_t *ctx) 178{ 179 return ctx->status; 180} 181 182int 183mpd_getclamp(const mpd_context_t *ctx) 184{ 185 return ctx->clamp; 186} 187 188int 189mpd_getcr(const mpd_context_t *ctx) 190{ 191 return ctx->allcr; 192} 193 194 195int 196mpd_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 205int 206mpd_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 215int 216mpd_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 225int 226mpd_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 235int 236mpd_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 245int 246mpd_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 255int 256mpd_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 265int 266mpd_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 276void 277mpd_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