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