Line data Source code
1 : /*
2 : * Copyright (c) 2008-2012 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 0 : mpd_dflt_traphandler(mpd_context_t *ctx UNUSED)
37 : {
38 0 : raise(SIGFPE);
39 0 : }
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 0 : mpd_setminalloc(mpd_ssize_t n)
50 : {
51 : static int minalloc_is_set = 0;
52 :
53 0 : if (minalloc_is_set) {
54 0 : mpd_err_warn("mpd_setminalloc: ignoring request to set "
55 : "MPD_MINALLOC a second time\n");
56 0 : return;
57 : }
58 0 : if (n < MPD_MINALLOC_MIN || n > MPD_MINALLOC_MAX) {
59 0 : mpd_err_fatal("illegal value for MPD_MINALLOC"); /* GCOV_NOT_REACHED */
60 : }
61 0 : MPD_MINALLOC = n;
62 0 : minalloc_is_set = 1;
63 : }
64 :
65 : void
66 0 : mpd_init(mpd_context_t *ctx, mpd_ssize_t prec)
67 : {
68 : mpd_ssize_t ideal_minalloc;
69 :
70 0 : mpd_defaultcontext(ctx);
71 :
72 0 : if (!mpd_qsetprec(ctx, prec)) {
73 0 : mpd_addstatus_raise(ctx, MPD_Invalid_context);
74 0 : return;
75 : }
76 :
77 0 : ideal_minalloc = 2 * ((prec+MPD_RDIGITS-1) / MPD_RDIGITS);
78 0 : if (ideal_minalloc < MPD_MINALLOC_MIN) ideal_minalloc = MPD_MINALLOC_MIN;
79 0 : if (ideal_minalloc > MPD_MINALLOC_MAX) ideal_minalloc = MPD_MINALLOC_MAX;
80 :
81 0 : mpd_setminalloc(ideal_minalloc);
82 : }
83 :
84 : void
85 0 : mpd_maxcontext(mpd_context_t *ctx)
86 : {
87 0 : ctx->prec=MPD_MAX_PREC;
88 0 : ctx->emax=MPD_MAX_EMAX;
89 0 : ctx->emin=MPD_MIN_EMIN;
90 0 : ctx->round=MPD_ROUND_HALF_EVEN;
91 0 : ctx->traps=MPD_Traps;
92 0 : ctx->status=0;
93 0 : ctx->newtrap=0;
94 0 : ctx->clamp=0;
95 0 : ctx->allcr=1;
96 0 : }
97 :
98 : void
99 0 : mpd_defaultcontext(mpd_context_t *ctx)
100 : {
101 0 : ctx->prec=2*MPD_RDIGITS;
102 0 : ctx->emax=MPD_MAX_EMAX;
103 0 : ctx->emin=MPD_MIN_EMIN;
104 0 : ctx->round=MPD_ROUND_HALF_UP;
105 0 : ctx->traps=MPD_Traps;
106 0 : ctx->status=0;
107 0 : ctx->newtrap=0;
108 0 : ctx->clamp=0;
109 0 : ctx->allcr=1;
110 0 : }
111 :
112 : void
113 0 : mpd_basiccontext(mpd_context_t *ctx)
114 : {
115 0 : ctx->prec=9;
116 0 : ctx->emax=MPD_MAX_EMAX;
117 0 : ctx->emin=MPD_MIN_EMIN;
118 0 : ctx->round=MPD_ROUND_HALF_UP;
119 0 : ctx->traps=MPD_Traps|MPD_Clamped;
120 0 : ctx->status=0;
121 0 : ctx->newtrap=0;
122 0 : ctx->clamp=0;
123 0 : ctx->allcr=1;
124 0 : }
125 :
126 : int
127 0 : mpd_ieee_context(mpd_context_t *ctx, int bits)
128 : {
129 0 : if (bits <= 0 || bits > MPD_IEEE_CONTEXT_MAX_BITS || bits % 32) {
130 0 : return -1;
131 : }
132 :
133 0 : ctx->prec = 9 * (bits/32) - 2;
134 0 : ctx->emax = 3 * ((mpd_ssize_t)1<<(bits/16+3));
135 0 : ctx->emin = 1 - ctx->emax;
136 0 : ctx->round=MPD_ROUND_HALF_EVEN;
137 0 : ctx->traps=0;
138 0 : ctx->status=0;
139 0 : ctx->newtrap=0;
140 0 : ctx->clamp=1;
141 0 : ctx->allcr=1;
142 :
143 0 : return 0;
144 : }
145 :
146 : mpd_ssize_t
147 0 : mpd_getprec(const mpd_context_t *ctx)
148 : {
149 0 : return ctx->prec;
150 : }
151 :
152 : mpd_ssize_t
153 0 : mpd_getemax(const mpd_context_t *ctx)
154 : {
155 0 : return ctx->emax;
156 : }
157 :
158 : mpd_ssize_t
159 0 : mpd_getemin(const mpd_context_t *ctx)
160 : {
161 0 : return ctx->emin;
162 : }
163 :
164 : int
165 0 : mpd_getround(const mpd_context_t *ctx)
166 : {
167 0 : return ctx->round;
168 : }
169 :
170 : uint32_t
171 0 : mpd_gettraps(const mpd_context_t *ctx)
172 : {
173 0 : return ctx->traps;
174 : }
175 :
176 : uint32_t
177 0 : mpd_getstatus(const mpd_context_t *ctx)
178 : {
179 0 : return ctx->status;
180 : }
181 :
182 : int
183 0 : mpd_getclamp(const mpd_context_t *ctx)
184 : {
185 0 : return ctx->clamp;
186 : }
187 :
188 : int
189 0 : mpd_getcr(const mpd_context_t *ctx)
190 : {
191 0 : return ctx->allcr;
192 : }
193 :
194 :
195 : int
196 0 : mpd_qsetprec(mpd_context_t *ctx, mpd_ssize_t prec)
197 : {
198 0 : if (prec <= 0 || prec > MPD_MAX_PREC) {
199 0 : return 0;
200 : }
201 0 : ctx->prec = prec;
202 0 : return 1;
203 : }
204 :
205 : int
206 0 : mpd_qsetemax(mpd_context_t *ctx, mpd_ssize_t emax)
207 : {
208 0 : if (emax < 0 || emax > MPD_MAX_EMAX) {
209 0 : return 0;
210 : }
211 0 : ctx->emax = emax;
212 0 : return 1;
213 : }
214 :
215 : int
216 0 : mpd_qsetemin(mpd_context_t *ctx, mpd_ssize_t emin)
217 : {
218 0 : if (emin > 0 || emin < MPD_MIN_EMIN) {
219 0 : return 0;
220 : }
221 0 : ctx->emin = emin;
222 0 : return 1;
223 : }
224 :
225 : int
226 0 : mpd_qsetround(mpd_context_t *ctx, int round)
227 : {
228 0 : if (!(0 <= round && round < MPD_ROUND_GUARD)) {
229 0 : return 0;
230 : }
231 0 : ctx->round = round;
232 0 : return 1;
233 : }
234 :
235 : int
236 0 : mpd_qsettraps(mpd_context_t *ctx, uint32_t traps)
237 : {
238 0 : if (traps > MPD_Max_status) {
239 0 : return 0;
240 : }
241 0 : ctx->traps = traps;
242 0 : return 1;
243 : }
244 :
245 : int
246 0 : mpd_qsetstatus(mpd_context_t *ctx, uint32_t flags)
247 : {
248 0 : if (flags > MPD_Max_status) {
249 0 : return 0;
250 : }
251 0 : ctx->status = flags;
252 0 : return 1;
253 : }
254 :
255 : int
256 0 : mpd_qsetclamp(mpd_context_t *ctx, int c)
257 : {
258 0 : if (c != 0 && c != 1) {
259 0 : return 0;
260 : }
261 0 : ctx->clamp = c;
262 0 : return 1;
263 : }
264 :
265 : int
266 0 : mpd_qsetcr(mpd_context_t *ctx, int c)
267 : {
268 0 : if (c != 0 && c != 1) {
269 0 : return 0;
270 : }
271 0 : ctx->allcr = c;
272 0 : return 1;
273 : }
274 :
275 :
276 : void
277 0 : mpd_addstatus_raise(mpd_context_t *ctx, uint32_t flags)
278 : {
279 0 : ctx->status |= flags;
280 0 : if (flags&ctx->traps) {
281 0 : ctx->newtrap = (flags&ctx->traps);
282 0 : mpd_traphandler(ctx);
283 : }
284 0 : }
285 :
286 :
|