| 
									
										
										
										
											2012-03-21 18:25:23 +01:00
										 |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2013-12-08 19:54:05 +01:00
										 |  |  |  * Copyright (c) 2008-2016 Stefan Krah. All rights reserved. | 
					
						
							| 
									
										
										
										
											2012-03-21 18:25:23 +01:00
										 |  |  |  * | 
					
						
							|  |  |  |  * Redistribution and use in source and binary forms, with or without | 
					
						
							|  |  |  |  * modification, are permitted provided that the following conditions | 
					
						
							|  |  |  |  * are met: | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * 1. Redistributions of source code must retain the above copyright | 
					
						
							|  |  |  |  *    notice, this list of conditions and the following disclaimer. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * 2. Redistributions in binary form must reproduce the above copyright | 
					
						
							|  |  |  |  *    notice, this list of conditions and the following disclaimer in the | 
					
						
							|  |  |  |  *    documentation and/or other materials provided with the distribution. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND | 
					
						
							|  |  |  |  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 
					
						
							|  |  |  |  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 
					
						
							|  |  |  |  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | 
					
						
							|  |  |  |  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | 
					
						
							|  |  |  |  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | 
					
						
							|  |  |  |  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | 
					
						
							|  |  |  |  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | 
					
						
							|  |  |  |  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 
					
						
							|  |  |  |  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 
					
						
							|  |  |  |  * SUCH DAMAGE. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "mpdecimal.h"
 | 
					
						
							|  |  |  | #include <stdio.h>
 | 
					
						
							|  |  |  | #include <string.h>
 | 
					
						
							|  |  |  | #include <signal.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void | 
					
						
							|  |  |  | mpd_dflt_traphandler(mpd_context_t *ctx UNUSED) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2012-03-21 20:21:20 +01:00
										 |  |  |     raise(SIGFPE); | 
					
						
							| 
									
										
										
										
											2012-03-21 18:25:23 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void (* mpd_traphandler)(mpd_context_t *) = mpd_dflt_traphandler; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Set guaranteed minimum number of coefficient words. The function may
 | 
					
						
							|  |  |  |    be used once at program start. Setting MPD_MINALLOC to out-of-bounds | 
					
						
							|  |  |  |    values is a catastrophic error, so in that case the function exits rather | 
					
						
							|  |  |  |    than relying on the user to check a return value. */ | 
					
						
							|  |  |  | void | 
					
						
							|  |  |  | mpd_setminalloc(mpd_ssize_t n) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2012-03-21 20:21:20 +01:00
										 |  |  |     static int minalloc_is_set = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (minalloc_is_set) { | 
					
						
							|  |  |  |         mpd_err_warn("mpd_setminalloc: ignoring request to set " | 
					
						
							|  |  |  |                      "MPD_MINALLOC a second time\n"); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (n < MPD_MINALLOC_MIN || n > MPD_MINALLOC_MAX) { | 
					
						
							|  |  |  |         mpd_err_fatal("illegal value for MPD_MINALLOC"); /* GCOV_NOT_REACHED */ | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     MPD_MINALLOC = n; | 
					
						
							|  |  |  |     minalloc_is_set = 1; | 
					
						
							| 
									
										
										
										
											2012-03-21 18:25:23 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void | 
					
						
							|  |  |  | mpd_init(mpd_context_t *ctx, mpd_ssize_t prec) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2012-03-21 20:21:20 +01:00
										 |  |  |     mpd_ssize_t ideal_minalloc; | 
					
						
							| 
									
										
										
										
											2012-03-21 18:25:23 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-03-21 20:21:20 +01:00
										 |  |  |     mpd_defaultcontext(ctx); | 
					
						
							| 
									
										
										
										
											2012-03-21 18:25:23 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-03-21 20:21:20 +01:00
										 |  |  |     if (!mpd_qsetprec(ctx, prec)) { | 
					
						
							|  |  |  |         mpd_addstatus_raise(ctx, MPD_Invalid_context); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2012-03-21 18:25:23 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-03-21 20:21:20 +01:00
										 |  |  |     ideal_minalloc = 2 * ((prec+MPD_RDIGITS-1) / MPD_RDIGITS); | 
					
						
							|  |  |  |     if (ideal_minalloc < MPD_MINALLOC_MIN) ideal_minalloc = MPD_MINALLOC_MIN; | 
					
						
							|  |  |  |     if (ideal_minalloc > MPD_MINALLOC_MAX) ideal_minalloc = MPD_MINALLOC_MAX; | 
					
						
							| 
									
										
										
										
											2012-03-21 18:25:23 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-03-21 20:21:20 +01:00
										 |  |  |     mpd_setminalloc(ideal_minalloc); | 
					
						
							| 
									
										
										
										
											2012-03-21 18:25:23 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void | 
					
						
							|  |  |  | mpd_maxcontext(mpd_context_t *ctx) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2012-03-21 20:21:20 +01:00
										 |  |  |     ctx->prec=MPD_MAX_PREC; | 
					
						
							|  |  |  |     ctx->emax=MPD_MAX_EMAX; | 
					
						
							|  |  |  |     ctx->emin=MPD_MIN_EMIN; | 
					
						
							|  |  |  |     ctx->round=MPD_ROUND_HALF_EVEN; | 
					
						
							|  |  |  |     ctx->traps=MPD_Traps; | 
					
						
							|  |  |  |     ctx->status=0; | 
					
						
							|  |  |  |     ctx->newtrap=0; | 
					
						
							|  |  |  |     ctx->clamp=0; | 
					
						
							|  |  |  |     ctx->allcr=1; | 
					
						
							| 
									
										
										
										
											2012-03-21 18:25:23 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void | 
					
						
							|  |  |  | mpd_defaultcontext(mpd_context_t *ctx) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2012-03-21 20:21:20 +01:00
										 |  |  |     ctx->prec=2*MPD_RDIGITS; | 
					
						
							|  |  |  |     ctx->emax=MPD_MAX_EMAX; | 
					
						
							|  |  |  |     ctx->emin=MPD_MIN_EMIN; | 
					
						
							|  |  |  |     ctx->round=MPD_ROUND_HALF_UP; | 
					
						
							|  |  |  |     ctx->traps=MPD_Traps; | 
					
						
							|  |  |  |     ctx->status=0; | 
					
						
							|  |  |  |     ctx->newtrap=0; | 
					
						
							|  |  |  |     ctx->clamp=0; | 
					
						
							|  |  |  |     ctx->allcr=1; | 
					
						
							| 
									
										
										
										
											2012-03-21 18:25:23 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void | 
					
						
							|  |  |  | mpd_basiccontext(mpd_context_t *ctx) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2012-03-21 20:21:20 +01:00
										 |  |  |     ctx->prec=9; | 
					
						
							|  |  |  |     ctx->emax=MPD_MAX_EMAX; | 
					
						
							|  |  |  |     ctx->emin=MPD_MIN_EMIN; | 
					
						
							|  |  |  |     ctx->round=MPD_ROUND_HALF_UP; | 
					
						
							|  |  |  |     ctx->traps=MPD_Traps|MPD_Clamped; | 
					
						
							|  |  |  |     ctx->status=0; | 
					
						
							|  |  |  |     ctx->newtrap=0; | 
					
						
							|  |  |  |     ctx->clamp=0; | 
					
						
							|  |  |  |     ctx->allcr=1; | 
					
						
							| 
									
										
										
										
											2012-03-21 18:25:23 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int | 
					
						
							|  |  |  | mpd_ieee_context(mpd_context_t *ctx, int bits) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2012-03-21 20:21:20 +01:00
										 |  |  |     if (bits <= 0 || bits > MPD_IEEE_CONTEXT_MAX_BITS || bits % 32) { | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ctx->prec = 9 * (bits/32) - 2; | 
					
						
							|  |  |  |     ctx->emax = 3 * ((mpd_ssize_t)1<<(bits/16+3)); | 
					
						
							|  |  |  |     ctx->emin = 1 - ctx->emax; | 
					
						
							|  |  |  |     ctx->round=MPD_ROUND_HALF_EVEN; | 
					
						
							|  |  |  |     ctx->traps=0; | 
					
						
							|  |  |  |     ctx->status=0; | 
					
						
							|  |  |  |     ctx->newtrap=0; | 
					
						
							|  |  |  |     ctx->clamp=1; | 
					
						
							|  |  |  |     ctx->allcr=1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return 0; | 
					
						
							| 
									
										
										
										
											2012-03-21 18:25:23 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | mpd_ssize_t | 
					
						
							|  |  |  | mpd_getprec(const mpd_context_t *ctx) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2012-03-21 20:21:20 +01:00
										 |  |  |     return ctx->prec; | 
					
						
							| 
									
										
										
										
											2012-03-21 18:25:23 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | mpd_ssize_t | 
					
						
							|  |  |  | mpd_getemax(const mpd_context_t *ctx) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2012-03-21 20:21:20 +01:00
										 |  |  |     return ctx->emax; | 
					
						
							| 
									
										
										
										
											2012-03-21 18:25:23 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | mpd_ssize_t | 
					
						
							|  |  |  | mpd_getemin(const mpd_context_t *ctx) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2012-03-21 20:21:20 +01:00
										 |  |  |     return ctx->emin; | 
					
						
							| 
									
										
										
										
											2012-03-21 18:25:23 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int | 
					
						
							|  |  |  | mpd_getround(const mpd_context_t *ctx) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2012-03-21 20:21:20 +01:00
										 |  |  |     return ctx->round; | 
					
						
							| 
									
										
										
										
											2012-03-21 18:25:23 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | uint32_t | 
					
						
							|  |  |  | mpd_gettraps(const mpd_context_t *ctx) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2012-03-21 20:21:20 +01:00
										 |  |  |     return ctx->traps; | 
					
						
							| 
									
										
										
										
											2012-03-21 18:25:23 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | uint32_t | 
					
						
							|  |  |  | mpd_getstatus(const mpd_context_t *ctx) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2012-03-21 20:21:20 +01:00
										 |  |  |     return ctx->status; | 
					
						
							| 
									
										
										
										
											2012-03-21 18:25:23 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int | 
					
						
							|  |  |  | mpd_getclamp(const mpd_context_t *ctx) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2012-03-21 20:21:20 +01:00
										 |  |  |     return ctx->clamp; | 
					
						
							| 
									
										
										
										
											2012-03-21 18:25:23 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int | 
					
						
							|  |  |  | mpd_getcr(const mpd_context_t *ctx) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2012-03-21 20:21:20 +01:00
										 |  |  |     return ctx->allcr; | 
					
						
							| 
									
										
										
										
											2012-03-21 18:25:23 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int | 
					
						
							|  |  |  | mpd_qsetprec(mpd_context_t *ctx, mpd_ssize_t prec) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2012-03-21 20:21:20 +01:00
										 |  |  |     if (prec <= 0 || prec > MPD_MAX_PREC) { | 
					
						
							|  |  |  |         return 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     ctx->prec = prec; | 
					
						
							|  |  |  |     return 1; | 
					
						
							| 
									
										
										
										
											2012-03-21 18:25:23 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int | 
					
						
							|  |  |  | mpd_qsetemax(mpd_context_t *ctx, mpd_ssize_t emax) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2012-03-21 20:21:20 +01:00
										 |  |  |     if (emax < 0 || emax > MPD_MAX_EMAX) { | 
					
						
							|  |  |  |         return 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     ctx->emax = emax; | 
					
						
							|  |  |  |     return 1; | 
					
						
							| 
									
										
										
										
											2012-03-21 18:25:23 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int | 
					
						
							|  |  |  | mpd_qsetemin(mpd_context_t *ctx, mpd_ssize_t emin) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2012-03-21 20:21:20 +01:00
										 |  |  |     if (emin > 0 || emin < MPD_MIN_EMIN) { | 
					
						
							|  |  |  |         return 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     ctx->emin = emin; | 
					
						
							|  |  |  |     return 1; | 
					
						
							| 
									
										
										
										
											2012-03-21 18:25:23 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int | 
					
						
							|  |  |  | mpd_qsetround(mpd_context_t *ctx, int round) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2012-03-21 20:21:20 +01:00
										 |  |  |     if (!(0 <= round && round < MPD_ROUND_GUARD)) { | 
					
						
							|  |  |  |         return 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     ctx->round = round; | 
					
						
							|  |  |  |     return 1; | 
					
						
							| 
									
										
										
										
											2012-03-21 18:25:23 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int | 
					
						
							|  |  |  | mpd_qsettraps(mpd_context_t *ctx, uint32_t traps) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2012-03-21 20:21:20 +01:00
										 |  |  |     if (traps > MPD_Max_status) { | 
					
						
							|  |  |  |         return 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     ctx->traps = traps; | 
					
						
							|  |  |  |     return 1; | 
					
						
							| 
									
										
										
										
											2012-03-21 18:25:23 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int | 
					
						
							|  |  |  | mpd_qsetstatus(mpd_context_t *ctx, uint32_t flags) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2012-03-21 20:21:20 +01:00
										 |  |  |     if (flags > MPD_Max_status) { | 
					
						
							|  |  |  |         return 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     ctx->status = flags; | 
					
						
							|  |  |  |     return 1; | 
					
						
							| 
									
										
										
										
											2012-03-21 18:25:23 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int | 
					
						
							|  |  |  | mpd_qsetclamp(mpd_context_t *ctx, int c) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2012-03-21 20:21:20 +01:00
										 |  |  |     if (c != 0 && c != 1) { | 
					
						
							|  |  |  |         return 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     ctx->clamp = c; | 
					
						
							|  |  |  |     return 1; | 
					
						
							| 
									
										
										
										
											2012-03-21 18:25:23 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int | 
					
						
							|  |  |  | mpd_qsetcr(mpd_context_t *ctx, int c) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2012-03-21 20:21:20 +01:00
										 |  |  |     if (c != 0 && c != 1) { | 
					
						
							|  |  |  |         return 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     ctx->allcr = c; | 
					
						
							|  |  |  |     return 1; | 
					
						
							| 
									
										
										
										
											2012-03-21 18:25:23 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void | 
					
						
							|  |  |  | mpd_addstatus_raise(mpd_context_t *ctx, uint32_t flags) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2012-03-21 20:21:20 +01:00
										 |  |  |     ctx->status |= flags; | 
					
						
							|  |  |  |     if (flags&ctx->traps) { | 
					
						
							|  |  |  |         ctx->newtrap = (flags&ctx->traps); | 
					
						
							|  |  |  |         mpd_traphandler(ctx); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2012-03-21 18:25:23 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 |