/ src / gmpy2_mpfr.h
gmpy2_mpfr.h
  1  /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2   * gmpy2_mpfr.h                                                            *
  3   * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  4   * Python interface to the GMP or MPIR, MPFR, and MPC multiple precision   *
  5   * libraries.                                                              *
  6   *                                                                         *
  7   * Copyright 2000 - 2009 Alex Martelli                                     *
  8   *                                                                         *
  9   * Copyright 2008 - 2021 Case Van Horsen                                   *
 10   *                                                                         *
 11   * This file is part of GMPY2.                                             *
 12   *                                                                         *
 13   * GMPY2 is free software: you can redistribute it and/or modify it under  *
 14   * the terms of the GNU Lesser General Public License as published by the  *
 15   * Free Software Foundation, either version 3 of the License, or (at your  *
 16   * option) any later version.                                              *
 17   *                                                                         *
 18   * GMPY2 is distributed in the hope that it will be useful, but WITHOUT    *
 19   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or   *
 20   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public    *
 21   * License for more details.                                               *
 22   *                                                                         *
 23   * You should have received a copy of the GNU Lesser General Public        *
 24   * License along with GMPY2; if not, see <http://www.gnu.org/licenses/>    *
 25   * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
 26  
 27  
 28  /* gmpy_mpfr C API extension header file.
 29   *
 30   * Provide interface to the MPFR (Multiple Precision Floating-point with
 31   * Rounding) library.
 32   *
 33   * Version 2.00, April 2011 (created) casevh
 34   */
 35  
 36  #ifndef GMPY_MPFR_H
 37  #define GMPY_MPFR_H
 38  
 39  #ifdef __cplusplus
 40  extern "C" {
 41  #endif
 42  
 43  
 44  #if !defined(FLT_RADIX) || (FLT_RADIX!=2)
 45  #   error "FLT_RADIX undefined or != 2, GMPY2 is confused. :("
 46  #endif
 47  
 48  #if defined(MS_WIN32) && defined(_MSC_VER)
 49  #  pragma comment(lib,"mpfr.lib")
 50  #endif
 51  
 52  #ifdef FAST
 53  
 54  /* Very bad code ahead. I've copied portions of mpfr-impl.h and
 55   * hacked them so they work. This code will only be enabled if you
 56   * specify the --fast option.
 57   */
 58  
 59  #define MPFR_THREAD_ATTR __thread
 60  __MPFR_DECLSPEC extern MPFR_THREAD_ATTR unsigned int __gmpfr_flags;
 61  __MPFR_DECLSPEC extern MPFR_THREAD_ATTR mpfr_exp_t   __gmpfr_emin;
 62  __MPFR_DECLSPEC extern MPFR_THREAD_ATTR mpfr_exp_t   __gmpfr_emax;
 63  
 64  /* Flags of __gmpfr_flags */
 65  #define MPFR_FLAGS_UNDERFLOW 1
 66  #define MPFR_FLAGS_OVERFLOW 2
 67  #define MPFR_FLAGS_NAN 4
 68  #define MPFR_FLAGS_INEXACT 8
 69  #define MPFR_FLAGS_ERANGE 16
 70  #define MPFR_FLAGS_DIVBY0 32
 71  #define MPFR_FLAGS_ALL (MPFR_FLAGS_UNDERFLOW | \
 72                          MPFR_FLAGS_OVERFLOW  | \
 73                          MPFR_FLAGS_NAN       | \
 74                          MPFR_FLAGS_INEXACT   | \
 75                          MPFR_FLAGS_ERANGE    | \
 76                          MPFR_FLAGS_DIVBY0)
 77  
 78  /* Replace some common functions for direct access to the global vars */
 79  #define mpfr_get_emin() (__gmpfr_emin + 0)
 80  #define mpfr_get_emax() (__gmpfr_emax + 0)
 81  
 82  #define mpfr_clear_flags()      ((void) (__gmpfr_flags = 0))
 83  #define mpfr_clear_underflow()  ((void) (__gmpfr_flags &= MPFR_FLAGS_ALL ^ MPFR_FLAGS_UNDERFLOW))
 84  #define mpfr_clear_overflow()   ((void) (__gmpfr_flags &= MPFR_FLAGS_ALL ^ MPFR_FLAGS_OVERFLOW))
 85  #define mpfr_clear_nanflag()    ((void) (__gmpfr_flags &= MPFR_FLAGS_ALL ^ MPFR_FLAGS_NAN))
 86  #define mpfr_clear_inexflag()   ((void) (__gmpfr_flags &= MPFR_FLAGS_ALL ^ MPFR_FLAGS_INEXACT))
 87  #define mpfr_clear_erangeflag() ((void) (__gmpfr_flags &= MPFR_FLAGS_ALL ^ MPFR_FLAGS_ERANGE))
 88  #define mpfr_clear_divby0()     ((void) (__gmpfr_flags &= MPFR_FLAGS_ALL ^ MPFR_FLAGS_DIVBY0))
 89  #define mpfr_underflow_p()      ((int) (__gmpfr_flags & MPFR_FLAGS_UNDERFLOW))
 90  #define mpfr_overflow_p()       ((int) (__gmpfr_flags & MPFR_FLAGS_OVERFLOW))
 91  #define mpfr_nanflag_p()        ((int) (__gmpfr_flags & MPFR_FLAGS_NAN))
 92  #define mpfr_inexflag_p()       ((int) (__gmpfr_flags & MPFR_FLAGS_INEXACT))
 93  #define mpfr_erangeflag_p()     ((int) (__gmpfr_flags & MPFR_FLAGS_ERANGE))
 94  #define mpfr_divby0_p()         ((int) (__gmpfr_flags & MPFR_FLAGS_DIVBY0))
 95  
 96  #define mpfr_check_range(x,t,r) \
 97   ((((x)->_mpfr_exp) >= __gmpfr_emin && ((x)->_mpfr_exp) <= __gmpfr_emax) \
 98    ? ((t) ? (__gmpfr_flags |= MPFR_FLAGS_INEXACT, (t)) : 0)               \
 99    : mpfr_check_range(x,t,r))
