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