• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
mpd_dflt_traphandler(mpd_context_t * ctx UNUSED)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
mpd_setminalloc(mpd_ssize_t n)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
mpd_init(mpd_context_t * ctx,mpd_ssize_t prec)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
mpd_maxcontext(mpd_context_t * ctx)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
mpd_defaultcontext(mpd_context_t * ctx)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
mpd_basiccontext(mpd_context_t * ctx)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
mpd_ieee_context(mpd_context_t * ctx,int bits)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
mpd_getprec(const mpd_context_t * ctx)147 mpd_getprec(const mpd_context_t *ctx)
148 {
149     return ctx->prec;
150 }
151 
152 mpd_ssize_t
mpd_getemax(const mpd_context_t * ctx)153 mpd_getemax(const mpd_context_t *ctx)
154 {
155     return ctx->emax;
156 }
157 
158 mpd_ssize_t
mpd_getemin(const mpd_context_t * ctx)159 mpd_getemin(const mpd_context_t *ctx)
160 {
161     return ctx->emin;
162 }
163 
164 int
mpd_getround(const mpd_context_t * ctx)165 mpd_getround(const mpd_context_t *ctx)
166 {
167     return ctx->round;
168 }
169 
170 uint32_t
mpd_gettraps(const mpd_context_t * ctx)171 mpd_gettraps(const mpd_context_t *ctx)
172 {
173     return ctx->traps;
174 }
175 
176 uint32_t
mpd_getstatus(const mpd_context_t * ctx)177 mpd_getstatus(const mpd_context_t *ctx)
178 {
179     return ctx->status;
180 }
181 
182 int
mpd_getclamp(const mpd_context_t * ctx)183 mpd_getclamp(const mpd_context_t *ctx)
184 {
185     return ctx->clamp;
186 }
187 
188 int
mpd_getcr(const mpd_context_t * ctx)189 mpd_getcr(const mpd_context_t *ctx)
190 {
191     return ctx->allcr;
192 }
193 
194 
195 int
mpd_qsetprec(mpd_context_t * ctx,mpd_ssize_t prec)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
mpd_qsetemax(mpd_context_t * ctx,mpd_ssize_t emax)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
mpd_qsetemin(mpd_context_t * ctx,mpd_ssize_t emin)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
mpd_qsetround(mpd_context_t * ctx,int round)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
mpd_qsettraps(mpd_context_t * ctx,uint32_t traps)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
mpd_qsetstatus(mpd_context_t * ctx,uint32_t flags)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
mpd_qsetclamp(mpd_context_t * ctx,int c)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
mpd_qsetcr(mpd_context_t * ctx,int c)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
mpd_addstatus_raise(mpd_context_t * ctx,uint32_t flags)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