/ src / gmpy2_mpfr.c
gmpy2_mpfr.c
  1  /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2   * gmpy2_mpfr.c                                                            *
  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  /* General purpose functions are defined here. They are used as an alternative
 29   * to code bloat via macro overuse.
 30   */
 31  
 32  static void
 33  _GMPy_MPFR_Cleanup(MPFR_Object **v, CTXT_Object *ctext)
 34  {
 35      /* GMPY_MPFR_CHECK_RANGE(V, CTX) */
 36      if (mpfr_regular_p((*v)->f) &&
 37          (!(((*v)->f->_mpfr_exp >= ctext->ctx.emin) &&
 38             ((*v)->f->_mpfr_exp <= ctext->ctx.emax)))) {
 39          mpfr_exp_t _oldemin, _oldemax;
 40          _oldemin = mpfr_get_emin();
 41          _oldemax = mpfr_get_emax();
 42          mpfr_set_emin(ctext->ctx.emin);
 43          mpfr_set_emax(ctext->ctx.emax); \
 44          (*v)->rc = mpfr_check_range((*v)->f, (*v)->rc, GET_MPFR_ROUND(ctext));
 45          mpfr_set_emin(_oldemin);
 46          mpfr_set_emax(_oldemax);
 47      }
 48  
 49      /* GMPY_MPFR_SUBNORMALIZE(V, CTX) */
 50      if (ctext->ctx.subnormalize &&
 51          (*v)->f->_mpfr_exp >= ctext->ctx.emin &&
 52          (*v)->f->_mpfr_exp <= ctext->ctx.emin + mpfr_get_prec((*v)->f) - 2) {
 53          mpfr_exp_t _oldemin, _oldemax;
 54          _oldemin = mpfr_get_emin();
 55          _oldemax = mpfr_get_emax();
 56          mpfr_set_emin(ctext->ctx.emin);
 57          mpfr_set_emax(ctext->ctx.emax);
 58          (*v)->rc = mpfr_subnormalize((*v)->f, (*v)->rc, GET_MPFR_ROUND(ctext));
 59          mpfr_set_emin(_oldemin);
 60          mpfr_set_emax(_oldemax);
 61      }
 62  
 63      /* GMPY_MPFR_EXCEPTIONS(V, CTX) */
 64      ctext->ctx.underflow |= mpfr_underflow_p();
 65      ctext->ctx.overflow |= mpfr_overflow_p();
 66      ctext->ctx.invalid |= mpfr_nanflag_p();
 67      ctext->ctx.inexact |= mpfr_inexflag_p();
 68      ctext->ctx.divzero |= mpfr_divby0_p();
 69      if (ctext->ctx.traps) {
 70          if ((ctext->ctx.traps & TRAP_UNDERFLOW) && mpfr_underflow_p()) {
 71              PyErr_SetString(GMPyExc_Underflow, "underflow");
 72              Py_XDECREF((PyObject*)(*v));
 73              (*v) = NULL;
 74          }
 75          if ((ctext->ctx.traps & TRAP_OVERFLOW) && mpfr_overflow_p()) {
 76              PyErr_SetString(GMPyExc_Overflow, "overflow");
 77              Py_XDECREF((PyObject*)(*v));
 78              (*v) = NULL;
 79          }
 80          if ((ctext->ctx.traps & TRAP_INEXACT) && mpfr_inexflag_p()) {
 81              PyErr_SetString(GMPyExc_Inexact, "inexact result");
 82              Py_XDECREF((PyObject*)(*v));
 83              (*v) = NULL;
 84          }
 85          if ((ctext->ctx.traps & TRAP_INVALID) && mpfr_nanflag_p()) {
 86              PyErr_SetString(GMPyExc_Invalid, "invalid operation");
 87              Py_XDECREF((PyObject*)(*v));
 88              (*v) = NULL;
 89          }
 90          if ((ctext->ctx.traps & TRAP_DIVZERO) && mpfr_divby0_p()) {
 91              PyErr_SetString(GMPyExc_DivZero, "division by zero");
 92              Py_XDECREF((PyObject*)(*v));
 93              (*v) = NULL;
 94          }
 95      }
 96  }
 97  
 98  PyDoc_STRVAR(GMPy_doc_mpfr,
 99  "mpfr() -> mpfr(0.0)\n\n"
100  "      If no argument is given, return mpfr(0.0).\n\n"
101  "mpfr(n [, precision=0 [, context]]) -> mpfr\n\n"
102  "      Return an 'mpfr' object after converting a numeric value. See\n"
103  "      below for the interpretation of precision.\n\n"
104  "mpfr(s [, precision=0 [, base=0 [, context]]]) -> mpfr\n\n"
105  "      Return a new 'mpfr' object by converting a string s made of\n"
106  "      digits in the given base, possibly with fraction-part (with a\n"
107  "      period as a separator) and/or exponent-part (with an exponent\n"
108  "      marker 'e' for base<=10, else '@'). The base of the string\n"
109  "      representation must be 0 or in the interval [2,62]. If the base\n"
110  "      is 0, the leading digits of the string are used to identify the\n"
111  "      base: 0b implies base=2, 0x implies base=16, otherwise base=10\n"
112  "      is assumed.\n\n"
113  "Note: If a precision greater than or equal to 2 is specified, then it\n"
114  "      is used.\n\n"
115  "      A precision of 0 (the default) implies the precision of either\n"
116  "      the specified context or the current context is used.\n\n"
117  "      A precision of 1 minimizes the loss of precision by following\n"
118  "      these rules:\n"
119  "        1) If n is a radix-2 floating point number, then the full\n"
120  "           precision of n is retained.\n"
121  "        2) If n is an integer, then the precision is the bit length\n"
122  "           of the integer.\n" );
123  
124  #ifdef PY3
125  static PyNumberMethods mpfr_number_methods =
126  {
127      (binaryfunc) GMPy_Number_Add_Slot,       /* nb_add                  */
128      (binaryfunc) GMPy_Number_Sub_Slot,       /* nb_subtract             */
129      (binaryfunc) GMPy_Number_Mul_Slot,       /* nb_multiply             */
130      (binaryfunc) GMPy_Number_Mod_Slot,       /* nb_remainder            */
131      (binaryfunc) GMPy_Number_DivMod_Slot,      /* nb_divmod               */
132      (ternaryfunc) GMPy_Number_Pow_Slot,        /* nb_power                */
133      (unaryfunc) GMPy_MPFR_Minus_Slot,        /* nb_negative             */
134      (unaryfunc) GMPy_MPFR_Plus_Slot,         /* nb_positive             */
135      (unaryfunc) GMPy_MPFR_Abs_Slot,          /* nb_absolute             */
136      (inquiry) GMPy_MPFR_NonZero_Slot,        /* nb_bool                 */
137          0,                                   /* nb_invert               */
138          0,                                   /* nb_lshift               */
139          0,                                   /* nb_rshift               */
140          0,                                   /* nb_and                  */
141          0,                                   /* nb_xor                  */
142          0,                                   /* nb_or                   */
143      (unaryfunc) GMPy_MPFR_Int_Slot,          /* nb_int                  */
144          0,                                   /* nb_reserved             */
145      (unaryfunc) GMPy_MPFR_Float_Slot,        /* nb_float                */
146          0,                                   /* nb_inplace_add          */
147          0,                                   /* nb_inplace_subtract     */
148          0,                                   /* nb_inplace_multiply     */
149          0,                                   /* nb_inplace_remainder    */
150          0,                                   /* nb_inplace_power        */
151          0,                                   /* nb_inplace_lshift       */
152          0,                                   /* nb_inplace_rshift       */
153          0,                                   /* nb_inplace_and          */
154          0,                                   /* nb_inplace_xor          */
155          0,                                   /* nb_inplace_or           */
156      (binaryfunc) GMPy_Number_FloorDiv_Slot,    /* nb_floor_divide         */
157      (binaryfunc) GMPy_Number_TrueDiv_Slot,     /* nb_true_divide          */
158          0,                                   /* nb_inplace_floor_divide */
159          0,                                   /* nb_inplace_true_divide  */
160          0,                                   /* nb_index                */
161  };
162  #else
163  static PyNumberMethods mpfr_number_methods =
164  {
165      (binaryfunc) GMPy_Number_Add_Slot,       /* nb_add                  */
166      (binaryfunc) GMPy_Number_Sub_Slot,       /* nb_subtract             */
167      (binaryfunc) GMPy_Number_Mul_Slot,       /* nb_multiply             */
168      (binaryfunc) GMPy_Number_TrueDiv_Slot,     /* nb_divide               */
169      (binaryfunc) GMPy_Number_Mod_Slot,       /* nb_remainder            */
170      (binaryfunc) GMPy_Number_DivMod_Slot,      /* nb_divmod               */
171      (ternaryfunc) GMPy_Number_Pow_Slot,        /* nb_power                */
172      (unaryfunc) GMPy_MPFR_Minus_Slot,        /* nb_negative             */
173      (unaryfunc) GMPy_MPFR_Plus_Slot,         /* nb_positive             */
174      (unaryfunc) GMPy_MPFR_Abs_Slot,          /* nb_absolute             */
175      (inquiry) GMPy_MPFR_NonZero_Slot,        /* nb_bool                 */
176          0,                                   /* nb_invert               */
177          0,                                   /* nb_lshift               */
178          0,                                   /* nb_rshift               */
179          0,                                   /* nb_and                  */
180          0,                                   /* nb_xor                  */
181          0,                                   /* nb_or                   */
182          0,                                   /* nb_coerce               */
183      (unaryfunc) GMPy_MPFR_Int_Slot,          /* nb_int                  */
184      (unaryfunc) GMPy_MPFR_Long_Slot,         /* nb_long                 */
185      (unaryfunc) GMPy_MPFR_Float_Slot,        /* nb_float                */
186          0,                                   /* nb_oct                  */
187          0,                                   /* nb_hex                  */
188          0,                                   /* nb_inplace_add          */
189          0,                                   /* nb_inplace_subtract     */
190          0,                                   /* nb_inplace_multiply     */
191          0,                                   /* nb_inplace_divide       */
192          0,                                   /* nb_inplace_remainder    */
193          0,                                   /* nb_inplace_power        */
194          0,                                   /* nb_inplace_lshift       */
195          0,                                   /* nb_inplace_rshift       */
196          0,                                   /* nb_inplace_and          */
197          0,                                   /* nb_inplace_xor          */
198          0,                                   /* nb_inplace_or           */
199      (binaryfunc) GMPy_Number_FloorDiv_Slot,    /* nb_floor_divide         */
200      (binaryfunc) GMPy_Number_TrueDiv_Slot,     /* nb_true_divide          */
201          0,                                   /* nb_inplace_floor_divide */
202          0,                                   /* nb_inplace_true_divide  */
203  };
204  #endif
205  
206  static PyGetSetDef Pympfr_getseters[] =
207  {
208      {"precision", (getter)GMPy_MPFR_GetPrec_Attrib, NULL, "precision in bits", NULL},
209      {"rc", (getter)GMPy_MPFR_GetRc_Attrib, NULL, "return code", NULL},
210      {"imag", (getter)GMPy_MPFR_GetImag_Attrib, NULL, "imaginary component", NULL},
211      {"real", (getter)GMPy_MPFR_GetReal_Attrib, NULL, "real component", NULL},
212      {NULL}
213  };
214  
215  static PyMethodDef Pympfr_methods [] =
216  {
217      { "__ceil__", GMPy_MPFR_Method_Ceil, METH_NOARGS, GMPy_doc_mpfr_ceil_method },
218      { "__floor__", GMPy_MPFR_Method_Floor, METH_NOARGS, GMPy_doc_mpfr_floor_method },
219      { "__format__", GMPy_MPFR_Format, METH_VARARGS, GMPy_doc_mpfr_format },
220      { "__round__", GMPy_MPFR_Method_Round10, METH_VARARGS, GMPy_doc_method_round10 },
221      { "__sizeof__", GMPy_MPFR_SizeOf_Method, METH_NOARGS, GMPy_doc_mpfr_sizeof_method },
222      { "__trunc__", GMPy_MPFR_Method_Trunc, METH_NOARGS, GMPy_doc_mpfr_trunc_method },
223      { "as_integer_ratio", GMPy_MPFR_Integer_Ratio_Method, METH_NOARGS, GMPy_doc_method_integer_ratio },
224      { "as_mantissa_exp", GMPy_MPFR_Mantissa_Exp_Method, METH_NOARGS, GMPy_doc_method_mantissa_exp },
225      { "as_simple_fraction", (PyCFunction)GMPy_MPFR_Simple_Fraction_Method, METH_VARARGS | METH_KEYWORDS, GMPy_doc_method_simple_fraction },
226      { "conjugate", GMPy_MP_Method_Conjugate, METH_NOARGS, GMPy_doc_mp_method_conjugate },
227      { "digits", GMPy_MPFR_Digits_Method, METH_VARARGS, GMPy_doc_mpfr_digits_method },
228      { "is_finite", GMPy_MPFR_Is_Finite_Method, METH_NOARGS, GMPy_doc_method_is_finite },
229      { "is_infinite", GMPy_MPFR_Is_Infinite_Method, METH_NOARGS, GMPy_doc_method_is_infinite },
230      { "is_integer", GMPy_MPFR_Is_Integer_Method, METH_NOARGS, GMPy_doc_method_is_integer },
231      { "is_nan", GMPy_MPFR_Is_NAN_Method, METH_NOARGS, GMPy_doc_method_is_nan },
232      { "is_signed", GMPy_MPFR_Is_Regular_Method, METH_NOARGS, GMPy_doc_method_is_regular },
233      { "is_signed", GMPy_MPFR_Is_Signed_Method, METH_NOARGS, GMPy_doc_method_is_signed },
234      { "is_zero", GMPy_MPFR_Is_Zero_Method, METH_NOARGS, GMPy_doc_method_is_zero },
235      { NULL, NULL, 1 }
236  };
237  
238  static PyTypeObject MPFR_Type =
239  {
240      /* PyObject_HEAD_INIT(&PyType_Type) */
241  #ifdef PY3
242      PyVarObject_HEAD_INIT(NULL, 0)
243  #else
244      PyObject_HEAD_INIT(0)
245      0,                                      /* ob_size          */
246  #endif
247      "mpfr",                                 /* tp_name          */
248      sizeof(MPFR_Object),                    /* tp_basicsize     */
249          0,                                  /* tp_itemsize      */
250      /* methods */
251      (destructor) GMPy_MPFR_Dealloc,         /* tp_dealloc       */
252          0,                                  /* tp_print         */
253          0,                                  /* tp_getattr       */
254          0,                                  /* tp_setattr       */
255          0,                                  /* tp_reserved      */
256      (reprfunc) GMPy_MPFR_Repr_Slot,         /* tp_repr          */
257      &mpfr_number_methods,                   /* tp_as_number     */
258          0,                                  /* tp_as_sequence   */
259          0,                                  /* tp_as_mapping    */
260      (hashfunc) GMPy_MPFR_Hash_Slot,         /* tp_hash          */
261          0,                                  /* tp_call          */
262      (reprfunc) GMPy_MPFR_Str_Slot,          /* tp_str           */
263      (getattrofunc) 0,                       /* tp_getattro      */
264      (setattrofunc) 0,                       /* tp_setattro      */
265          0,                                  /* tp_as_buffer     */
266  #ifdef PY3
267      Py_TPFLAGS_DEFAULT,                     /* tp_flags         */
268  #else
269      Py_TPFLAGS_HAVE_RICHCOMPARE|Py_TPFLAGS_CHECKTYPES,  /* tp_flags */
270  #endif
271      GMPy_doc_mpfr,                          /* tp_doc           */
272          0,                                  /* tp_traverse      */
273          0,                                  /* tp_clear         */
274      (richcmpfunc)&GMPy_RichCompare_Slot,    /* tp_richcompare   */
275          0,                                  /* tp_weaklistoffset*/
276          0,                                  /* tp_iter          */
277          0,                                  /* tp_iternext      */
278      Pympfr_methods,                         /* tp_methods       */
279          0,                                  /* tp_members       */
280      Pympfr_getseters,                       /* tp_getset        */
281          0,                                  /* tp_base          */
282          0,                                  /* tp_dict          */
283          0,                                  /* tp_descr_get     */
284          0,                                  /* tp_descr_set     */
285          0,                                  /* tp_dictoffset    */
286          0,                                  /* tp_init          */
287          0,                                  /* tp_alloc         */
288      GMPy_MPFR_NewInit,                      /* tp_new           */
289          0,                                  /* tp_free          */
290  };
291