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