100  
101  /* End of the really bad code. Hopefully.
102   */
103  
104  #endif
105  
106  static PyTypeObject MPFR_Type;
107  #define MPFR_Check(v) (((PyObject*)v)->ob_type == &MPFR_Type)
108  
109  #define GMPY_DIVZERO(msg) PyErr_SetString(GMPyExc_DivZero, msg)
110  #define GMPY_INEXACT(msg) PyErr_SetString(GMPyExc_Inexact, msg)
111  #define GMPY_INVALID(msg) PyErr_SetString(GMPyExc_Invalid, msg)
112  #define GMPY_OVERFLOW(msg) PyErr_SetString(GMPyExc_Overflow, msg)
113  #define GMPY_UNDERFLOW(msg) PyErr_SetString(GMPyExc_Underflow, msg)
114  #define GMPY_ERANGE(msg) PyErr_SetString(GMPyExc_Erange, msg)
115  
116  #define GMPY_MPFR_CHECK_RANGE(V, CTX) \
117      if (mpfr_regular_p(V->f) && \
118          (!((V->f->_mpfr_exp >= CTX->ctx.emin) && \
119              (V->f->_mpfr_exp <= CTX->ctx.emax)))) { \
120          mpfr_exp_t _oldemin, _oldemax; \
121          _oldemin = mpfr_get_emin(); \
122          _oldemax = mpfr_get_emax(); \
123          mpfr_set_emin(CTX->ctx.emin); \
124          mpfr_set_emax(CTX->ctx.emax); \
125          V->rc = mpfr_check_range(V->f, V->rc, GET_MPFR_ROUND(CTX)); \
126          mpfr_set_emin(_oldemin); \
127          mpfr_set_emax(_oldemax); \
128      }
129  
130  #define GMPY_MPFR_SUBNORMALIZE(V, CTX) \
131      if (CTX->ctx.subnormalize && \
132          V->f->_mpfr_exp >= CTX->ctx.emin && \
133          V->f->_mpfr_exp <= CTX->ctx.emin + mpfr_get_prec(V->f) - 2) { \
134          mpfr_exp_t _oldemin, _oldemax; \
135          _oldemin = mpfr_get_emin(); \
136          _oldemax = mpfr_get_emax(); \
137          mpfr_set_emin(CTX->ctx.emin); \
138          mpfr_set_emax(CTX->ctx.emax); \
139          V->rc = mpfr_subnormalize(V->f, V->rc, GET_MPFR_ROUND(CTX)); \
140          mpfr_set_emin(_oldemin); \
141          mpfr_set_emax(_oldemax); \
142      }
143  
144  /* Exceptions should be checked in order of least important to most important.
145   */
146  
147  #define GMPY_MPFR_EXCEPTIONS(V, CTX) \
148      CTX->ctx.underflow |= mpfr_underflow_p(); \
149      CTX->ctx.overflow |= mpfr_overflow_p(); \
150      CTX->ctx.invalid |= mpfr_nanflag_p(); \
151      CTX->ctx.inexact |= mpfr_inexflag_p(); \
152      CTX->ctx.divzero |= mpfr_divby0_p(); \
153      if (CTX->ctx.traps) { \
154          if ((CTX->ctx.traps & TRAP_UNDERFLOW) && mpfr_underflow_p()) { \
155              GMPY_UNDERFLOW("underflow"); \
156              Py_XDECREF((PyObject*)V); \
157              V = NULL; \
158          } \
159          if ((CTX->ctx.traps & TRAP_OVERFLOW) && mpfr_overflow_p()) { \
160              GMPY_OVERFLOW("overflow"); \
161              Py_XDECREF((PyObject*)V); \
162              V = NULL; \
163          } \
164          if ((CTX->ctx.traps & TRAP_INEXACT) && mpfr_inexflag_p()) { \
165              GMPY_INEXACT("inexact result"); \
166              Py_XDECREF((PyObject*)V); \
167              V = NULL; \
168          } \
169          if ((CTX->ctx.traps & TRAP_INVALID) && mpfr_nanflag_p()) { \
170              GMPY_INVALID("invalid operation"); \
171              Py_XDECREF((PyObject*)V); \
172              V = NULL; \
173          } \
174          if ((CTX->ctx.traps & TRAP_DIVZERO) && mpfr_divby0_p()) { \
175              GMPY_DIVZERO("division by zero"); \
176              Py_XDECREF((PyObject*)V); \
177              V = NULL; \
178          } \
179      }
180  
181  #define GMPY_MPFR_CLEANUP(V, CTX) \
182      GMPY_MPFR_CHECK_RANGE(V, CTX); \
183      GMPY_MPFR_SUBNORMALIZE(V, CTX); \
184      GMPY_MPFR_EXCEPTIONS(V, CTX);
185  
186  #define GMPY_CHECK_ERANGE(V, CTX, MSG) \
187      CTX->ctx.erange |= mpfr_erangeflag_p(); \
188      if (CTX->ctx.traps) { \
189          if ((CTX->ctx.traps & TRAP_ERANGE) && mpfr_erangeflag_p()) { \
190              GMPY_ERANGE(MSG); \
191              Py_XDECREF((PyObject*)V); \
192              V = NULL; \
193          } \
194      } \
195  
196  static void _GMPy_MPFR_Cleanup(MPFR_Object **v, CTXT_Object *ctext);
197  
198  #ifdef __cplusplus
199  }
200  #endif
201  #endif