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