├── .gitignore ├── .travis.yml ├── MANIFEST.in ├── bigfloat ├── test │ ├── test___all__.py │ ├── test_data │ │ ├── next_up.bft │ │ ├── next_down.bft │ │ ├── mod.bft │ │ ├── pos.bft │ │ ├── various.bft │ │ └── floordiv.bft │ ├── __init__.py │ ├── test_rounding_mode.py │ ├── test_mpz.py │ ├── test_context.py │ └── test_formatting.py ├── version.py ├── rounding_mode.py ├── ieee.py ├── formatting.py ├── __init__.py ├── mpfr_supplemental.py └── context.py ├── Misc ├── mpfr_notes.txt └── alg_notes.tex ├── cgmp.pxd ├── RELEASING.rst ├── INSTALL.rst ├── fabfile.py ├── examples ├── lanczos_coeffs.py └── contfrac.py ├── docs ├── Makefile └── source │ ├── index.rst │ ├── conf.py │ └── tutorial │ └── index.rst ├── README.rst ├── COPYING.LESSER ├── CHANGELOG.rst ├── setup.py └── cmpfr.pxd /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled files. 2 | __pycache__/ 3 | *.py[co] 4 | 5 | # Cython output. 6 | mpfr.c 7 | mpfr*.so 8 | 9 | # Build output (covers docs and extension build) 10 | build/ 11 | 12 | # Distribution 13 | MANIFEST 14 | dist/ 15 | bigfloat.egg-info/ 16 | 17 | # Coverage output. 18 | .coverage 19 | htmlcov -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | dist: bionic 3 | python: 4 | - 2.7 5 | - 3.5 6 | - 3.6 7 | - 3.7 8 | - 3.8 9 | install: 10 | - sudo apt-get update 11 | - sudo apt-get install libmpfr-dev 12 | - pip install Cython 13 | - pip install six 14 | script: 15 | - python setup.py build_ext --inplace 16 | - python -m unittest discover -v 17 | notifications: 18 | email: 19 | - dickinsm@gmail.com 20 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include CHANGELOG.rst 2 | include COPYING 3 | include COPYING.LESSER 4 | include INSTALL.rst 5 | include MANIFEST.in 6 | include README.rst 7 | 8 | # Distribution should include Cython source files, though the generated 9 | # C file is included, so neither Cython nor the Cython source is 10 | # necessary for installation. 11 | include cgmp.pxd 12 | include cmpfr.pxd 13 | include mpfr.pyx 14 | 15 | # Explicitly include the generated C source. 16 | include mpfr.c 17 | 18 | # Include docs and examples directories in their entirety. 19 | graft docs 20 | graft examples 21 | -------------------------------------------------------------------------------- /bigfloat/test/test___all__.py: -------------------------------------------------------------------------------- 1 | import collections 2 | import unittest 3 | 4 | 5 | class TestAll(unittest.TestCase): 6 | def test_from_import_star_on_bigfloat_package(self): 7 | exec("from bigfloat import *") 8 | 9 | def test_duplicates(self): 10 | # Check for duplicate entries in __all__. 11 | from bigfloat import __all__ 12 | 13 | counts = collections.defaultdict(int) 14 | for item in __all__: 15 | counts[item] += 1 16 | duplicates = sorted(k for k, v in counts.items() if v > 1) 17 | self.assertEqual(duplicates, []) 18 | 19 | 20 | if __name__ == "__main__": 21 | unittest.main() 22 | -------------------------------------------------------------------------------- /bigfloat/test/test_data/next_up.bft: -------------------------------------------------------------------------------- 1 | context double_precision 2 | 3 | next_up -inf -> -1.fffffffffffffp+1023 4 | next_up -1p-1074 -> -0 5 | next_up -0.8p-1075 -> -0 6 | next_up -0.4p-1075 -> -0 7 | next_up -0.000000000000000000000000001p-1075 -> -0 8 | next_up -1p-999999999 -> -0 9 | next_up -0 -> 1p-1074 10 | next_up 0 -> 1p-1074 11 | next_up 1p-999999999 -> 1p-1074 12 | next_up 0.8p-1074 -> 1p-1074 13 | next_up 0.ffffffffffffffffffffp-1074 -> 1p-1074 14 | next_up 1p-1074 -> 2p-1074 15 | next_up 1p-1023 -> 1.0000000000002p-1023 16 | next_up 1p-1022 -> 1.0000000000001p-1022 17 | next_up 1.ffffffffffffep+1023 -> 1.fffffffffffffp+1023 18 | next_up 1.ffffffffffffeffffp+1023 -> 1.fffffffffffffp+1023 19 | next_up 1.fffffffffffffp+1023 -> inf 20 | next_up inf -> inf 21 | 22 | next_up nan -> nan 23 | -------------------------------------------------------------------------------- /bigfloat/test/test_data/next_down.bft: -------------------------------------------------------------------------------- 1 | context double_precision 2 | 3 | next_down -inf -> -inf 4 | next_down -1.fffffffffffffp+1023 -> -inf 5 | next_down -1.ffffffffffffeffffp+1023 -> -1.fffffffffffffp+1023 6 | next_down -1.ffffffffffffep+1023 -> -1.fffffffffffffp+1023 7 | next_down -1p-1022 -> -1.0000000000001p-1022 8 | next_down -1p-1023 -> -1.0000000000002p-1023 9 | next_down -1p-1074 -> -2p-1074 10 | next_down -0.ffffffffffffffffffffp-1074 -> -1p-1074 11 | next_down -0.8p-1074 -> -1p-1074 12 | next_down -1p-999999999 -> -1p-1074 13 | next_down -0 -> -1p-1074 14 | next_down 0 -> -1p-1074 15 | next_down 1p-999999999 -> 0 16 | next_down 0.000000000000000000000000001p-1075 -> 0 17 | next_down 0.4p-1075 -> 0 18 | next_down 0.8p-1075 -> 0 19 | next_down 1p-1074 -> 0 20 | next_down inf -> 1.fffffffffffffp+1023 21 | 22 | next_down nan -> nan 23 | -------------------------------------------------------------------------------- /bigfloat/test/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2009--2019 Mark Dickinson. 2 | # 3 | # This file is part of the bigfloat package. 4 | # 5 | # The bigfloat package is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU Lesser General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or (at your 8 | # option) any later version. 9 | # 10 | # The bigfloat package is distributed in the hope that it will be useful, but 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 | # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License 13 | # for more details. 14 | # 15 | # You should have received a copy of the GNU Lesser General Public License 16 | # along with the bigfloat package. If not, see . 17 | -------------------------------------------------------------------------------- /bigfloat/version.py: -------------------------------------------------------------------------------- 1 | # Copyright 2009--2019 Mark Dickinson. 2 | # 3 | # This file is part of the bigfloat package. 4 | # 5 | # The bigfloat package is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU Lesser General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or (at your 8 | # option) any later version. 9 | # 10 | # The bigfloat package is distributed in the hope that it will be useful, but 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 | # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License 13 | # for more details. 14 | # 15 | # You should have received a copy of the GNU Lesser General Public License 16 | # along with the bigfloat package. If not, see . 17 | 18 | major = 0 19 | minor = 5 20 | patch = 0 21 | prerelease = "dev" 22 | 23 | if prerelease: 24 | __version__ = "{}.{}.{}-{}".format(major, minor, patch, prerelease) 25 | else: 26 | __version__ = "{}.{}.{}".format(major, minor, patch) 27 | 28 | # Release and version for Sphinx purposes. 29 | 30 | # The short X.Y version. 31 | version = "{}.{}".format(major, minor) 32 | 33 | # The full version, including patchlevel and alpha/beta/rc tags. 34 | release = __version__ 35 | -------------------------------------------------------------------------------- /Misc/mpfr_notes.txt: -------------------------------------------------------------------------------- 1 | Notes on using MPFR 2 | ------------------- 3 | 4 | 1. Should always have mpfr_emin <= mpfr_emax, else results may be undefined. 5 | 6 | For example, if mpfr_emin > mpfr_emax then the only representable 7 | values are zeros, infinities and nans. But then nextbelow(+Inf) should 8 | return 0.0. It doesn't (at least in MPFR 2.4.1.) 9 | 10 | Suggest adding a note to the docs saying that mpfr_emin <= mpfr_emax is 11 | required. 12 | 13 | 14 | 2. mpfr_set_ui_2exp doesn't check bounds on exponents; can induce 15 | undefined behaviour by taking exponent close to LONG_MAX. 16 | 17 | On my (32-bit) machine: 18 | 19 | mpfr_set_ui_2exp(x, 12345, LONG_MAX-10, RoundTiesToEven) gives 20 | 'Infinity' (correct), but a ternary value of 0 (incorrect); 21 | mpfr_set_ui_2exp(x, 12345, LONG_MAX-14, RoundTiesToEven) is okay. 22 | mpfr_set_ui_2exp(x, 12345, LONG_MAX-9, RoundTiesToEven) gives a result 23 | of 0 (bad) and ternary value of -1. 24 | 25 | (1st case gives the magic exponent corr. to infinity...) 26 | 27 | Should document a range of exponents for which mpfr_set_ui_2exp is 28 | guaranteed to work correcly. 29 | 30 | 3. mpfr_init_set, ... mpfr_init_set_f are macros. Please document this. 31 | (mpfr_init_set_str appears not to be a macro) 32 | XXX. It *is* documented! 33 | 34 | 4. Using set_emax and set_emin: the warning about making sure that all 35 | current variables are within the exponent bounds seems a little extreme ( 36 | and in practice, unusable), but it appears to be true that some functions 37 | and operations (e.g., addition) assume that arguments are within bounds. 38 | 39 | The way to get around this seems to be to do all computations with 40 | unbounded exponent range, and then just set emax and emin before doing 41 | check_range. 42 | -------------------------------------------------------------------------------- /cgmp.pxd: -------------------------------------------------------------------------------- 1 | # Copyright 2009--2019 Mark Dickinson. 2 | # 3 | # This file is part of the bigfloat package. 4 | # 5 | # The bigfloat package is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU Lesser General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or (at your 8 | # option) any later version. 9 | # 10 | # The bigfloat package is distributed in the hope that it will be useful, but 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 | # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License 13 | # for more details. 14 | # 15 | # You should have received a copy of the GNU Lesser General Public License 16 | # along with the bigfloat package. If not, see . 17 | 18 | cdef extern from "gmp.h": 19 | # GMP type declarations 20 | ctypedef int mp_exp_t 21 | ctypedef unsigned int mp_limb_t 22 | 23 | ctypedef struct __mpz_struct: 24 | int _mp_alloc 25 | int _mp_size 26 | mp_limb_t *_mp_d 27 | 28 | # ctypedef __mpz_struct mpz_t[1] 29 | ctypedef __mpz_struct *mpz_ptr 30 | 31 | # 5.1 Initialization Functions 32 | 33 | void mpz_init(mpz_ptr x) 34 | void mpz_clear(mpz_ptr x) 35 | 36 | # 5.2 Assignment Functions 37 | 38 | int mpz_set_str(mpz_ptr rop, const char *str, int base) 39 | 40 | # 5.4 Conversion Functions 41 | 42 | char *mpz_get_str(char *str, int base, const mpz_ptr op) 43 | 44 | # 13 Custom Allocation 45 | 46 | void mp_get_memory_functions( 47 | void *(**alloc_func_ptr) (size_t), 48 | void *(**realloc_func_ptr) (void *, size_t, size_t), 49 | void (**free_func_ptr) (void *, size_t)) 50 | -------------------------------------------------------------------------------- /RELEASING.rst: -------------------------------------------------------------------------------- 1 | Preparing a release 2 | =================== 3 | 4 | Notes on creating a release. These notes apply my own system, currently OS X 5 | 10.9, with mpfr and gmp installed via MacPorts. 6 | 7 | 0. Make sure that you have a clean and up-to-date source tree. 8 | 9 | 1. Create a release branch:: 10 | 11 | git checkout release/0.4.0 12 | 13 | 2. Update version numbers if necessary. Places that need to be updated 14 | include:: 15 | 16 | docs/conf.py ('version' and 'release' keys) 17 | setup.py ('version') 18 | 19 | You might also look at: 20 | 21 | * ``CHANGELOG.rst`` 22 | * ``INSTALL.rst`` 23 | * ``RELEASING.rst`` (this document). 24 | 25 | 3. Create a test release with ``python setup.py sdist``; copy the generated 26 | tarball and check that it's possible to install from it. Run tests. 27 | 28 | 4. When satisfied, tag the release:: 29 | 30 | git tag -a v0.4.0 31 | 32 | 5. Upload the release to PyPI. Register first if necessary:: 33 | 34 | python setup.py sdist upload 35 | 36 | If you don't have PyPI details registered in ~/.pypirc, this may fail; in 37 | that case you'll need to reissue the 'python setup.py sdist upload' command 38 | in the form:: 39 | 40 | python setup.py sdist register upload 41 | 42 | Make sure you answer "y" to the "Save your login (y/N)" prompt! 43 | 44 | 6. Update tags on ReadTheDocs. 45 | 46 | 7. Building docs to upload to PyPI. In the docs directory, do:: 47 | 48 | make html 49 | cd build/html 50 | zip -r bigfloat_docs.zip * 51 | mv -i bigfloat_docs.zip ~/Desktop 52 | 53 | Now you can go to:: 54 | 55 | http://pypi.python.org/pypi?%3Aaction=pkg_edit&name=bigfloat 56 | 57 | and upload the documentation from there. The documentation is uploaded 58 | to http://pythonhosted.org/bigfloat. 59 | 60 | 61 | Post-release 62 | ============ 63 | 64 | 0. Merge the release branch back into master. 65 | 66 | 1. Bump version number again. 67 | -------------------------------------------------------------------------------- /Misc/alg_notes.tex: -------------------------------------------------------------------------------- 1 | \documentclass{article} 2 | 3 | \usepackage{amsmath} 4 | \usepackage{amsthm} 5 | 6 | \newtheorem{lemma}{Lemma} 7 | \newtheorem{definition}{Definition} 8 | \newtheorem{examples}{Examples} 9 | \newcommand{\abs}[1]{|#1|} 10 | 11 | \begin{document} 12 | 13 | \begin{definition} 14 | For any positive real number~$x$, write $e(x)$ for the unique 15 | integer such that $2^{e(x)-1} \le x < 2^{e(x)}$. 16 | \end{definition} 17 | 18 | The following lemma is needed for implementing efficient floor division. 19 | 20 | \begin{lemma} 21 | Suppose that $x$, $y$ and $z$ are positive binary floating-point 22 | numbers with precisions~$p$, $q$ and $r$ respectively, and that $z 23 | \ne x/y$. Then 24 | $$\abs{z-x/y} \ge 2^{e(z) - \max(p+1,\,q+r)}$$ where $e(z)$ is the 25 | unique integer satisfying $2^{e(z)-1} \le z < 2^{e(z)}$. 26 | \end{lemma} 27 | 28 | \begin{proof} 29 | We divide the proof into two cases. For the first case, suppose 30 | that $e(x)-e(y) \ge e(z)-1$. Now 31 | $$z-x/y = (2^{r-e(z)}z)2^{e(z)-r} - \frac{2^{p-e(x)}x}{2^{q-e(y)}y} 32 | 2^{e(x)-e(y)-p+q}$$ and $2^{r-e(z)}z$, $2^{p-e(x)}x$ and 33 | $2^{q-e(y)}y$ are integers, so 34 | $$z-x/y = \left(\frac{2^{\min(e(z)-r,\, 35 | e(x)-e(y)-p+q)}}{2^{q-e(y)}y}\right)t$$ for some nonzero 36 | integer~$t$. Since $2^{-e(y)}y < 1$ by definition of $e(y)$, and 37 | $e(x)-e(y)\ge e(z)-1$ by assumption, the result follows. 38 | 39 | For the second case, suppose that $e(x) - e(y) \le e(z)-2$. 40 | Then 41 | \begin{align*} 42 | \frac xy&\le (1-2^{-p})2^{e(x)-e(y)+1}\\ 43 | &\le(1-2^{-p})2^{e(z)-1}\\ 44 | &< 2^{e(z)-1} \le z. 45 | \end{align*} 46 | and hence $z-x/y \ge 2^{e(z)-1-p}$. Hence we obtain the inequality 47 | of the theorem. We get equality if and only if $y$ and $z$ are 48 | exact powers of $2$, $x = (1-2^{-p})2^{e(x)}$, $e(x)-e(y) = e(z)-2$, 49 | and $p+1\ge q+r$. 50 | \end{proof} 51 | 52 | \begin{examples} 53 | Suppose that $y=z=1$, $x = 1-2^{-5}$. Then $e(z) = 1$, 54 | we can take $q=r=1$ and $p=5$, and the lemma predicts that $z-x/y \ge 55 | 2^{-5}$. 56 | 57 | Now suppose that 58 | 59 | \end{examples} 60 | 61 | \end{document} 62 | -------------------------------------------------------------------------------- /bigfloat/rounding_mode.py: -------------------------------------------------------------------------------- 1 | # Copyright 2009--2019 Mark Dickinson. 2 | # 3 | # This file is part of the bigfloat package. 4 | # 5 | # The bigfloat package is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU Lesser General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or (at your 8 | # option) any later version. 9 | # 10 | # The bigfloat package is distributed in the hope that it will be useful, but 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 | # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License 13 | # for more details. 14 | # 15 | # You should have received a copy of the GNU Lesser General Public License 16 | # along with the bigfloat package. If not, see . 17 | 18 | from mpfr import ( 19 | MPFR_RNDN, 20 | MPFR_RNDZ, 21 | MPFR_RNDU, 22 | MPFR_RNDD, 23 | MPFR_RNDA, 24 | ) 25 | 26 | 27 | __all__ = [ 28 | "RoundingMode", 29 | "ROUND_TIES_TO_EVEN", 30 | "ROUND_TOWARD_ZERO", 31 | "ROUND_TOWARD_POSITIVE", 32 | "ROUND_TOWARD_NEGATIVE", 33 | "ROUND_AWAY_FROM_ZERO", 34 | ] 35 | 36 | 37 | _rounding_mode_names = { 38 | MPFR_RNDN: "ROUND_TIES_TO_EVEN", 39 | MPFR_RNDZ: "ROUND_TOWARD_ZERO", 40 | MPFR_RNDU: "ROUND_TOWARD_POSITIVE", 41 | MPFR_RNDD: "ROUND_TOWARD_NEGATIVE", 42 | MPFR_RNDA: "ROUND_AWAY_FROM_ZERO", 43 | } 44 | 45 | 46 | class RoundingMode(int): 47 | """ Subclass of int representing a rounding mode. """ 48 | 49 | def __new__(cls, value): 50 | self = int.__new__(cls, value) 51 | if value not in _rounding_mode_names: 52 | raise ValueError("Invalid rounding mode {}".format(value)) 53 | self._name = _rounding_mode_names[value] 54 | return self 55 | 56 | def __repr__(self): 57 | return self._name 58 | 59 | __str__ = __repr__ 60 | 61 | 62 | ROUND_TIES_TO_EVEN = RoundingMode(MPFR_RNDN) 63 | ROUND_TOWARD_ZERO = RoundingMode(MPFR_RNDZ) 64 | ROUND_TOWARD_POSITIVE = RoundingMode(MPFR_RNDU) 65 | ROUND_TOWARD_NEGATIVE = RoundingMode(MPFR_RNDD) 66 | ROUND_AWAY_FROM_ZERO = RoundingMode(MPFR_RNDA) 67 | -------------------------------------------------------------------------------- /INSTALL.rst: -------------------------------------------------------------------------------- 1 | Prerequisites 2 | ------------- 3 | 4 | This package requires Python 2.7 or 3.5 or later. The `MPFR `_ 5 | and `GMP `_ libraries will need to be already installed on your 6 | system, along with any necessary development headers for both of those 7 | libraries. On Linux, look for a package named something like ``libmpfr-dev`` 8 | or ``mpfr-devel``, along with similarly named packages for GMP. 9 | 10 | 11 | Installation from a release tarball 12 | ----------------------------------- 13 | 14 | The instructions cover installation from either a repository clone, 15 | or a source distribution tarball. After cloning the repository 16 | or unpacking the tarball, you should have a top-level directory 17 | named something like ``bigfloat-0.4.0``. 18 | 19 | (1) Enter that top-level directory and execute the command:: 20 | 21 | python setup.py install 22 | 23 | For a site-wide installation, you many need to be become superuser, or use 24 | the ``sudo`` command. You can also build and install in two separate 25 | steps:: 26 | 27 | python setup.py build_ext 28 | sudo python setup.py install 29 | 30 | For this to work, the MPFR and GMP libraries must already be installed 31 | on your system, complete with any necessary header files. If the libraries 32 | or include files are found in an unusual place, you many need to modify 33 | environment variables so that the setup command can find the necessary 34 | header files. 35 | 36 | An example: on OS X 10.9, using the system Python but with MPFR and GMP 37 | installed in /opt/local (e.g., by MacPorts), one can do:: 38 | 39 | $ sudo LIBRARY_PATH=/opt/local/lib CPATH=/opt/local/include python setup.py install 40 | 41 | Alternatively, the include and library directories can be supplied to the 42 | build_ext command:: 43 | 44 | $ python setup.py build_ext -I /opt/local/include -L/opt/local/lib 45 | $ sudo python setup.py install 46 | 47 | (2) (Optional) Test the installation by doing:: 48 | 49 | $ python -m unittest discover bigfloat 50 | 51 | (3) To check that everything's working, compute the square root of 2 to 1000 52 | bits of precision:: 53 | 54 | >>> from bigfloat import precision, sqrt 55 | >>> with precision(200): 56 | ... print(sqrt(2)) 57 | ... 58 | 1.4142135623730950488016887242096980785696718753769480731766796 59 | 60 | If installation was successful, the ``bigfloat-0.4.0`` directory that you 61 | created can now be deleted. 62 | 63 | 64 | .. _gmp library: http://gmplib.org 65 | .. _mpfr library: http://www.mpfr.org 66 | -------------------------------------------------------------------------------- /bigfloat/ieee.py: -------------------------------------------------------------------------------- 1 | # Copyright 2009--2019 Mark Dickinson. 2 | # 3 | # This file is part of the bigfloat package. 4 | # 5 | # The bigfloat package is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU Lesser General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or (at your 8 | # option) any later version. 9 | # 10 | # The bigfloat package is distributed in the hope that it will be useful, but 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 | # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License 13 | # for more details. 14 | # 15 | # You should have received a copy of the GNU Lesser General Public License 16 | # along with the bigfloat package. If not, see . 17 | 18 | from bigfloat.core import _bit_length 19 | from bigfloat.context import Context 20 | 21 | 22 | def IEEEContext(bitwidth): 23 | """ 24 | Return IEEE 754-2008 context for a given bit width. 25 | 26 | The IEEE 754 standard specifies binary interchange formats with bitwidths 27 | 16, 32, 64, 128, and all multiples of 32 greater than 128. This function 28 | returns the context corresponding to the interchange format for the given 29 | bitwidth. 30 | 31 | See section 3.6 of IEEE 754-2008 or the bigfloat source for more details. 32 | 33 | """ 34 | try: 35 | precision = {16: 11, 32: 24, 64: 53, 128: 113}[bitwidth] 36 | except KeyError: 37 | if not (bitwidth >= 128 and bitwidth % 32 == 0): 38 | raise ValueError( 39 | "nonstandard bitwidth: bitwidth should be " 40 | "16, 32, 64, 128, or k*32 for some k >= 4" 41 | ) 42 | # The formula for the precision involves rounding 4*log2(width) to the 43 | # nearest integer. We have: 44 | # 45 | # round(4*log2(width)) == round(log2(width**8)/2) 46 | # == floor((log2(width**8) + 1)/2) 47 | # == (width**8).bit_length() // 2 48 | # 49 | # (Note that 8*log2(width) can never be an odd integer, so we 50 | # don't care which way half-way cases round in the 'round' 51 | # operation.) 52 | precision = bitwidth - _bit_length(bitwidth ** 8) // 2 + 13 53 | 54 | emax = 1 << bitwidth - precision - 1 55 | return Context( 56 | precision=precision, 57 | emin=4 - emax - precision, 58 | emax=emax, 59 | subnormalize=True, 60 | ) 61 | 62 | 63 | half_precision = IEEEContext(16) 64 | single_precision = IEEEContext(32) 65 | double_precision = IEEEContext(64) 66 | quadruple_precision = IEEEContext(128) 67 | -------------------------------------------------------------------------------- /fabfile.py: -------------------------------------------------------------------------------- 1 | from fabric.api import local, lcd 2 | 3 | # Default choice for Python executable 4 | PYTHON = "python" 5 | COVERAGE = "coverage" 6 | 7 | # Paths for mpfr and gmp libraries and include files. 8 | LIBRARY_PATH = "/opt/local/lib" 9 | INCLUDE_PATH = "/opt/local/include" 10 | 11 | 12 | def build(python=PYTHON): 13 | """Build the bigfloat library for in-place testing.""" 14 | clean() 15 | local( 16 | "LIBRARY_PATH={library_path} CPATH={include_path} {python} " 17 | "setup.py build_ext --inplace".format( 18 | library_path=LIBRARY_PATH, 19 | include_path=INCLUDE_PATH, 20 | python=python, 21 | ) 22 | ) 23 | 24 | 25 | def install(python=PYTHON): 26 | """Install into site-packages""" 27 | local( 28 | "LIBRARY_PATH={library_path} CPATH={include_path} {python} " 29 | "setup.py build".format( 30 | library_path=LIBRARY_PATH, 31 | include_path=INCLUDE_PATH, 32 | python=python, 33 | ) 34 | ) 35 | local("sudo {python} setup.py install".format(python=python)) 36 | 37 | 38 | def uninstall(python=PYTHON): 39 | """Uninstall from site-packages""" 40 | site_packages = local( 41 | "{python} -c 'from distutils.sysconfig import " 42 | "get_python_lib; print(get_python_lib())'".format(python=python), 43 | capture=True, 44 | ) 45 | with lcd(site_packages): 46 | local("sudo rm mpfr.so") 47 | local("sudo rm -fr bigfloat") 48 | local("sudo rm bigfloat*.egg-info") 49 | 50 | 51 | def clean(): 52 | """Remove build artifacts.""" 53 | local("git clean -fdX") 54 | 55 | 56 | def run_tests(python=PYTHON): 57 | unittest = "{python} -m unittest".format(python=python) 58 | local("{unittest} discover -v .".format(unittest=unittest)) 59 | 60 | 61 | def test(python=PYTHON): 62 | """Run tests on a single version of Python.""" 63 | build(python=python) 64 | run_tests(python=python) 65 | 66 | 67 | def coverage(coverage=COVERAGE): 68 | local("{coverage} run -m unittest discover -v .".format(coverage=coverage)) 69 | local("{coverage} html".format(coverage=coverage)) 70 | 71 | 72 | def html(): 73 | """Build html documentation.""" 74 | clean() 75 | with lcd("docs"): 76 | local("make html") 77 | 78 | 79 | def pdf(): 80 | """Build PDF documentation.""" 81 | clean() 82 | with lcd("docs"): 83 | local("make latexpdf") 84 | 85 | 86 | def docs(python=PYTHON): 87 | """Build PDF and html documentation.""" 88 | html() 89 | pdf() 90 | 91 | 92 | def test_all(): 93 | """Run tests on Python versions 2.7 and 3.5 through 3.8.""" 94 | test(python="python2.7") 95 | test(python="python3.5") 96 | test(python="python3.6") 97 | test(python="python3.7") 98 | test(python="python3.8") 99 | -------------------------------------------------------------------------------- /bigfloat/test/test_data/mod.bft: -------------------------------------------------------------------------------- 1 | context double_precision 2 | context RoundTiesToEven 3 | 4 | # Check treatment of signs in normal cases. 5 | mod 0x5p0 0x3p0 -> 0x2p0 6 | mod -0x5p0 0x3p0 -> 0x1p0 7 | mod 0x5p0 -0x3p0 -> -0x1p0 8 | mod -0x5p0 -0x3p0 -> -0x2p0 9 | 10 | # A result of zero should have the same sign 11 | # as the second argument. 12 | mod 0x2p0 0x1p0 -> 0x0p0 13 | mod -0x2p0 0x1p0 -> 0x0p0 14 | mod 0x2p0 -0x1p0 -> -0x0p0 15 | mod -0x2p0 -0x1p0 -> -0x0p0 16 | 17 | # Finite input cases where the result may not be exact. 18 | mod 0x1p-100 0x1p0 -> 0x1p-100 19 | mod -0x1p-100 0x1p0 -> 0x1p0 Inexact 20 | mod 0x1p-100 -0x1p0 -> -0x1p0 Inexact 21 | mod -0x1p-100 -0x1p0 -> -0x1p-100 22 | 23 | # NaN inputs 24 | mod nan nan -> nan NanFlag 25 | mod -inf nan -> nan NanFlag 26 | mod -0x1p0 nan -> nan NanFlag 27 | mod -0x0p0 nan -> nan NanFlag 28 | mod 0x0p0 nan -> nan NanFlag 29 | mod 0x1p0 nan -> nan NanFlag 30 | mod nan inf -> nan NanFlag 31 | mod nan -inf -> nan NanFlag 32 | mod nan -0x1p0 -> nan NanFlag 33 | mod nan -0x0p0 -> nan NanFlag 34 | mod nan 0x0p0 -> nan NanFlag 35 | mod nan 0x1p0 -> nan NanFlag 36 | mod nan inf -> nan NanFlag 37 | 38 | # Other invalid cases: x infinite, y zero. 39 | mod inf -inf -> nan NanFlag 40 | mod inf -0x1p0 -> nan NanFlag 41 | mod inf -0x0p0 -> nan NanFlag 42 | mod inf 0x0p0 -> nan NanFlag 43 | mod inf 0x1p0 -> nan NanFlag 44 | mod inf inf -> nan NanFlag 45 | mod -inf -inf -> nan NanFlag 46 | mod -inf -0x1p0 -> nan NanFlag 47 | mod -inf -0x0p0 -> nan NanFlag 48 | mod -inf 0x0p0 -> nan NanFlag 49 | mod -inf 0x1p0 -> nan NanFlag 50 | mod -inf inf -> nan NanFlag 51 | mod -inf 0x0p0 -> nan NanFlag 52 | mod -0x1p0 0x0p0 -> nan NanFlag 53 | mod -0x0p0 0x0p0 -> nan NanFlag 54 | mod 0x0p0 0x0p0 -> nan NanFlag 55 | mod 0x1p0 0x0p0 -> nan NanFlag 56 | mod inf 0x0p0 -> nan NanFlag 57 | mod -inf -0x0p0 -> nan NanFlag 58 | mod -0x1p0 -0x0p0 -> nan NanFlag 59 | mod -0x0p0 -0x0p0 -> nan NanFlag 60 | mod 0x0p0 -0x0p0 -> nan NanFlag 61 | mod 0x1p0 -0x0p0 -> nan NanFlag 62 | mod inf -0x0p0 -> nan NanFlag 63 | 64 | # x finite, y infinite. 65 | mod -0x1p0 inf -> inf 66 | mod -0x0p0 inf -> 0x0p0 67 | mod 0x0p0 inf -> 0x0p0 68 | mod 0x1p0 inf -> 0x1p0 69 | 70 | mod -0x1p0 -inf -> -0x1p0 71 | mod -0x0p0 -inf -> -0x0p0 72 | mod 0x0p0 -inf -> -0x0p0 73 | mod 0x1p0 -inf -> -inf 74 | 75 | # x zero, y finite but nonzero: sign of x is irrelevant. 76 | mod 0x0p0 0x5p0 -> 0x0p0 77 | mod -0x0p0 0x5p0 -> 0x0p0 78 | mod 0x0p0 -0x5p0 -> -0x0p0 79 | mod -0x0p0 -0x5p0 -> -0x0p0 80 | -------------------------------------------------------------------------------- /bigfloat/test/test_rounding_mode.py: -------------------------------------------------------------------------------- 1 | # Copyright 2009--2019 Mark Dickinson. 2 | # 3 | # This file is part of the bigfloat package. 4 | # 5 | # The bigfloat package is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU Lesser General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or (at your 8 | # option) any later version. 9 | # 10 | # The bigfloat package is distributed in the hope that it will be useful, but 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 | # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License 13 | # for more details. 14 | # 15 | # You should have received a copy of the GNU Lesser General Public License 16 | # along with the bigfloat package. If not, see . 17 | 18 | import unittest 19 | 20 | import mpfr as mpfr 21 | from bigfloat.rounding_mode import ( 22 | RoundingMode, 23 | ROUND_TIES_TO_EVEN, 24 | ROUND_TOWARD_ZERO, 25 | ROUND_TOWARD_POSITIVE, 26 | ROUND_TOWARD_NEGATIVE, 27 | ROUND_AWAY_FROM_ZERO, 28 | ) 29 | 30 | 31 | class TestRoundingMode(unittest.TestCase): 32 | def test_rounding_mode_from_int(self): 33 | rm = RoundingMode(mpfr.MPFR_RNDN) 34 | self.assertEqual(rm, ROUND_TIES_TO_EVEN) 35 | self.assertIsInstance(rm, RoundingMode) 36 | 37 | def test_rounding_mode_from_rounding_mode(self): 38 | rm = RoundingMode(ROUND_TOWARD_POSITIVE) 39 | self.assertEqual(rm, ROUND_TOWARD_POSITIVE) 40 | self.assertIsInstance(rm, RoundingMode) 41 | 42 | def test_str(self): 43 | self.assertEqual(str(ROUND_TIES_TO_EVEN), "ROUND_TIES_TO_EVEN") 44 | self.assertEqual(str(ROUND_TOWARD_ZERO), "ROUND_TOWARD_ZERO") 45 | self.assertEqual(str(ROUND_TOWARD_POSITIVE), "ROUND_TOWARD_POSITIVE") 46 | self.assertEqual(str(ROUND_TOWARD_NEGATIVE), "ROUND_TOWARD_NEGATIVE") 47 | self.assertEqual(str(ROUND_AWAY_FROM_ZERO), "ROUND_AWAY_FROM_ZERO") 48 | 49 | def test_repr(self): 50 | self.assertEqual(repr(ROUND_TIES_TO_EVEN), "ROUND_TIES_TO_EVEN") 51 | self.assertEqual(repr(ROUND_TOWARD_ZERO), "ROUND_TOWARD_ZERO") 52 | self.assertEqual(repr(ROUND_TOWARD_POSITIVE), "ROUND_TOWARD_POSITIVE") 53 | self.assertEqual(repr(ROUND_TOWARD_NEGATIVE), "ROUND_TOWARD_NEGATIVE") 54 | self.assertEqual(repr(ROUND_AWAY_FROM_ZERO), "ROUND_AWAY_FROM_ZERO") 55 | 56 | def test_int(self): 57 | self.assertEqual(int(ROUND_TIES_TO_EVEN), mpfr.MPFR_RNDN) 58 | self.assertEqual(int(ROUND_TOWARD_ZERO), mpfr.MPFR_RNDZ) 59 | self.assertEqual(int(ROUND_TOWARD_POSITIVE), mpfr.MPFR_RNDU) 60 | self.assertEqual(int(ROUND_TOWARD_NEGATIVE), mpfr.MPFR_RNDD) 61 | self.assertEqual(int(ROUND_AWAY_FROM_ZERO), mpfr.MPFR_RNDA) 62 | 63 | def test_type(self): 64 | self.assertTrue(issubclass(RoundingMode, int)) 65 | self.assertIs(type(ROUND_TIES_TO_EVEN), RoundingMode) 66 | self.assertIs(type(ROUND_TOWARD_ZERO), RoundingMode) 67 | self.assertIs(type(ROUND_TOWARD_POSITIVE), RoundingMode) 68 | self.assertIs(type(ROUND_TOWARD_NEGATIVE), RoundingMode) 69 | self.assertIs(type(ROUND_AWAY_FROM_ZERO), RoundingMode) 70 | 71 | def test_invalid_rounding_mode(self): 72 | with self.assertRaises(ValueError): 73 | RoundingMode(-1) 74 | 75 | 76 | if __name__ == "__main__": 77 | unittest.main() 78 | -------------------------------------------------------------------------------- /bigfloat/test/test_mpz.py: -------------------------------------------------------------------------------- 1 | # Copyright 2009--2019 Mark Dickinson. 2 | # 3 | # This file is part of the bigfloat package. 4 | # 5 | # The bigfloat package is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU Lesser General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or (at your 8 | # option) any later version. 9 | # 10 | # The bigfloat package is distributed in the hope that it will be useful, but 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 | # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License 13 | # for more details. 14 | # 15 | # You should have received a copy of the GNU Lesser General Public License 16 | # along with the bigfloat package. If not, see . 17 | 18 | import unittest 19 | 20 | from mpfr import ( 21 | Mpz_t, 22 | mpz_set_str, 23 | mpz_get_str, 24 | ) 25 | 26 | 27 | class TestMpz(unittest.TestCase): 28 | def test_mpz_initial_value(self): 29 | z = Mpz_t() 30 | self.assertEqual(mpz_get_str(10, z), "0") 31 | 32 | def test_set_and_get_str(self): 33 | z = Mpz_t() 34 | mpz_set_str(z, "123", 10) 35 | self.assertEqual(mpz_get_str(10, z), "123") 36 | 37 | def test_set_str_base(self): 38 | z = Mpz_t() 39 | 40 | # Triples (str, base, value) 41 | test_values = [ 42 | ("1001", 2, 9), 43 | ("1001", 3, 28), 44 | ("123", 10, 123), 45 | ("-123", 10, -123), 46 | ("abc", 16, 2748), 47 | ("ABC", 16, 2748), 48 | ("A", 37, 10), 49 | ("a", 37, 36), 50 | ("z", 62, 61), 51 | ("Z", 62, 35), 52 | ("11", 0, 11), 53 | ("011", 0, 9), 54 | ("0x12", 0, 18), 55 | ("-0x12", 0, -18), 56 | ("0X012", 0, 18), 57 | ("0B00101", 0, 5), 58 | ("-1 2 3 4 5 6", 0, -123456), 59 | ("\n3\t45\n6\n\n\n7\t\n", 0, 34567), 60 | ] 61 | 62 | for s, base, expected in test_values: 63 | mpz_set_str(z, s, base) 64 | actual = int(mpz_get_str(10, z)) 65 | self.assertEqual(actual, expected) 66 | 67 | bad_bases = [-2, 1, 63] 68 | for base in bad_bases: 69 | with self.assertRaises(ValueError): 70 | mpz_set_str(z, "101", base) 71 | 72 | def test_set_str_bad_values(self): 73 | z = Mpz_t() 74 | 75 | bad_values = [ 76 | ("123\nabc", 10), 77 | ("12", 2), 78 | ] 79 | 80 | for value, base in bad_values: 81 | mpz_set_str(z, str(-314159), 10) 82 | with self.assertRaises(ValueError): 83 | mpz_set_str(z, value, base) 84 | self.assertEqual(int(mpz_get_str(10, z)), -314159) 85 | 86 | def test_get_str(self): 87 | z = Mpz_t() 88 | 89 | # Triples (value, base, expected_output) 90 | test_values = [ 91 | (456, 2, "111001000"), 92 | (456, 10, "456"), 93 | (456, 16, "1c8"), 94 | (456, 36, "co"), 95 | (456, 37, "CC"), 96 | (456, -2, "111001000"), 97 | (456, -16, "1C8"), 98 | (456, -36, "CO"), 99 | ] 100 | 101 | for value, base, expected in test_values: 102 | mpz_set_str(z, str(value), 10) 103 | actual = mpz_get_str(base, z) 104 | self.assertEqual(actual, expected) 105 | 106 | bad_bases = [-37, -1, 0, 1, 63] 107 | 108 | for base in bad_bases: 109 | with self.assertRaises(ValueError): 110 | mpz_get_str(base, z) 111 | -------------------------------------------------------------------------------- /bigfloat/test/test_data/pos.bft: -------------------------------------------------------------------------------- 1 | context double_precision 2 | context RoundTiesToEven 3 | 4 | pos 0 -> 0 5 | pos -0 -> -0 6 | pos inf -> inf 7 | pos -inf -> -inf 8 | pos nan -> nan NanFlag 9 | 10 | # smallest representable positive value is 1p-1074 11 | # values in (0, 0.8p-1074] -> 0 Inexact Underflow 12 | 13 | # exactly representable with precision 53 and unbounded exponent, 14 | # but not exactly representable with precision 53 and bounded exponent 15 | pos 0.8p-1075 -> 0 Inexact Underflow 16 | pos 0.cp-1075 -> 0 Inexact Underflow 17 | pos 0.ffffffffffffp-1075 -> 0 Inexact Underflow 18 | 19 | # not exactly representable with precision 53 and unbounded exponent 20 | pos 0.ffffffffffffffffffffp-1075 -> 0 Inexact Underflow 21 | pos 1p-1075 -> 0 Inexact Underflow 22 | 23 | # values in (0.8p-1075, 1p-1074) -> 1p-1074 Inexact Underflow 24 | 25 | pos 1.00000000000000000001p-1075 -> 1p-1074 Inexact Underflow 26 | pos 1.000000001p-1075 -> 1p-1074 Inexact Underflow 27 | pos 1.8p-1075 -> 1p-1074 Inexact Underflow 28 | pos 0.ffffffffffff8p-1074 -> 1p-1074 Inexact Underflow 29 | pos 0.ffffffffffffffffffffp-1074 -> 1p-1074 Inexact Underflow 30 | 31 | # 1p-1074 exactly representable 32 | pos 1p-1074 -> 1p-1074 Underflow 33 | 34 | # values in (1p-1074, 1.8p-1074) -> 1p-1074 Inexact Underflow 35 | pos 1.7p-1074 -> 1p-1074 Inexact Underflow 36 | pos 1.7ffffffffffffp-1074 -> 1p-1074 Inexact Underflow 37 | pos 1.7ffffffffffff8p-1074 -> 1p-1074 Inexact Underflow 38 | 39 | # values in [1.8p-1074, 2p-1074) -> 2p-1074 Inexact Underflow 40 | pos 1.8p-1074 -> 2p-1074 Inexact Underflow 41 | pos 1.80000000000008p-1074 -> 2p-1074 Inexact Underflow 42 | pos 1.8000000000001p-1074 -> 2p-1074 Inexact Underflow 43 | pos 2p-1074 -> 2p-1074 Underflow 44 | 45 | # test round-half-to-even at some mid-range subnormal values 46 | pos 123456p-1074 -> 123456p-1074 Underflow 47 | pos 123456.7p-1074 -> 123456p-1074 Inexact Underflow 48 | pos 123456.7ffffffffffffp-1074 -> 123456p-1074 Inexact Underflow 49 | pos 123456.8p-1074 -> 123456p-1074 Inexact Underflow 50 | pos 123456.8000000000001p-1074 -> 123457p-1074 Inexact Underflow 51 | pos 123456.9p-1074 -> 123457p-1074 Inexact Underflow 52 | pos 123456.ap-1074 -> 123457p-1074 Inexact Underflow 53 | pos 123456.bp-1074 -> 123457p-1074 Inexact Underflow 54 | pos 123456.cp-1074 -> 123457p-1074 Inexact Underflow 55 | pos 123456.dp-1074 -> 123457p-1074 Inexact Underflow 56 | pos 123456.ep-1074 -> 123457p-1074 Inexact Underflow 57 | pos 123456.fp-1074 -> 123457p-1074 Inexact Underflow 58 | pos 123457.0p-1074 -> 123457p-1074 Underflow 59 | pos 123457.1p-1074 -> 123457p-1074 Inexact Underflow 60 | pos 123457.2p-1074 -> 123457p-1074 Inexact Underflow 61 | pos 123457.3p-1074 -> 123457p-1074 Inexact Underflow 62 | pos 123457.4p-1074 -> 123457p-1074 Inexact Underflow 63 | pos 123457.5p-1074 -> 123457p-1074 Inexact Underflow 64 | pos 123457.6p-1074 -> 123457p-1074 Inexact Underflow 65 | pos 123457.7p-1074 -> 123457p-1074 Inexact Underflow 66 | pos 123457.7fffffffp-1074 -> 123457p-1074 Inexact Underflow 67 | pos 123457.7fffffff8p-1074 -> 123457p-1074 Inexact Underflow 68 | pos 123457.8p-1074 -> 123458p-1074 Inexact Underflow 69 | pos 123457.800000008p-1074 -> 123458p-1074 Inexact Underflow 70 | pos 123457.80000001p-1074 -> 123458p-1074 Inexact Underflow 71 | pos 123457.9p-1074 -> 123458p-1074 Inexact Underflow 72 | 73 | # values near smallest representable normal value, 1p-1022 74 | pos 0.8p-1022 -> 0.8p-1022 Underflow 75 | 76 | # write e for 2**-53, t for 1p-1022, then: 77 | # 78 | # (1-2e)t -> Underflow # exactly representable 79 | # ((1-2e)t, (1-e)t) -> (1-2e)t Inexact Underflow 80 | # [(1-e)t, (1-e/2)t) -> t Inexact Underflow 81 | # [(1-e/2)t, t) -> t Inexact # no underflow! after rounding at work 82 | 83 | pos 0.fffffffffffffp-1022 -> 0.fffffffffffffp-1022 Underflow 84 | pos 0.fffffffffffff00000000001p-1022 -> 0.fffffffffffffp-1022 Inexact Underflow 85 | pos 0.fffffffffffff4p-1022 -> 0.fffffffffffffp-1022 Inexact Underflow 86 | pos 0.fffffffffffff7ffffffffffp-1022 -> 0.fffffffffffffp-1022 Inexact Underflow 87 | pos 0.fffffffffffff8p-1022 -> 1p-1022 Inexact Underflow 88 | pos 0.fffffffffffffbffffffffffp-1022 -> 1p-1022 Inexact Underflow 89 | pos 0.fffffffffffffcp-1022 -> 1p-1022 Inexact 90 | pos 0.ffffffffffffffffffffffffp-1022 -> 1p-1022 Inexact 91 | pos 1p-1022 -> 1p-1022 92 | pos 1p+1024 -> inf Inexact Overflow 93 | -------------------------------------------------------------------------------- /bigfloat/formatting.py: -------------------------------------------------------------------------------- 1 | # Copyright 2009--2019 Mark Dickinson. 2 | # 3 | # This file is part of the bigfloat package. 4 | # 5 | # The bigfloat package is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU Lesser General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or (at your 8 | # option) any later version. 9 | # 10 | # The bigfloat package is distributed in the hope that it will be useful, but 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 | # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License 13 | # for more details. 14 | # 15 | # You should have received a copy of the GNU Lesser General Public License 16 | # along with the bigfloat package. If not, see . 17 | """ 18 | Helper functions for formatting. 19 | 20 | """ 21 | import re 22 | 23 | from bigfloat.rounding_mode import ( 24 | ROUND_TIES_TO_EVEN, 25 | ROUND_TOWARD_ZERO, 26 | ROUND_TOWARD_POSITIVE, 27 | ROUND_TOWARD_NEGATIVE, 28 | ROUND_AWAY_FROM_ZERO, 29 | ) 30 | 31 | # Regular expression matching valid format specifiers. 32 | _parse_format_specifier_regex = re.compile( 33 | r"""\A 34 | (?: 35 | (?P.)? 36 | (?P[<>=^]) 37 | )? 38 | (?P[-+ ])? 39 | (?P\#)? 40 | (?P0)? 41 | (?P[0-9]*) 42 | (?P\.[0-9]+)? 43 | (?P[UDYZN])? 44 | (?P[aAbeEfFgG%])? 45 | \Z""", 46 | re.VERBOSE | re.DOTALL, 47 | ) 48 | 49 | 50 | rounding_mode_from_specifier = { 51 | "U": ROUND_TOWARD_POSITIVE, 52 | "D": ROUND_TOWARD_NEGATIVE, 53 | "Y": ROUND_AWAY_FROM_ZERO, 54 | "Z": ROUND_TOWARD_ZERO, 55 | "N": ROUND_TIES_TO_EVEN, 56 | } 57 | 58 | 59 | def parse_format_specifier(specification): 60 | """ 61 | Parse the given format specification and return a dictionary 62 | containing relevant values. 63 | 64 | """ 65 | m = _parse_format_specifier_regex.match(specification) 66 | if m is None: 67 | raise ValueError( 68 | "Invalid format specifier: {!r}".format(specification) 69 | ) 70 | format_dict = m.groupdict("") 71 | 72 | # Convert zero-padding into fill and alignment. 73 | zeropad = format_dict.pop("zeropad") 74 | if zeropad: 75 | # If zero padding is requested, fill and align fields should be absent. 76 | if format_dict["align"]: 77 | raise ValueError( 78 | "Invalid format specifier: {!r}".format(specification) 79 | ) 80 | # Impossible to have 'fill' without 'align'. 81 | assert not format_dict["fill"] 82 | format_dict["align"] = "=" 83 | format_dict["fill"] = "0" 84 | 85 | # Default alignment is right-aligned. 86 | if not format_dict["align"]: 87 | format_dict["align"] = ">" 88 | 89 | # Default fill character is space. 90 | if not format_dict["fill"]: 91 | format_dict["fill"] = " " 92 | 93 | # Default sign is '-'. 94 | if not format_dict["sign"]: 95 | format_dict["sign"] = "-" 96 | 97 | # Convert minimum width to an int; default is zero. 98 | format_dict["minimumwidth"] = int(format_dict["minimumwidth"] or "0") 99 | 100 | # Convert precision to an int, or `None` if no precision given. 101 | if format_dict["precision"]: 102 | format_dict["precision"] = int(format_dict["precision"][1:]) 103 | else: 104 | format_dict["precision"] = None 105 | 106 | # If no rounding mode is given, assume 'N'. 107 | if not format_dict["rounding"]: 108 | format_dict["rounding"] = "N" 109 | 110 | return format_dict 111 | 112 | 113 | def format_align(sign, body, spec): 114 | """Given an unpadded, non-aligned numeric string 'body' and sign 115 | string 'sign', add padding and alignment conforming to the given 116 | format specifier dictionary 'spec' (as produced by 117 | parse_format_specifier). 118 | 119 | """ 120 | padding = spec["fill"] * (spec["minimumwidth"] - len(sign) - len(body)) 121 | align = spec["align"] 122 | if align == "<": 123 | result = sign + body + padding 124 | elif align == ">": 125 | result = padding + sign + body 126 | elif align == "=": 127 | result = sign + padding + body 128 | elif align == "^": 129 | half = len(padding) // 2 130 | result = padding[:half] + sign + body + padding[half:] 131 | else: 132 | raise ValueError("Unrecognised alignment field: {!r}".format(align)) 133 | 134 | return result 135 | -------------------------------------------------------------------------------- /bigfloat/test/test_data/various.bft: -------------------------------------------------------------------------------- 1 | # The following tests are not supposed to be exhaustive tests of the behaviour 2 | # of the individual functions; that job is left to the MPFR test suite. 3 | # Instead, they're supposed to exercise the functions to catch simple errors 4 | # like mismatches in wrapping. So we only need to check one or two 5 | # characteristic values per function. The test values below were computed 6 | # using independent sources (mainly Pari/GP). 7 | 8 | context double_precision 9 | context RoundTiesToEven 10 | 11 | # Powers. 12 | sqr 1.8p0 -> 2.4p0 13 | rec_sqrt 2.4p0 -> 0.aaaaaaaaaaaaa8p0 Inexact 14 | cbrt 2p0 -> 1.428a2f98d728bp+0 Inexact 15 | 16 | # Log and exponential functions. 17 | log 2p0 -> 1.62e42fefa39efp-1 Inexact 18 | log2 2.8p0 -> 1.5269e12f346e3p+0 Inexact 19 | log10 1p4 -> 1.34413509f79ffp+0 Inexact 20 | log1p 0.8p0 -> 1.9f323ecbf984cp-2 Inexact 21 | 22 | exp 1p-2 -> 1.48b5e3c3e8186p+0 Inexact 23 | exp2 1p-2 -> 1.306fe0a31b715p+0 Inexact 24 | exp10 1p-2 -> 1.c73d51c54470ep+0 Inexact 25 | expm1 0.8p0 -> 1.4c2531c3c0d38p-1 Inexact 26 | 27 | # Trigonometric functions and their inverses. 28 | cos 2p0 -> -1.aa22657537205p-2 Inexact 29 | sin 2p0 -> 1.d18f6ead1b446p-1 Inexact 30 | tan 2p0 -> -1.17af62e0950f8p+1 Inexact 31 | sec 2p0 -> -1.33956fecf9e48p+1 Inexact 32 | csc 2p0 -> 1.19893a272f912p+0 Inexact 33 | cot 2p0 -> -1.d4a42e92faa4ep-2 Inexact 34 | 35 | acos 0.8p0 -> 1.0c152382d7366p+0 Inexact 36 | asin 0.8p0 -> 1.0c152382d7366p-1 Inexact 37 | atan 0.8p0 -> 1.dac670561bb4fp-2 Inexact 38 | 39 | # Hyperbolic trigonometric functions and their inverses. 40 | cosh 0.8p0 -> 1.20ac1862ae8d0p+0 Inexact 41 | sinh 0.8p0 -> 1.0acd00fe63b97p-1 Inexact 42 | tanh 0.8p0 -> 1.d9353d7568af3p-2 Inexact 43 | sech 0.8p0 -> 1.c60d1ff040dd0p-1 Inexact 44 | csch 0.8p0 -> 1.eb45dc88defedp+0 Inexact 45 | coth 0.8p0 -> 1.14fc6ceb099bfp+1 Inexact 46 | 47 | acosh 1.8p0 -> 1.ecc2caec5160ap-1 Inexact 48 | asinh 0.8p0 -> 1.ecc2caec5160ap-2 Inexact 49 | atanh 0.8p0 -> 1.193ea7aad030bp-1 Inexact 50 | 51 | # Other transcendental functions. 52 | eint 1.8p0 -> 1.a690858762f6bp+1 Inexact 53 | li2 0.cp0 -> 1.f4f9f0b58b974p-1 Inexact 54 | gamma 2.8p0 -> 1.544fa6d47b390p+0 Inexact 55 | gamma_inc 0.5p0 1.7p0 -> 0x1.1b29c8af307e2p-3 Inexact 56 | lngamma 2.8p0 -> 1.2383e809a67e8p-2 Inexact 57 | digamma 2.8p0 -> 1.680425af12b5ep-1 Inexact 58 | beta 0.5p0 1.7p0 -> 0x1.619aaeeb6cb2bp+1 Inexact 59 | zeta 4.0p0 -> 1.151322ac7d848p+0 Inexact 60 | erf 3.8p0 -> 1.ffffe710d565ep-1 Inexact 61 | erfc 3.8p0 -> 1.8ef2a9a18d857p-21 Inexact 62 | agm 1p0 1.6a09e667f3bcdp+0 -> 1.32b95184360ccp+0 Inexact 63 | ai 0.ap0 -> 1.a2db43a6d812dp-3 Inexact 64 | 65 | # Arithmetic functions not tested elsewhere. 66 | dim 2.8p0 1p0 -> 1.8p0 67 | dim 1p0 2.8p0 -> 0p0 68 | fma 3p0 5p0 8p0 -> 17p0 69 | fms 3p0 5p0 8p0 -> 7p0 70 | fmma 3 5 8 9 -> 0x57 71 | fmms 3 5 8 9 -> -0x39 72 | 73 | hypot 5p0 cp0 -> dp0 74 | 75 | floor -1p0 -> -1p0 76 | floor -0.dp0 -> -1p0 77 | floor -0.1p0 -> -1p0 78 | floor -0p0 -> -0p0 79 | floor 0p0 -> 0p0 80 | floor 0.1p0 -> 0p0 81 | floor 0.dp0 -> 0p0 82 | floor 1p0 -> 1p0 83 | 84 | ceil -1p0 -> -1p0 85 | ceil -0.dp0 -> -0p0 86 | ceil -0.1p0 -> -0p0 87 | ceil -0p0 -> -0p0 88 | ceil 0p0 -> 0p0 89 | ceil 0.1p0 -> 1p0 90 | ceil 0.dp0 -> 1p0 91 | ceil 1p0 -> 1p0 92 | 93 | round -1.8p0 -> -2p0 94 | round -1p0 -> -1p0 95 | round -0.8p0 -> -1p0 96 | round -0.dp0 -> -1p0 97 | round -0.1p0 -> -0p0 98 | round -0p0 -> -0p0 99 | round 0p0 -> 0p0 100 | round 0.1p0 -> 0p0 101 | round 0.8p0 -> 1p0 102 | round 0.dp0 -> 1p0 103 | round 1p0 -> 1p0 104 | round 1.8p0 -> 2p0 105 | 106 | roundeven -1.8p0 -> -2p0 107 | roundeven -1p0 -> -1p0 108 | roundeven -0.8p0 -> -0p0 109 | roundeven -0.dp0 -> -1p0 110 | roundeven -0.1p0 -> -0p0 111 | roundeven -0p0 -> -0p0 112 | roundeven 0p0 -> 0p0 113 | roundeven 0.1p0 -> 0p0 114 | roundeven 0.8p0 -> 0p0 115 | roundeven 0.dp0 -> 1p0 116 | roundeven 1p0 -> 1p0 117 | roundeven 1.8p0 -> 2p0 118 | 119 | trunc -1p0 -> -1p0 120 | trunc -0.dp0 -> -0p0 121 | trunc -0.1p0 -> -0p0 122 | trunc -0p0 -> -0p0 123 | trunc 0p0 -> 0p0 124 | trunc 0.1p0 -> 0p0 125 | trunc 0.dp0 -> 0p0 126 | trunc 1p0 -> 1p0 127 | 128 | frac -1p0 -> -0p0 129 | frac -0.dp0 -> -0.dp0 130 | frac -0.1p0 -> -0.1p0 131 | frac -0p0 -> -0p0 132 | frac 0p0 -> 0p0 133 | frac 0.1p0 -> 0.1p0 134 | frac 0.dp0 -> 0.dp0 135 | frac 1p0 -> 0p0 136 | 137 | remainder -5p0 3p0 -> 1p0 138 | remainder -4p0 3p0 -> -1p0 139 | remainder -3p0 3p0 -> -0p0 140 | remainder -2p0 3p0 -> 1p0 141 | remainder -1p0 3p0 -> -1p0 142 | remainder -0p0 3p0 -> -0p0 143 | remainder 0p0 3p0 -> 0p0 144 | remainder 1p0 3p0 -> 1p0 145 | remainder 2p0 3p0 -> -1p0 146 | remainder 3p0 3p0 -> 0p0 147 | remainder 4p0 3p0 -> 1p0 148 | remainder 5p0 3p0 -> -1p0 149 | -------------------------------------------------------------------------------- /examples/lanczos_coeffs.py: -------------------------------------------------------------------------------- 1 | # Copyright 2009--2019 Mark Dickinson. 2 | # 3 | # This file is part of the bigfloat package. 4 | # 5 | # The bigfloat package is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU Lesser General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or (at your 8 | # option) any later version. 9 | # 10 | # The bigfloat package is distributed in the hope that it will be useful, but 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 | # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License 13 | # for more details. 14 | # 15 | # You should have received a copy of the GNU Lesser General Public License 16 | # along with the bigfloat package. If not, see . 17 | 18 | # Computing the gamma function via Lanczos' formula 19 | # 20 | # See document at: 21 | # 22 | # http://www.boost.org/doc/libs/1_40_0/libs/math/doc/sf_and_dist/html/math_toolkit/backgrounders/lanczos.html 23 | # 24 | # for more. Note that the formula for a_0 on that page is invalid, involving 25 | # a (-1)!. But in general, the j=0 term of the sum for a_k is 26 | # (k-1)!/(k)! = 1/k, and multiplying by k gives 0. 27 | 28 | # The reference 29 | # 30 | # http://my.fit.edu/~gabdo/gamma.txt (Paul Godfrey) gives instead 31 | # the formulas: 32 | # 33 | # z! = sqrt(2*pi)*(z+g+1/2)^(z+1/2)*exp(-(z+g+1/2))*Ag(z) 34 | 35 | # Ag(z) = 1/2*p(0) + z/(z+1)*p(1) + z*(z-1)/(z+1)/(z+2)*p(2) + ... 36 | 37 | # p(k) = sum_{j=0}^k C(2k, 2j)*F(g, j) 38 | 39 | # C(2k, 2j) : coefficients of the Chebyshev polynomials of the 40 | # first kind. (1, x, 2x^2-1, 4x^3-3x, ...). Thus: 41 | # 42 | # C(0, 0) = 1 43 | # C(2, 0) = -1, C(2, 2) = 2 44 | # C(4, 0) = 1, C(4, 2) = -8, C(4, 4) = 8 45 | 46 | # sequence A053120. 47 | # 48 | # if C(n, m) = coefficient of x**m in nth poly, then 49 | # C(n, 0) = (-1)**(n/2) (n even) 50 | # C(n, m) = (-1)**((n+m)/2 + m) * (2**(m-1))*n*binomial((n+m)/2-1, m-1)/m 51 | 52 | # Hence: 53 | # 54 | # C(2k, 2j) = (-1)**(j+k) 2**(2j-1) 2k binomial(k+j-1, 2j-1) / (2j) 55 | # = (-1)**(j+k) 2**2j (k+j-1)! / (2j)! / (k-j)! * k 56 | # absorbing the (2j)!/j!/2**(2j) from F(g, j) gives: 57 | # = (-1)**(j+k) (k+j-1)! * k / (k-j)! / j! 58 | 59 | # Okay, so that works in 60 | 61 | 62 | # F(g, j) = sqrt(2)/pi * (j-1/2)!*(j+g+1/2)^-(j+1/2)*exp(j+g+1/2) 63 | 64 | # note that (j-1/2)! = (j-1/2)*(j-3/2)*...*(1/2) * sqrt(pi) 65 | # = (2*j-1)*(2*j-3)*...*2 * sqrt(pi) / 2**j 66 | # = (2*j)!/j!/2**(2j) * sqrt(pi) 67 | 68 | 69 | from __future__ import division 70 | from math import factorial 71 | import bigfloat 72 | from bigfloat import exp 73 | 74 | 75 | def M(k, j): 76 | # returns an integer, the combinatorial coefficient in the 77 | # Lanczos formula. 78 | assert 0 <= j and 0 <= k 79 | if j == k == 0: 80 | return 1 81 | if j > k: 82 | return 0 83 | top = (-1) ** (k + j) * factorial(j + k - 1) * k 84 | bottom = factorial(k - j) * factorial(j) 85 | assert top % bottom == 0 86 | return top // bottom 87 | 88 | 89 | def H(g, j): 90 | return exp(j + g + 0.5) / (j + g + 0.5) ** (j + 0.5) 91 | 92 | 93 | def b(j, N): 94 | assert 0 <= j <= N - 1 95 | coeffs = [1] 96 | facs = list(range(j, N - 1)) + list(range(-1, -j - 1, -1)) 97 | for i in facs: 98 | # multiply by (z+i) 99 | times_z = [0] + coeffs 100 | times_i = [i * c for c in coeffs] + [0] 101 | coeffs = [a + b for a, b in zip(times_z, times_i)] 102 | assert len(coeffs) == N 103 | return coeffs 104 | 105 | 106 | def Lg_num_coeffs(g, N): 107 | B = [b(j, N) for j in range(N)] 108 | MM = [ 109 | [(M(k, j) if k == 0 else 2 * M(k, j)) for j in range(N)] 110 | for k in range(N) 111 | ] 112 | # BTM has only integer entries 113 | BTM = [ 114 | [sum(B[k][l] * MM[k][j] for k in range(N)) for j in range(N)] 115 | for l in range(N) 116 | ] 117 | 118 | HH = [H(g, j) for j in range(N)] 119 | coeffs = [sum(BTM[i][j] * HH[j] for j in range(N)) for i in range(N)] 120 | return coeffs 121 | 122 | 123 | def Lg_den_coeffs(g, N): 124 | return b(0, N) 125 | 126 | 127 | def L(g, z, N): 128 | num_coeffs = Lg_num_coeffs(g, N) 129 | den_coeffs = Lg_den_coeffs(g, N) 130 | 131 | num = 0.0 132 | for c in reversed(num_coeffs): 133 | num = num * z + c 134 | den = 0.0 135 | for c in reversed(den_coeffs): 136 | den = den * z + c 137 | return num / den 138 | 139 | 140 | def gamma(z, g, N): 141 | return (z + g - 0.5) ** (z - 0.5) / exp(z + g - 0.5) * L(g, z, N) 142 | 143 | 144 | # Now express everything as a rational function; we want to be 145 | # able to figure out the coefficient of p_j z^k in the numerator. 146 | # Let's call this coefficient b(j, k). It depends on N. 147 | # b(j, N)[k] is the coefficient of p_j z^k in the numerator. 148 | # except: b(0, N)[k] is the coefficient of p_0/2 z^k in the numerator. 149 | 150 | p = 300 # bits of precision to use for computation 151 | g = bigfloat.BigFloat(6.024680040776729583740234375) 152 | N = 13 153 | 154 | with bigfloat.precision(p): 155 | print("Numerator coefficients:") 156 | for c in Lg_num_coeffs(g, N): 157 | print(c) 158 | 159 | print("Denominator coefficients:") 160 | for c in Lg_den_coeffs(g, N): 161 | print(c) 162 | -------------------------------------------------------------------------------- /examples/contfrac.py: -------------------------------------------------------------------------------- 1 | # Copyright 2009--2019 Mark Dickinson. 2 | # 3 | # This file is part of the bigfloat package. 4 | # 5 | # The bigfloat package is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU Lesser General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or (at your 8 | # option) any later version. 9 | # 10 | # The bigfloat package is distributed in the hope that it will be useful, but 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 | # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License 13 | # for more details. 14 | # 15 | # You should have received a copy of the GNU Lesser General Public License 16 | # along with the bigfloat package. If not, see . 17 | 18 | """ 19 | The documentation for mpfr_get_str, for converting a precision n 20 | number into a base b string, says: 21 | 22 | "the chosen precision of str is the minimal precision depending on 23 | n and b only that satisfies the above property, i.e., m = 1 + 24 | ceil(n*log(2)/log(b)), but in some very rare cases, it might be 25 | m+1." 26 | 27 | In this script, we compute the smallest precisions for which this 28 | 'very rare' case occurs, for each base b in the range 2 <= b <= 62. 29 | We compare our results with those computed by Paul Zimmerman. 30 | 31 | """ 32 | 33 | from fractions import Fraction 34 | from bigfloat import log2, div, precision, next_up 35 | from bigfloat import RoundTowardPositive, RoundTowardNegative 36 | 37 | 38 | def semiconvergents(x): 39 | """Semiconvergents of continued fraction expansion of a Fraction x.""" 40 | 41 | (q, n), d = divmod(x.numerator, x.denominator), x.denominator 42 | yield Fraction(q) 43 | p0, q0, p1, q1 = 1, 0, q, 1 44 | while n: 45 | (q, n), d = divmod(d, n), n 46 | for _ in range(q): 47 | p0, q0 = p0 + p1, q0 + q1 48 | yield Fraction(p0, q0) 49 | p0, q0, p1, q1 = p1, q1, p0, q0 50 | 51 | 52 | def logn2(n, p): 53 | """Best p-bit lower and upper bounds for log(2)/log(n), as Fractions.""" 54 | with precision(p): 55 | extra = 10 56 | while True: 57 | with precision(p + extra): 58 | # use extra precision for intermediate step 59 | log2upper = log2(n, RoundTowardPositive) 60 | log2lower = log2(n, RoundTowardNegative) 61 | 62 | lower = div(1, log2upper, RoundTowardNegative) 63 | upper = div(1, log2lower, RoundTowardPositive) 64 | 65 | # if lower and upper are adjacent (or equal) we're done 66 | if next_up(lower) == upper: 67 | return ( 68 | Fraction(*lower.as_integer_ratio()), 69 | Fraction(*upper.as_integer_ratio()), 70 | ) 71 | 72 | # otherwise, increase the precision and try again 73 | extra += 10 74 | 75 | 76 | marks_results = {} 77 | all_n = [n for n in range(3, 63) if n & (n - 1)] 78 | for n in all_n: 79 | # 76-bit upper approximation used for the computation of m 80 | approx = logn2(n, 76)[1] 81 | # Find first semiconvergent s s.t. log(2)/log(n) < s < approx. To 82 | # get semiconvergents of log(2)/log(n), get lower and upper bounds, 83 | # find semiconvergents of those, then use the matching initial portions 84 | # of the two lists. 85 | l, u = logn2(n, 100) # 100 seems to be big enough 86 | for lc, uc in zip(semiconvergents(l), semiconvergents(u)): 87 | if lc != uc: 88 | raise RuntimeError("not enough semiconvergents") 89 | if u <= lc < approx: 90 | marks_results[n] = lc.denominator 91 | break 92 | 93 | # from http://websympa.loria.fr/wwsympa/arc/mpfr/2009-06/msg00034.html: 94 | check_values = r""" 95 | 3, 975675645481 & 21, 500866275153 & 37, 1412595553751 & 52, 4234025992181\\ 96 | 5, 751072483167 & 22, 1148143737877 & 38, 2296403499681 & 53, 1114714558973\\ 97 | 6, 880248760192 & 23, 2963487537029 & 39, 227010038198 & 54, 653230957562 \\ 98 | 7, 186564318007 & 24, 930741237529 & 40, 3574908346547 & 55, 1113846215983\\ 99 | 9, 1951351290962 & 25, 751072483167 & 41, 458909109357 & 56, 385930970803 \\ 100 | 10, 1074541795081 & 26, 1973399062219 & 42, 1385773590791 & 57, 676124411642 \\ 101 | 11, 890679595344 & 27, 1193652440098 & 43, 945885487008 & 58, 330079387370 \\ 102 | 12, 727742578896 & 28, 319475419871 & 44, 1405607880410 & 59, 276902299279 \\ 103 | 13, 1553566199646 & 29, 1645653531910 & 45, 421759749499 & 60, 2304608467893\\ 104 | 14, 253019868939 & 30, 1190119072066 & 46, 376795094250 & 61, 1364503143363\\ 105 | 15, 947578699731 & 31, 2605117443408 & 47, 1352868311988 & 62, 414481628603 \\ 106 | 17, 628204683310 & 33, 1138749817330 & 48, 1133739896162 \\ 107 | 18, 2280193268258 & 34, 1611724268329 & 49, 186564318007 \\ 108 | 19, 2290706306707 & 35, 820222240621 & 50, 842842574535 \\ 109 | 20, 645428387961 & 36, 1760497520384 & 51, 1435927298893 \\ 110 | """ 111 | 112 | pauls_results = dict( 113 | map(int, piece.split(",")) 114 | for line in check_values.rstrip("\\\n").split(r"\\") 115 | for piece in line.split("&") 116 | ) 117 | 118 | print("{0:4s} {1:15s}".format("base", "precision")) 119 | print("{0:4s} {1:15s}".format("====", "===============")) 120 | for b, n in sorted(marks_results.items()): 121 | print("{0:4d} {1:15d}".format(b, n)) 122 | results_match = marks_results == pauls_results 123 | print("Results match Paul Zimmerman's: {}".format(results_match)) 124 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | PAPER = 8 | BUILDDIR = build 9 | 10 | # User-friendly check for sphinx-build 11 | ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) 12 | $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) 13 | endif 14 | 15 | # Internal variables. 16 | PAPEROPT_a4 = -D latex_paper_size=a4 17 | PAPEROPT_letter = -D latex_paper_size=letter 18 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source 19 | # the i18n builder cannot share the environment and doctrees with the others 20 | I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source 21 | 22 | .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext 23 | 24 | help: 25 | @echo "Please use \`make ' where is one of" 26 | @echo " html to make standalone HTML files" 27 | @echo " dirhtml to make HTML files named index.html in directories" 28 | @echo " singlehtml to make a single large HTML file" 29 | @echo " pickle to make pickle files" 30 | @echo " json to make JSON files" 31 | @echo " htmlhelp to make HTML files and a HTML help project" 32 | @echo " qthelp to make HTML files and a qthelp project" 33 | @echo " devhelp to make HTML files and a Devhelp project" 34 | @echo " epub to make an epub" 35 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" 36 | @echo " latexpdf to make LaTeX files and run them through pdflatex" 37 | @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" 38 | @echo " text to make text files" 39 | @echo " man to make manual pages" 40 | @echo " texinfo to make Texinfo files" 41 | @echo " info to make Texinfo files and run them through makeinfo" 42 | @echo " gettext to make PO message catalogs" 43 | @echo " changes to make an overview of all changed/added/deprecated items" 44 | @echo " xml to make Docutils-native XML files" 45 | @echo " pseudoxml to make pseudoxml-XML files for display purposes" 46 | @echo " linkcheck to check all external links for integrity" 47 | @echo " doctest to run all doctests embedded in the documentation (if enabled)" 48 | 49 | clean: 50 | rm -rf $(BUILDDIR)/* 51 | 52 | html: 53 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html 54 | @echo 55 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." 56 | 57 | dirhtml: 58 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml 59 | @echo 60 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." 61 | 62 | singlehtml: 63 | $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml 64 | @echo 65 | @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." 66 | 67 | pickle: 68 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle 69 | @echo 70 | @echo "Build finished; now you can process the pickle files." 71 | 72 | json: 73 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json 74 | @echo 75 | @echo "Build finished; now you can process the JSON files." 76 | 77 | htmlhelp: 78 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp 79 | @echo 80 | @echo "Build finished; now you can run HTML Help Workshop with the" \ 81 | ".hhp project file in $(BUILDDIR)/htmlhelp." 82 | 83 | qthelp: 84 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp 85 | @echo 86 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \ 87 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:" 88 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/bigfloat.qhcp" 89 | @echo "To view the help file:" 90 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/bigfloat.qhc" 91 | 92 | devhelp: 93 | $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp 94 | @echo 95 | @echo "Build finished." 96 | @echo "To view the help file:" 97 | @echo "# mkdir -p $$HOME/.local/share/devhelp/bigfloat" 98 | @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/bigfloat" 99 | @echo "# devhelp" 100 | 101 | epub: 102 | $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub 103 | @echo 104 | @echo "Build finished. The epub file is in $(BUILDDIR)/epub." 105 | 106 | latex: 107 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 108 | @echo 109 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." 110 | @echo "Run \`make' in that directory to run these through (pdf)latex" \ 111 | "(use \`make latexpdf' here to do that automatically)." 112 | 113 | latexpdf: 114 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 115 | @echo "Running LaTeX files through pdflatex..." 116 | $(MAKE) -C $(BUILDDIR)/latex all-pdf 117 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 118 | 119 | latexpdfja: 120 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 121 | @echo "Running LaTeX files through platex and dvipdfmx..." 122 | $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja 123 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 124 | 125 | text: 126 | $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text 127 | @echo 128 | @echo "Build finished. The text files are in $(BUILDDIR)/text." 129 | 130 | man: 131 | $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man 132 | @echo 133 | @echo "Build finished. The manual pages are in $(BUILDDIR)/man." 134 | 135 | texinfo: 136 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 137 | @echo 138 | @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." 139 | @echo "Run \`make' in that directory to run these through makeinfo" \ 140 | "(use \`make info' here to do that automatically)." 141 | 142 | info: 143 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 144 | @echo "Running Texinfo files through makeinfo..." 145 | make -C $(BUILDDIR)/texinfo info 146 | @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." 147 | 148 | gettext: 149 | $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale 150 | @echo 151 | @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." 152 | 153 | changes: 154 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes 155 | @echo 156 | @echo "The overview file is in $(BUILDDIR)/changes." 157 | 158 | linkcheck: 159 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck 160 | @echo 161 | @echo "Link check complete; look for any errors in the above output " \ 162 | "or in $(BUILDDIR)/linkcheck/output.txt." 163 | 164 | doctest: 165 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest 166 | @echo "Testing of doctests in the sources finished, look at the " \ 167 | "results in $(BUILDDIR)/doctest/output.txt." 168 | 169 | xml: 170 | $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml 171 | @echo 172 | @echo "Build finished. The XML files are in $(BUILDDIR)/xml." 173 | 174 | pseudoxml: 175 | $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml 176 | @echo 177 | @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." 178 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | .. image:: https://travis-ci.org/mdickinson/bigfloat.svg?branch=master 2 | :alt: Status of most recent Travis CI run 3 | :target: https://travis-ci.org/mdickinson/bigfloat 4 | 5 | 6 | The bigfloat package 7 | ==================== 8 | 9 | The ``bigfloat`` package is a Python package providing arbitrary-precision 10 | correctly-rounded binary floating-point arithmetic. It is implemented as a 11 | `Cython `_ wrapper around the `GNU MPFR library 12 | `_. A couple of lines of Python code should give the 13 | idea:: 14 | 15 | >>> from bigfloat import * 16 | >>> with precision(200) + RoundTowardZero: 17 | ... print(sqrt(2)) 18 | ... 19 | 1.4142135623730950488016887242096980785696718753769480731766796 20 | >>> with quadruple_precision: 21 | ... const_pi() 22 | ... 23 | BigFloat.exact('3.14159265358979323846264338327950280', precision=113) 24 | 25 | Features 26 | -------- 27 | 28 | - Supports Python 2 (version 2.7) and Python 3 (version 3.5 or later). 29 | 30 | - Exactly reproducible correctly-rounded results across platforms; 31 | precisely-defined semantics compatible with the IEEE 754-2008 standard. 32 | 33 | - Support for mixed-type operations with Python integers and floats. 34 | 35 | - Support for emulating IEEE 754 arithmetic in any of the IEEE binary 36 | interchange formats described in IEEE 754-2008. Infinities, NaNs, 37 | signed zeros, and subnormals are all supported. 38 | 39 | - Easy control of rounding modes and precisions via ``Context`` objects 40 | and Python's ``with`` statement. 41 | 42 | Documentation 43 | ------------- 44 | 45 | Full `package documentation `_ is hosted at 46 | Read the Docs. Read on for a quick tour. 47 | 48 | A quick tour 49 | ------------ 50 | 51 | The ``bigfloat`` package is small and simple to use. Here's a quick 52 | tour of some of its features. 53 | 54 | For demonstration purposes, start with:: 55 | 56 | >>> from bigfloat import * 57 | 58 | Note that this import shadows some builtin Python functions, namely ``abs``, 59 | ``max``, ``min``, ``pow``, ``round``, ``sum`` and (on Python 2 only) ``cmp``. 60 | In normal usage you'll probably only want to import the classes and functions 61 | that you actually need. 62 | 63 | The main class is the ``BigFloat`` class:: 64 | 65 | >>> BigFloat(1) # can be constructed from an integer, float or string 66 | BigFloat.exact('1.00000000000000000000000000000000000', precision=113) 67 | >>> BigFloat('3.14159') ** 2 / 6.0 # can combine with ints and floats 68 | BigFloat.exact('1.64493128801666666666666666666666670', precision=113) 69 | >>> BigFloat('0.1', precision(200)) # high-precision value from string 70 | BigFloat.exact('0.1000000000000000000000000000000000000000000000000000 71 | 0000000002', precision=200) 72 | 73 | Newly-created ``BigFloat`` instances refer to the current *context* to 74 | determine what precision and rounding modes to use. This current 75 | context is represented by a ``Context`` instance, and can be retrieved 76 | by calling ``getcontext``:: 77 | 78 | >>> getcontext() 79 | Context(precision=113, emax=16384, emin=-16493, 80 | subnormalize=True, rounding=ROUND_TIES_TO_EVEN) 81 | 82 | The ``precision(200)`` argument passed to the ``BigFloat`` constructor 83 | above is also an example of a ``Context``:: 84 | 85 | >>> precision(200) 86 | Context(precision=200) 87 | 88 | The context used for a calculation can be set using the ``setcontext`` 89 | function, but a better way to make a temporary change to the context 90 | is to use Python's ``with`` statement:: 91 | 92 | >>> with precision(1000): 93 | ... print sqrt(2) 94 | ... 95 | 1.41421356237309504880168872420969807856967187537694807317667973 96 | 7990732478462107038850387534327641572735013846230912297024924836 97 | 0558507372126441214970999358314132226659275055927557999505011527 98 | 8206057147010955997160597027453459686201472851741864088919860955 99 | 232923048430871432145083976260362799525140798964 100 | 101 | Here, ``sqrt`` is one of a number of mathematical functions that the 102 | ``bigfloat`` package exports. As you can see, these functions operate on 103 | integers and floats as well as ``BigFloat`` instances, but always 104 | return a ``BigFloat`` instance. 105 | 106 | Rounding modes can be controlled similarly. Here are upper and lower 107 | bounds for π, accurate to 53 significant bits:: 108 | 109 | >>> with RoundTowardPositive: 110 | ... const_pi() 111 | ... 112 | BigFloat.exact('3.14159265358979323846264338327950318', precision=113) 113 | >>> with RoundTowardNegative: 114 | ... const_pi() 115 | ... 116 | BigFloat.exact('3.14159265358979323846264338327950280', precision=113) 117 | 118 | And as you'd expect, ``with`` statements like those above can be 119 | nested. ``Context`` objects can also be combined using addition:: 120 | 121 | >>> with RoundTowardPositive + precision(24): 122 | ... BigFloat(1) / 3 123 | ... 124 | BigFloat.exact('0.333333343', precision=24) 125 | 126 | Various ``Context`` objects corresponding to IEEE 754 interchange 127 | formats are predefined:: 128 | 129 | >>> quadruple_precision 130 | Context(precision=113, emax=16384, emin=-16493, subnormalize=True) 131 | >>> half_precision 132 | Context(precision=11, emax=16, emin=-23, subnormalize=True) 133 | >>> with half_precision: 134 | log(2) 135 | ... 136 | BigFloat.exact('0.69336', precision=11) 137 | 138 | Installation 139 | ------------ 140 | 141 | The ``bigfloat`` package is `available on the Python package index 142 | `_, and can be installed in the usual 143 | way using ``easy_install`` or ``pip``. Alternatively, the development sources 144 | may be downloaded from the project's `homepage 145 | `_ on GitHub. 146 | 147 | For more comprehensive installation instructions, please see the `full 148 | documentation `_. 149 | 150 | Feedback 151 | -------- 152 | 153 | Feedback is welcome! Please use the `GitHub issue tracker 154 | `_ to report issues. 155 | Alternatively, you can contact Mark Dickinson directly at dickinsm@gmail.com 156 | with suggestions, complaints, bug reports, etc. 157 | 158 | License 159 | ------- 160 | 161 | The bigfloat package is copyright (C) 2009--2019 Mark Dickinson 162 | 163 | The bigfloat package is free software: you can redistribute it and/or modify 164 | it under the terms of the GNU Lesser General Public License as published by 165 | the Free Software Foundation, either version 3 of the License, or (at your 166 | option) any later version. 167 | 168 | The bigfloat package is distributed in the hope that it will be useful, but 169 | WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 170 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License 171 | for more details. 172 | 173 | You should have received a copy of the GNU Lesser General Public License 174 | along with the bigfloat package. If not, see . 175 | 176 | Links 177 | ----- 178 | - `Documentation at Read the Docs `_ 179 | - `Python package index `_ 180 | - `Project homepage at GitHub `_ 181 | - `Issue tracker `_ 182 | -------------------------------------------------------------------------------- /docs/source/index.rst: -------------------------------------------------------------------------------- 1 | The bigfloat package --- high precision floating-point arithmetic 2 | ================================================================= 3 | 4 | Release v\ |release|. 5 | 6 | .. module:: bigfloat 7 | :synopsis: Python wrapper for MPFR floating-point library. 8 | 9 | .. moduleauthor:: Mark Dickinson 10 | 11 | The :mod:`bigfloat` package is a Python wrapper for the `GNU MPFR library 12 | `_ for arbitrary-precision floating-point reliable 13 | arithmetic. The MPFR library is a well-known portable C library for 14 | arbitrary-precision arithmetic on floating-point numbers. It provides precise 15 | control over precisions and rounding modes and gives correctly-rounded 16 | reproducible platform-independent results. 17 | 18 | The :mod:`bigfloat` package aims to provide a convenient and friendly 19 | Python interface to the operations and functions provided by the MPFR 20 | library. The main class, :class:`BigFloat`, gives an immutable 21 | multiple-precision floating-point type that can be freely mixed with 22 | Python integers and floats. The :class:`Context` class, when used in 23 | conjunction with Python's ``with`` statement, gives a simple way of 24 | controlling precisions and rounding modes. Additional module-level 25 | functions provide various standard mathematical operations. There is 26 | full support for IEEE 754 signed zeros, nans, infinities and 27 | subnormals. 28 | 29 | 30 | Features 31 | -------- 32 | 33 | - Supports Python 2 (version 2.7) and Python 3 (version 3.5 or later). 34 | 35 | - Exactly reproducible correctly-rounded results across platforms; 36 | precisely-defined semantics compatible with the IEEE 754-2008 standard. 37 | 38 | - Support for mixed-type operations with Python integers and floats. 39 | 40 | - Support for emulating IEEE 754 arithmetic in any of the IEEE binary 41 | interchange formats described in IEEE 754-2008. Infinities, NaNs, 42 | signed zeros, and subnormals are all supported. 43 | 44 | - Easy control of rounding modes and precisions via ``Context`` objects 45 | and Python's ``with`` statement. 46 | 47 | 48 | Introduction 49 | ------------ 50 | 51 | Here's a quick tour:: 52 | 53 | >>> from bigfloat import * 54 | >>> sqrt(2, precision(100)) # compute sqrt(2) with 100 bits of precision 55 | BigFloat.exact('1.4142135623730950488016887242092', precision=100) 56 | >>> with precision(100): # another way to get the same result 57 | ... sqrt(2) 58 | ... 59 | BigFloat.exact('1.4142135623730950488016887242092', precision=100) 60 | >>> my_context = precision(100) + RoundTowardPositive 61 | >>> my_context 62 | Context(precision=100, rounding='RoundTowardPositive') 63 | >>> sqrt(2, my_context) # and another, this time rounding up 64 | BigFloat.exact('1.4142135623730950488016887242108', precision=100) 65 | >>> with RoundTowardNegative: # a lower bound for zeta(2) 66 | ... sum(1/sqr(n) for n in range(1, 10000)) 67 | ... 68 | BigFloat.exact('1.6448340618469506', precision=53) 69 | >>> zeta(2) # actual value, for comparison 70 | BigFloat.exact('1.6449340668482264', precision=53) 71 | >>> const_pi()**2/6.0 # double check value 72 | BigFloat.exact('1.6449340668482264', precision=53) 73 | >>> quadruple_precision # context implementing IEEE 754 binary128 format 74 | Context(precision=113, emax=16384, emin=-16493, subnormalize=True) 75 | >>> next_up(0, quadruple_precision) # smallest subnormal for binary128 76 | BigFloat.exact('6.47517511943802511092443895822764655e-4966', precision=113) 77 | >>> log2(_) 78 | BigFloat.exact('-16494.000000000000', precision=53) 79 | 80 | 81 | Installation 82 | ------------ 83 | 84 | Where to get it 85 | ^^^^^^^^^^^^^^^ 86 | 87 | The latest released version of the :mod:`bigfloat` package can be obtained from 88 | the `Python Package Index `_. 89 | Development sources can be checked out from the project's `GitHub page 90 | `_. 91 | 92 | 93 | Prerequisites 94 | ^^^^^^^^^^^^^ 95 | 96 | The :mod:`bigfloat` package works with Python 2 (version 2.7) or 97 | Python 3 (version 3.5 or later). It uses a single codebase for both Python 98 | dialects, so the same source works on both dialects of Python. 99 | 100 | Whether installing ``bigfloat`` from source or from the Python Package Index, 101 | you will need to have both the GMP and MPFR libraries already installed on your 102 | system, along with the include files for those libraries. See the `MPFR 103 | homepage `_ and the `GMP homepage `_ 104 | for more information about these libraries. Currently, MPFR version 3.0.0 or 105 | later is required. 106 | 107 | On Ubuntu, prerequisites can be installed with:: 108 | 109 | sudo apt-get install libmpfr-dev 110 | 111 | On Fedora Linux, use (for example):: 112 | 113 | su -c "yum install mpfr-devel" 114 | 115 | On other flavours of Linux, some variant of one of the above should work. 116 | 117 | 118 | Installation from the Python Package Index 119 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 120 | 121 | Once you have the prerequisites described above installed, the recommended 122 | method for installation is to use `pip`_:: 123 | 124 | pip install bigfloat 125 | 126 | If you prefer, you can use the ``easy_install`` command from `setuptools`_:: 127 | 128 | easy-install bigfloat 129 | 130 | Depending on your system, you may need superuser privileges for the install. 131 | For example:: 132 | 133 | sudo pip install bigfloat 134 | 135 | If the MPFR and GMP libraries are installed in an unusual location, you may 136 | need to set appropriate environment variables when installing. For example, on 137 | an OS X 10.9 system with MPFR and GMP installed in /opt/local, I need to do:: 138 | 139 | sudo LIBRARY_PATH=/opt/local/lib CPATH=/opt/local/include pip install bigfloat 140 | 141 | Platform-specific installation instructions 142 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 143 | 144 | On a newly-installed version of Ubuntu 14.04LTS (trusty), the commands below 145 | are enough to install bigfloat for Python 3, from scratch. You may not need 146 | the first line if you already have ``pip`` and the Python development headers 147 | installed. 148 | 149 | :: 150 | 151 | sudo apt-get install python3-dev python3-pip 152 | sudo apt-get install libmpfr-dev 153 | sudo pip3 install bigfloat 154 | 155 | For Python 2, the procedure is similar:: 156 | 157 | sudo apt-get install python-dev python-pip 158 | sudo apt-get install libmpfr-dev 159 | sudo pip install bigfloat 160 | 161 | On Fedora 20, the following sequence of commands worked for me (for Python 3; 162 | again, remove all occurrences of ``3`` to get the commands for Python 2):: 163 | 164 | su -c "yum install gcc python3-devel python3-pip" 165 | su -c "yum install mpfr-devel" 166 | su -c "pip-python3 install bigfloat" 167 | 168 | 169 | Installation from source 170 | ^^^^^^^^^^^^^^^^^^^^^^^^ 171 | 172 | Installation from source (for example, from a GitHub checkout, or from an 173 | unpacked source distribution), is similar to installation from the Python 174 | Package Index: the only difference is that you should use the ``setup.py `` 175 | script instead of using ``pip`` or ``easy_install``. On many systems, 176 | installation should be as simple as typing:: 177 | 178 | python setup.py install 179 | 180 | in the top-level directory of the unpacked distribution. As above, you may 181 | need superuser privileges to install the library, for example with:: 182 | 183 | sudo python setup.py install 184 | 185 | Again as above, if the libraries and include files are installed in an 186 | unusual place, it may be necessary to specify their location using environment 187 | variables on the command line. For example:: 188 | 189 | LIBRARY_PATH=/opt/local/lib CPATH=/opt/local/include python setup.py install 190 | 191 | 192 | Detailed Documentation 193 | ====================== 194 | 195 | .. toctree:: 196 | :maxdepth: 2 197 | 198 | tutorial/index 199 | reference/index 200 | 201 | 202 | Indices and tables 203 | ================== 204 | 205 | * :ref:`genindex` 206 | 207 | .. _pip: https://pypi.python.org/pypi/pip 208 | .. _setuptools: https://pypi.python.org/pypi/setuptools 209 | -------------------------------------------------------------------------------- /bigfloat/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright 2009--2019 Mark Dickinson. 2 | # 3 | # This file is part of the bigfloat package. 4 | # 5 | # The bigfloat package is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU Lesser General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or (at your 8 | # option) any later version. 9 | # 10 | # The bigfloat package is distributed in the hope that it will be useful, but 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 | # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License 13 | # for more details. 14 | # 15 | # You should have received a copy of the GNU Lesser General Public License 16 | # along with the bigfloat package. If not, see . 17 | 18 | __all__ = [ 19 | # version string for bigfloat 20 | "__version__", 21 | # main class 22 | "BigFloat", 23 | # contexts 24 | "Context", 25 | # limits on emin, emax and precision 26 | "EMIN_MIN", 27 | "EMIN_MAX", 28 | "EMAX_MIN", 29 | "EMAX_MAX", 30 | "PRECISION_MIN", 31 | "PRECISION_MAX", 32 | # rounding mode constants 33 | "ROUND_TIES_TO_EVEN", 34 | "ROUND_TOWARD_ZERO", 35 | "ROUND_TOWARD_POSITIVE", 36 | "ROUND_TOWARD_NEGATIVE", 37 | "ROUND_AWAY_FROM_ZERO", 38 | # context constants... 39 | "DefaultContext", 40 | "EmptyContext", 41 | "half_precision", 42 | "single_precision", 43 | "double_precision", 44 | "quadruple_precision", 45 | "RoundTiesToEven", 46 | "RoundTowardZero", 47 | "RoundTowardPositive", 48 | "RoundTowardNegative", 49 | "RoundAwayFromZero", 50 | # ... and functions 51 | "IEEEContext", 52 | "precision", 53 | "extra_precision", 54 | "rounding", 55 | # get and set current context 56 | "getcontext", 57 | "setcontext", 58 | # flags 59 | "Inexact", 60 | "Overflow", 61 | "Underflow", 62 | "NanFlag", 63 | "ZeroDivision", 64 | # functions to test, set and clear individual flags 65 | "test_flag", 66 | "set_flag", 67 | "clear_flag", 68 | # and to get and set the entire flag state 69 | "set_flagstate", 70 | "get_flagstate", 71 | # numeric functions 72 | "next_up", 73 | "next_down", 74 | # 5.2 Assignment Functions 75 | "pos", 76 | # 5.4 Conversion functions 77 | "frexp", 78 | # 5.5 Basic arithmetic functions 79 | "add", 80 | "sub", 81 | "mul", 82 | "sqr", 83 | "div", 84 | "sqrt", 85 | "rec_sqrt", 86 | "cbrt", 87 | "root", 88 | "rootn", 89 | "pow", 90 | "neg", 91 | "abs", 92 | "dim", 93 | "floordiv", 94 | "mod", 95 | # 5.6 Comparison functions 96 | "cmp", 97 | "cmpabs", 98 | "is_nan", 99 | "is_inf", 100 | "is_finite", 101 | "is_zero", 102 | "is_regular", 103 | "sgn", 104 | "greater", 105 | "greaterequal", 106 | "less", 107 | "lessequal", 108 | "equal", 109 | "notequal", 110 | "lessgreater", 111 | "unordered", 112 | # 5.7 Special Functions 113 | "log", 114 | "log2", 115 | "log10", 116 | "log1p", 117 | "exp", 118 | "exp2", 119 | "exp10", 120 | "expm1", 121 | "cos", 122 | "sin", 123 | "tan", 124 | "sec", 125 | "csc", 126 | "cot", 127 | "acos", 128 | "asin", 129 | "atan", 130 | "atan2", 131 | "cosh", 132 | "sinh", 133 | "tanh", 134 | "sech", 135 | "csch", 136 | "coth", 137 | "acosh", 138 | "asinh", 139 | "atanh", 140 | "factorial", 141 | "eint", 142 | "li2", 143 | "gamma", 144 | "gamma_inc", 145 | "lngamma", 146 | "lgamma", 147 | "digamma", 148 | "beta", 149 | "zeta", 150 | "zeta_ui", 151 | "erf", 152 | "erfc", 153 | "j0", 154 | "j1", 155 | "jn", 156 | "y0", 157 | "y1", 158 | "yn", 159 | "fma", 160 | "fms", 161 | "fmma", 162 | "fmms", 163 | "agm", 164 | "hypot", 165 | "ai", 166 | "const_log2", 167 | "const_pi", 168 | "const_euler", 169 | "const_catalan", 170 | "sum", 171 | # 5.10 Integer and Remainder Related Functions 172 | "ceil", 173 | "floor", 174 | "round", 175 | "roundeven", 176 | "trunc", 177 | "frac", 178 | "fmod", 179 | "remainder", 180 | "is_integer", 181 | # 5.12 Miscellaneous Functions 182 | "min", 183 | "max", 184 | "is_negative", 185 | "copysign", 186 | "MPFR_VERSION", 187 | "MPFR_VERSION_MAJOR", 188 | "MPFR_VERSION_MINOR", 189 | "MPFR_VERSION_PATCHLEVEL", 190 | "MPFR_VERSION_STRING", 191 | ] 192 | 193 | from bigfloat.core import ( 194 | BigFloat, 195 | EMIN_MIN, 196 | EMIN_MAX, 197 | EMAX_MIN, 198 | EMAX_MAX, 199 | PRECISION_MIN, 200 | PRECISION_MAX, 201 | Inexact, 202 | Overflow, 203 | ZeroDivision, 204 | NanFlag, 205 | Underflow, 206 | set_flagstate, 207 | get_flagstate, 208 | test_flag, 209 | set_flag, 210 | clear_flag, 211 | # Miscellaneous functions 212 | next_down, 213 | next_up, 214 | # 5.2 Assignment Functions 215 | pos, 216 | # 5.4 Conversion Functions 217 | frexp, 218 | # 5.5 Basic Arithmetic Functions 219 | add, 220 | sub, 221 | mul, 222 | sqr, 223 | div, 224 | sqrt, 225 | rec_sqrt, 226 | cbrt, 227 | root, 228 | rootn, 229 | pow, 230 | neg, 231 | abs, 232 | dim, 233 | # Additional arithmetic functions (not implemented directly by MPFR) 234 | floordiv, 235 | mod, 236 | # 5.6 Comparison Functions 237 | cmp, 238 | cmpabs, 239 | is_nan, 240 | is_inf, 241 | is_finite, 242 | is_zero, 243 | is_regular, 244 | sgn, 245 | greater, 246 | greaterequal, 247 | less, 248 | lessequal, 249 | equal, 250 | notequal, 251 | lessgreater, 252 | unordered, 253 | # 5.7 Special Functions 254 | log, 255 | log2, 256 | log10, 257 | log1p, 258 | exp, 259 | exp2, 260 | exp10, 261 | expm1, 262 | cos, 263 | sin, 264 | tan, 265 | sec, 266 | csc, 267 | cot, 268 | acos, 269 | asin, 270 | atan, 271 | atan2, 272 | cosh, 273 | sinh, 274 | tanh, 275 | sech, 276 | csch, 277 | coth, 278 | acosh, 279 | asinh, 280 | atanh, 281 | factorial, 282 | eint, 283 | li2, 284 | gamma, 285 | gamma_inc, 286 | lngamma, 287 | lgamma, 288 | digamma, 289 | beta, 290 | zeta, 291 | zeta_ui, 292 | erf, 293 | erfc, 294 | j0, 295 | j1, 296 | jn, 297 | y0, 298 | y1, 299 | yn, 300 | fma, 301 | fms, 302 | fmma, 303 | fmms, 304 | agm, 305 | hypot, 306 | ai, 307 | const_log2, 308 | const_pi, 309 | const_euler, 310 | const_catalan, 311 | sum, 312 | # 5.10 Integer and Remainder Related Functions 313 | ceil, 314 | floor, 315 | round, 316 | roundeven, 317 | trunc, 318 | frac, 319 | fmod, 320 | remainder, 321 | is_integer, 322 | # 5.12 Miscellaneous Functions 323 | min, 324 | max, 325 | is_negative, 326 | copysign, 327 | ) 328 | 329 | from bigfloat.version import __version__ 330 | 331 | from mpfr import ( 332 | # MPFR Version information 333 | MPFR_VERSION, 334 | MPFR_VERSION_MAJOR, 335 | MPFR_VERSION_MINOR, 336 | MPFR_VERSION_PATCHLEVEL, 337 | MPFR_VERSION_STRING, 338 | ) 339 | 340 | from bigfloat.context import ( 341 | Context, 342 | setcontext, 343 | getcontext, 344 | DefaultContext, 345 | EmptyContext, 346 | precision, 347 | rounding, 348 | extra_precision, 349 | RoundTiesToEven, 350 | RoundTowardZero, 351 | RoundTowardPositive, 352 | RoundTowardNegative, 353 | RoundAwayFromZero, 354 | ) 355 | 356 | from bigfloat.ieee import ( 357 | IEEEContext, 358 | half_precision, 359 | single_precision, 360 | double_precision, 361 | quadruple_precision, 362 | ) 363 | 364 | from bigfloat.rounding_mode import ( 365 | ROUND_TIES_TO_EVEN, 366 | ROUND_TOWARD_ZERO, 367 | ROUND_TOWARD_POSITIVE, 368 | ROUND_TOWARD_NEGATIVE, 369 | ROUND_AWAY_FROM_ZERO, 370 | ) 371 | -------------------------------------------------------------------------------- /COPYING.LESSER: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /CHANGELOG.rst: -------------------------------------------------------------------------------- 1 | What's new in bigfloat 0.4.0? 2 | ============================= 3 | 4 | Release date: 2019-12-30 5 | 6 | This minor release adds a number of small features, changes the default 7 | context to match IEEE 754 quadruple precision (binary128), and fixes support 8 | for recent Python versions. 9 | 10 | Thanks to Hugo van Kemenade for contributions to this release. 11 | 12 | New Features 13 | ------------ 14 | 15 | - Wrap mpfr_buildopt_gmpinternals_p and mpfr_buildopt_tune_case. (#54) 16 | 17 | - Add bigfloat.__version__ (#46). 18 | 19 | - Add bigfloat.notequal. (#47) 20 | 21 | - Add format support. (#58). 22 | 23 | - Add support for ``round``, ``math.floor``, ``math.ceil``, ``math.trunc`` on 24 | Python 3. (#64) 25 | 26 | - Add support for ``divmod`` and the ``//`` operator. (#69) 27 | 28 | - New ``floordiv`` and ``mod`` functions. The new ``mod`` replaces the old 29 | ``mod`` function, which has been renamed to ``fmod``. (#69) 30 | 31 | Changes 32 | ------- 33 | 34 | - The default context now matches IEEE 754 quadruple precision instead 35 | of double precision. (#72, #89, #87) 36 | 37 | - Infinities and NaNs are now represented as 'inf' and 'nan' rather 38 | than 'Infinity' and 'NaN', for consistency with the float type, and 39 | for consistency with the newly-introduced string formatting. 40 | 41 | - The 'mod' function now follows Python sign conventions; the old 42 | 'mod' function has been renamed to 'fmod'. The '%' operator 43 | now also follows Python sign conventions. (#69) 44 | 45 | - MPFR version 3.0.0 or later is required. 46 | 47 | - Support for Python versions earlier than 3.5 or 2.7 has been dropped. 48 | Support for Python 3.7 and 3.8 has been added. (#75, 81). 49 | 50 | Bugfixes 51 | -------- 52 | 53 | - The ``root`` function was accidentally wrapping ``cbrt`` (#60). 54 | Now fixed (#62). 55 | 56 | - Fix a test failure with Mpfr 4.0, that was due a change in the value 57 | of ``MPFR_PREC_MIN``. (#77) 58 | 59 | - Fix initialization of the context on background threads. (#91) 60 | 61 | - Fix unit tests that changed the context and didn't reset their changes. 62 | (#92, #98) 63 | 64 | Build 65 | ----- 66 | 67 | - Use ``language_level=3`` in the Cython code. (#96) 68 | 69 | Documentation 70 | ------------- 71 | 72 | - Installation documentation cleaned up. (#68) 73 | 74 | - Add ``cmp`` to list of shadowed builtins in ``README.rst``. (#63) 75 | 76 | - Fix (outdated) uses of strings for rounding modes. (#57) 77 | 78 | 79 | What's new in bigfloat 0.3.0? 80 | ============================= 81 | 82 | Library 83 | ------- 84 | 85 | - Fix string-returning functions and string constants in ``mpfr`` module to 86 | return something of type ``str`` both on Python 2 and Python 3. In earlier 87 | 0.3.0 pre-releases, objects of type ``unicode`` were being returned on 88 | Python 2. 89 | 90 | - Declarations in ``cmpfr.pxd`` fixed to include ``const`` where necessary; 91 | this fixes some compiler warnings. 92 | 93 | - Improved tests for hashing. 94 | 95 | 96 | Miscellaneous 97 | ------------- 98 | 99 | - Fix documentation link for PyPI upload. 100 | 101 | - Docs updated to remove outdated instructions about use under Python 2.5 and 102 | outdated information (dating from the earlier ctypes version) about runtime 103 | location of the MPFR and GMP libraries. 104 | 105 | - ``README``, ``setup.py`` updates: include the quick tour in the ``README``, 106 | make content match that of the ``setup.py`` long description. 107 | 108 | - ``CHANGELOG``, ``README``, ``INSTALL`` files updated with various 109 | reStructuredText fixes; renamed to add ``.rst`` suffix so that they display 110 | nicely on GitHub. 111 | 112 | - Update copyright notices. 113 | 114 | 115 | What's new in bigfloat 0.3.0b1? 116 | =============================== 117 | 118 | Library 119 | ------- 120 | 121 | - Python 3.2 and later are now supported. Python 2 support requires Python 2.6 122 | or later. 123 | 124 | - Added support for the new 'divide-by-zero' flag (exposed as ``ZeroDivision`` 125 | to bigfloat). 126 | 127 | Miscellaneous 128 | ------------- 129 | 130 | - Development moved from bitbucket (https://bitbucket.org/dickinsm/bigfloat) 131 | to GitHub (https://github.com/mdickinson/bigfloat), and repository 132 | converted from mercurial to Git. 133 | 134 | - Travis CI and Read the Docs GitHub hooks added. 135 | 136 | 137 | What's new in bigfloat 0.3.0a2? 138 | =============================== 139 | 140 | - Minor documentation fixes. 141 | 142 | 143 | What's new in bigfloat 0.3.0a1? 144 | =============================== 145 | 146 | 147 | Prerequisites 148 | ------------- 149 | 150 | - For now, Python 2.7 and MPFR version >= 3.0 are required. Support for 151 | earlier versions of Python is planned. Support for MPFR 2.x will probably 152 | not be added. 153 | 154 | 155 | Library 156 | ------- 157 | 158 | - Major rewrite and restructuring of the core code. The core now uses Cython 159 | rather than ctypes. 160 | 161 | - mpfr module now separately available as an extension type, with semantics 162 | very close to the Mpfr library. 163 | 164 | - Added bigfloat support for new rounding mode MPFR_RNDA (round away from 165 | zero). 166 | 167 | - Rounding modes are now represented as named integers (instances of 168 | RoundingMode, an int subclass), rather than strings. This allows them to be 169 | passed directly to Mpfr functions. 170 | 171 | - Fixed a bug that meant old context wasn't restored when changing exponents 172 | with one valid exponent and one invalid. (eminmax) 173 | 174 | - Many more docstrings than originally; better function signatures. 175 | 176 | - Restructured bigfloat package: mpfr wrapper module is now bigfloat.mpfr, 177 | context class and related functions are in bigfloat.context, rounding modes 178 | are defined in bigfloat.rounding_modes, and the main BigFloat type is defined 179 | in bigfloat.core. Everything is importable directory from bigfloat, as 180 | before. 181 | 182 | 183 | Documentation 184 | ------------- 185 | 186 | - Most of the documentation is now generated automatically using Sphinx's 187 | autodoc extension. 188 | 189 | 190 | What's new in bigfloat 0.2.1? 191 | ============================= 192 | 193 | Library 194 | ------- 195 | 196 | - Simplify weakref callback scheme used to ensure BigFloat instances 197 | are freed properly. 198 | 199 | - Make sure all python files in distribution have the LGPL header. 200 | 201 | 202 | What's new in bigfloat 0.2? 203 | =========================== 204 | 205 | Library 206 | ------- 207 | 208 | - The setup.py file no longer attempts to locate the MPFR library at 209 | install time. The configuration file still exists, and can be edited 210 | to give a hard-coded location. Alternatively, ctypes should find the 211 | library if it's within the usual library search paths. (If not, it 212 | might be necessary to set LD_LIBRARY_PATH or DYLD_LIBRARY_PATH.) 213 | 214 | - Use a weakref callback to ensure ``mpfr_clear`` gets called, instead of 215 | relying on ``__del__``. 216 | 217 | - Make bigfloat compatible with versions of MPFR as far back as MPFR 2.3.0 218 | 219 | - Relicense under LGPL, since this package might be considered a 220 | derived work of MPFR. 221 | 222 | 223 | Tests 224 | ----- 225 | 226 | - Skip the hashing consistency tests (those that test whether ``hash(n) == 227 | hash(BigFloat(n))`` for integers ``n``) on Python 2.5. In rare cases, this 228 | equality fails with Python 2.5, and this is awkward to fix. If this affects 229 | you, upgrade to Python 2.6 or avoid mixing BigFloat instances with ints in 230 | sets or dictionary keys. 231 | 232 | 233 | What's new in bigfloat 0.1.2? 234 | ============================= 235 | 236 | Library 237 | ------- 238 | 239 | - Make ``Context`` objects hashable. 240 | 241 | Documentation 242 | ------------- 243 | 244 | - Add 'where to get it' section to the documentation, pointing both 245 | to the PyPI page and the bitbucket source. 246 | 247 | - Expand installation information in documentation. 248 | 249 | Packaging/distribution 250 | ---------------------- 251 | 252 | - Include html documentation in distribution, in docs directory. 253 | 254 | - Include INSTALL and CHANGELOG files in distribution. 255 | 256 | - Make sure the bigfloat_config.py file ends up in the top-level 257 | package directory. 258 | 259 | - Add /usr/lib{32,64} and /usr/local/lib{32,64} to default search 260 | paths in setup.py. 261 | -------------------------------------------------------------------------------- /bigfloat/mpfr_supplemental.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 2 | 3 | # Copyright 2009--2019 Mark Dickinson. 4 | # 5 | # This file is part of the bigfloat package. 6 | # 7 | # The bigfloat package is free software: you can redistribute it and/or modify 8 | # it under the terms of the GNU Lesser General Public License as published by 9 | # the Free Software Foundation, either version 3 of the License, or (at your 10 | # option) any later version. 11 | # 12 | # The bigfloat package is distributed in the hope that it will be useful, but 13 | # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 | # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License 15 | # for more details. 16 | # 17 | # You should have received a copy of the GNU Lesser General Public License 18 | # along with the bigfloat package. If not, see . 19 | """ 20 | Supplementary functions with a similar API to those in the mpfr module. 21 | """ 22 | import mpfr 23 | 24 | 25 | def _quotient_exponent(x, y): 26 | """ 27 | Given two positive finite MPFR instances x and y, 28 | find the exponent of x / y; that is, the unique 29 | integer e such that 2**(e-1) <= x / y < 2**e. 30 | 31 | """ 32 | assert mpfr.mpfr_regular_p(x) 33 | assert mpfr.mpfr_regular_p(y) 34 | 35 | # Make copy of x with the exponent of y. 36 | x2 = mpfr.Mpfr_t() 37 | mpfr.mpfr_init2(x2, mpfr.mpfr_get_prec(x)) 38 | mpfr.mpfr_set(x2, x, mpfr.MPFR_RNDN) 39 | mpfr.mpfr_set_exp(x2, mpfr.mpfr_get_exp(y)) 40 | 41 | # Compare x2 and y, disregarding the sign. 42 | extra = mpfr.mpfr_cmpabs(x2, y) >= 0 43 | return extra + mpfr.mpfr_get_exp(x) - mpfr.mpfr_get_exp(y) 44 | 45 | 46 | def mpfr_floordiv(rop, x, y, rnd): 47 | """ 48 | Given two MPFR numbers x and y, compute floor(x / y), 49 | rounded if necessary using the given rounding mode. 50 | The result is placed in 'rop'. 51 | """ 52 | # Algorithm notes 53 | # --------------- 54 | # A simple and obvious approach is to compute floor(x / y) exactly, and 55 | # then round to the nearest representable value using the given rounding 56 | # mode. This requires computing x / y to a precision sufficient to ensure 57 | # that floor(x / y) is exactly representable. If abs(x / y) < 2**r, then 58 | # abs(floor(x / y)) <= 2**r, and so r bits of precision is enough. 59 | # However, for large quotients this is impractical, and we need some other 60 | # method. For x / y sufficiently large, it's possible to show that x / y 61 | # and floor(x / y) are indistinguishable, in the sense that both quantities 62 | # round to the same value. More precisely, we have the following theorem: 63 | # 64 | # Theorem. Suppose that x and y are nonzero finite binary floats 65 | # representable with p and q bits of precision, respectively. Let R be any 66 | # of the IEEE 754 standard rounding modes, and choose a target precision r. 67 | # Write rnd for the rounding operation from Q to precision-r binary floats 68 | # with rounding mode R. Write bin(x) for the binade of a nonzero float x. 69 | # 70 | # If R is a round-to-nearest rounding mode, and either 71 | # 72 | # (1) p <= q + r and |x / y| >= 2^(q + r), or 73 | # (2) p > q + r and bin(x) - bin(y) >= p 74 | # 75 | # then 76 | # 77 | # rnd(floor(x / y)) == rnd(x / y) 78 | # 79 | # Conversely, if R is a directed rounding mode, and either 80 | # 81 | # (1) p < q + r and |x / y| >= 2^(q + r - 1), or 82 | # (2) p >= q + r and bin(x) - bin(y) >= p 83 | # 84 | # then again 85 | # 86 | # rnd(floor(x / y)) == rnd(x / y). 87 | # 88 | # Proof. See separate notes and Coq proof in the float-proofs 89 | # repository. 90 | # 91 | # Rather than distinguish between the various cases (R directed 92 | # or not, p large versus p small) above, we use a weaker but 93 | # simpler amalgamation of the above result: 94 | # 95 | # Corollary 1. With x, y, p, q, R, r and rnd as above, if 96 | # 97 | # |x / y| >= 2^max(q + r, p) 98 | # 99 | # then 100 | # 101 | # rnd(floor(x / y)) == rnd(x / y). 102 | # 103 | # Proof. Note that |x / y| >= 2^p implies bin(x) - bin(y) >= p, 104 | # so it's enough that |x / y| >= 2^max(p, q + r) in the case of 105 | # a round-to-nearest mode, and that |x / y| >= 2^max(p, q + r - 1) 106 | # in the case of a directed rounding mode. 107 | 108 | # In special cases, it's safe to defer to mpfr_div: the result in 109 | # these cases is always 0, infinity, or nan. 110 | if not mpfr.mpfr_regular_p(x) or not mpfr.mpfr_regular_p(y): 111 | return mpfr.mpfr_div(rop, x, y, rnd) 112 | 113 | e = _quotient_exponent(x, y) 114 | 115 | p = mpfr.mpfr_get_prec(x) 116 | q = mpfr.mpfr_get_prec(y) 117 | r = mpfr.mpfr_get_prec(rop) 118 | 119 | # If e - 1 >= max(p, q+r) then |x / y| >= 2^(e-1) >= 2^max(p, q+r), 120 | # so by the above theorem, round(floordiv(x, y)) == round(div(x, y)). 121 | if e - 1 >= max(p, q + r): 122 | return mpfr.mpfr_div(rop, x, y, rnd) 123 | 124 | # Slow version: compute to sufficient bits to get integer precision. Given 125 | # that 2**(e-1) <= x / y < 2**e, need >= e bits of precision. 126 | z_prec = max(e, 2) 127 | z = mpfr.Mpfr_t() 128 | mpfr.mpfr_init2(z, z_prec) 129 | 130 | # Compute the floor exactly. The division may set the 131 | # inexact flag, so we save its state first. 132 | old_inexact = mpfr.mpfr_inexflag_p() 133 | mpfr.mpfr_div(z, x, y, mpfr.MPFR_RNDD) 134 | if not old_inexact: 135 | mpfr.mpfr_clear_inexflag() 136 | 137 | # Floor result should be exactly representable, so any rounding mode will 138 | # do. 139 | ternary = mpfr.mpfr_rint_floor(z, z, rnd) 140 | assert ternary == 0 141 | 142 | # ... and round to the given rounding mode. 143 | return mpfr.mpfr_set(rop, z, rnd) 144 | 145 | 146 | def mpfr_mod(rop, x, y, rnd): 147 | """ 148 | Given two MPRF numbers x and y, compute 149 | x - floor(x / y) * y, rounded if necessary using the given 150 | rounding mode. The result is placed in 'rop'. 151 | 152 | This is the 'remainder' operation, with sign convention 153 | compatible with Python's % operator (where x % y has 154 | the same sign as y). 155 | """ 156 | # There are various cases: 157 | # 158 | # 0. If either argument is a NaN, the result is NaN. 159 | # 160 | # 1. If x is infinite or y is zero, the result is NaN. 161 | # 162 | # 2. If y is infinite, return 0 with the sign of y if x is zero, x if x has 163 | # the same sign as y, and infinity with the sign of y if it has the 164 | # opposite sign. 165 | # 166 | # 3. If none of the above cases apply then both x and y are finite, 167 | # and y is nonzero. If x and y have the same sign, simply 168 | # return the result of fmod(x, y). 169 | # 170 | # 4. Now both x and y are finite, y is nonzero, and x and y have 171 | # differing signs. Compute r = fmod(x, y) with sufficient precision 172 | # to get an exact result. If r == 0, return 0 with the sign of y 173 | # (which will be the opposite of the sign of x). If r != 0, 174 | # return r + y, rounded appropriately. 175 | 176 | if not mpfr.mpfr_number_p(x) or mpfr.mpfr_nan_p(y) or mpfr.mpfr_zero_p(y): 177 | return mpfr.mpfr_fmod(rop, x, y, rnd) 178 | elif mpfr.mpfr_inf_p(y): 179 | x_negative = mpfr.mpfr_signbit(x) 180 | y_negative = mpfr.mpfr_signbit(y) 181 | if mpfr.mpfr_zero_p(x): 182 | mpfr.mpfr_set_zero(rop, -y_negative) 183 | return 0 184 | elif x_negative == y_negative: 185 | return mpfr.mpfr_set(rop, x, rnd) 186 | else: 187 | mpfr.mpfr_set_inf(rop, -y_negative) 188 | return 0 189 | 190 | x_negative = mpfr.mpfr_signbit(x) 191 | y_negative = mpfr.mpfr_signbit(y) 192 | if x_negative == y_negative: 193 | return mpfr.mpfr_fmod(rop, x, y, rnd) 194 | else: 195 | p = max(mpfr.mpfr_get_prec(x), mpfr.mpfr_get_prec(y)) 196 | z = mpfr.Mpfr_t() 197 | mpfr.mpfr_init2(z, p) 198 | # Doesn't matter what rounding mode we use here; the result 199 | # should be exact. 200 | ternary = mpfr.mpfr_fmod(z, x, y, rnd) 201 | assert ternary == 0 202 | if mpfr.mpfr_zero_p(z): 203 | mpfr.mpfr_set_zero(rop, -y_negative) 204 | return 0 205 | else: 206 | return mpfr.mpfr_add(rop, y, z, rnd) 207 | -------------------------------------------------------------------------------- /bigfloat/test/test_data/floordiv.bft: -------------------------------------------------------------------------------- 1 | context double_precision 2 | context RoundTiesToEven 3 | 4 | # Simple cases. 5 | floordiv 0x2p0 0x1p0 -> 0x2p0 6 | floordiv 0x1p0 0x2p0 -> 0x0p0 7 | 8 | # Negative operands. 9 | floordiv -0x2p0 0x1p0 -> -0x2p0 10 | floordiv -0x1p0 0x2p0 -> -0x1p0 11 | 12 | floordiv 0x2p0 -0x1p0 -> -0x2p0 13 | floordiv 0x1p0 -0x2p0 -> -0x1p0 14 | 15 | # Zeros. 16 | floordiv 0x0p0 0x1.88p0 -> 0x0p0 17 | floordiv -0x0p0 0x1.88p0 -> -0x0p0 18 | floordiv 0x0p0 -0x1.88p0 -> -0x0p0 19 | floordiv -0x0p0 -0x1.88p0 -> 0x0p0 20 | 21 | floordiv 0x1.88p0 0x0p0 -> inf ZeroDivision 22 | floordiv -0x1.88p0 0x0p0 -> -inf ZeroDivision 23 | floordiv 0x1.88p0 -0x0p0 -> -inf ZeroDivision 24 | floordiv -0x1.88p0 -0x0p0 -> inf ZeroDivision 25 | 26 | floordiv 0x0p0 0x0p0 -> nan NanFlag 27 | floordiv -0x0p0 0x0p0 -> nan NanFlag 28 | floordiv 0x0p0 -0x0p0 -> nan NanFlag 29 | floordiv -0x0p0 -0x0p0 -> nan NanFlag 30 | 31 | # Infinities. 32 | floordiv 0x0p0 inf -> 0x0p0 33 | floordiv -0x0p0 inf -> -0x0p0 34 | floordiv 0x0p0 -inf -> -0x0p0 35 | floordiv -0x0p0 -inf -> 0x0p0 36 | 37 | floordiv 0x1.34ap-23 inf -> 0x0p0 38 | floordiv -0x1.34ap-23 inf -> -0x0p0 39 | floordiv 0x1.34ap-23 -inf -> -0x0p0 40 | floordiv -0x1.34ap-23 -inf -> 0x0p0 41 | 42 | floordiv inf inf -> nan NanFlag 43 | floordiv -inf inf -> nan NanFlag 44 | floordiv inf -inf -> nan NanFlag 45 | floordiv -inf -inf -> nan NanFlag 46 | 47 | floordiv inf 0x1.adep55 -> inf 48 | floordiv -inf 0x1.adep55 -> -inf 49 | floordiv inf -0x1.adep55 -> -inf 50 | floordiv -inf -0x1.adep55 -> inf 51 | 52 | floordiv inf 0x0p0 -> inf 53 | floordiv -inf 0x0p0 -> -inf 54 | floordiv inf -0x0p0 -> -inf 55 | floordiv -inf -0x0p0 -> inf 56 | 57 | # NaNs 58 | floordiv nan 0x0p0 -> nan NanFlag 59 | floordiv nan 0x1p0 -> nan NanFlag 60 | floordiv nan inf -> nan NanFlag 61 | floordiv nan nan -> nan NanFlag 62 | floordiv inf nan -> nan NanFlag 63 | floordiv 0x1p0 nan -> nan NanFlag 64 | floordiv 0x0p0 nan -> nan NanFlag 65 | 66 | # A few randomly-generated cases. 67 | floordiv 0x1.b2a98bbcc49b4p+98 0x1.3d74b2d390501p+48 -> 0x1.5e843fc46ffa8p+50 68 | floordiv -0x1.b2a98bbcc49b4p+98 -0x1.3d74b2d390501p+48 -> 0x1.5e843fc46ffa8p+50 69 | floordiv -0x1.b2a98bbcc49b4p+98 0x1.3d74b2d390501p+48 -> -0x1.5e843fc46ffacp+50 70 | floordiv 0x1.b2a98bbcc49b4p+98 -0x1.3d74b2d390501p+48 -> -0x1.5e843fc46ffacp+50 71 | 72 | # Randomly-generated near-halfway cases. 73 | floordiv 0x1.7455b4855c470p+158 0x1.9f63221b65037p+52 -> 0x1.caef27bbd32c3p+105 Inexact 74 | floordiv -0x1.7455b4855c470p+158 0x1.9f63221b65037p+52 -> -0x1.caef27bbd32c4p+105 Inexact 75 | floordiv 0x1.3e80b2f3da4e3p+158 0x1.55d84f1af57e3p+52 -> 0x1.dd0a000b852e5p+105 Inexact 76 | floordiv -0x1.3e80b2f3da4e3p+158 0x1.55d84f1af57e3p+52 -> -0x1.dd0a000b852e6p+105 Inexact 77 | floordiv 0x1.1ef2d934ebab9p+158 0x1.b1f7b86b3147fp+52 -> 0x1.528b96ac455bfp+105 Inexact 78 | floordiv -0x1.1ef2d934ebab9p+158 0x1.b1f7b86b3147fp+52 -> -0x1.528b96ac455c0p+105 Inexact 79 | floordiv 0x1.d9e46ba382852p+158 0x1.e12e2c5c55f27p+52 -> 0x1.f83ebede8104bp+105 Inexact 80 | floordiv -0x1.d9e46ba382852p+158 0x1.e12e2c5c55f27p+52 -> -0x1.f83ebede8104cp+105 Inexact 81 | floordiv 0x1.0a29a5b5b8f7dp+158 0x1.2c53d755c382dp+52 -> 0x1.c5c170a956bd2p+105 Inexact 82 | floordiv -0x1.0a29a5b5b8f7dp+158 0x1.2c53d755c382dp+52 -> -0x1.c5c170a956bd2p+105 Inexact 83 | floordiv 0x1.236ba96f8838bp+158 0x1.e2e23e8730f95p+52 -> 0x1.34fe01ad9e1dep+105 Inexact 84 | floordiv -0x1.236ba96f8838bp+158 0x1.e2e23e8730f95p+52 -> -0x1.34fe01ad9e1dep+105 Inexact 85 | floordiv 0x1.1ff3215dc95f4p+158 0x1.ec809f7a6c20bp+52 -> 0x1.2b596bfcd1cd1p+105 Inexact 86 | floordiv -0x1.1ff3215dc95f4p+158 0x1.ec809f7a6c20bp+52 -> -0x1.2b596bfcd1cd2p+105 Inexact 87 | floordiv 0x1.b55d8ec0da9fep+158 0x1.f6d8adea89b9fp+52 -> 0x1.bd53bacf4e02fp+105 Inexact 88 | floordiv -0x1.b55d8ec0da9fep+158 0x1.f6d8adea89b9fp+52 -> -0x1.bd53bacf4e030p+105 Inexact 89 | floordiv 0x1.2852761e5852bp+158 0x1.7ddb08bf86a6fp+52 -> 0x1.8d509db211a47p+105 Inexact 90 | floordiv -0x1.2852761e5852bp+158 0x1.7ddb08bf86a6fp+52 -> -0x1.8d509db211a48p+105 Inexact 91 | floordiv 0x1.1c97fd65f4e7cp+158 0x1.a6ba81f4da293p+52 -> 0x1.58b1a7e0e65cdp+105 Inexact 92 | floordiv -0x1.1c97fd65f4e7cp+158 0x1.a6ba81f4da293p+52 -> -0x1.58b1a7e0e65cep+105 Inexact 93 | 94 | floordiv 0x1.8ae6742f94fcap+158 0x1.af61efd069439p+52 -> 0x1.d4b323e4872fcp+105 Inexact 95 | floordiv -0x1.8ae6742f94fcap+158 0x1.af61efd069439p+52 -> -0x1.d4b323e4872fcp+105 Inexact 96 | floordiv 0x1.50371bfb1ded8p+158 0x1.64df147fa2c0bp+52 -> 0x1.e25d6618d002ep+105 Inexact 97 | floordiv -0x1.50371bfb1ded8p+158 0x1.64df147fa2c0bp+52 -> -0x1.e25d6618d002fp+105 Inexact 98 | floordiv 0x1.29ad82f921e61p+158 0x1.ee88b9d5af47fp+52 -> 0x1.3430ee7ff9a40p+105 Inexact 99 | floordiv -0x1.29ad82f921e61p+158 0x1.ee88b9d5af47fp+52 -> -0x1.3430ee7ff9a41p+105 Inexact 100 | floordiv 0x1.341e592b2ef12p+158 0x1.c5715b0058be3p+52 -> 0x1.5be8a10c7f71ap+105 Inexact 101 | floordiv -0x1.341e592b2ef12p+158 0x1.c5715b0058be3p+52 -> -0x1.5be8a10c7f71bp+105 Inexact 102 | floordiv 0x1.281ad0d0b6e5ap+158 0x1.84ad50291a943p+52 -> 0x1.860e39fb7ea4ap+105 Inexact 103 | floordiv -0x1.281ad0d0b6e5ap+158 0x1.84ad50291a943p+52 -> -0x1.860e39fb7ea4bp+105 Inexact 104 | floordiv 0x1.1016dc07e1acep+158 0x1.70c44c2b976c1p+52 -> 0x1.79c5994d7f360p+105 Inexact 105 | floordiv -0x1.1016dc07e1acep+158 0x1.70c44c2b976c1p+52 -> -0x1.79c5994d7f360p+105 Inexact 106 | floordiv 0x1.c348cf5e24425p+158 0x1.d34d5e92de493p+52 -> 0x1.ee73382469332p+105 Inexact 107 | floordiv -0x1.c348cf5e24425p+158 0x1.d34d5e92de493p+52 -> -0x1.ee73382469333p+105 Inexact 108 | floordiv 0x1.bcfea94be48e6p+158 0x1.dde69c1267a85p+52 -> 0x1.dcbefc6ebc8dap+105 Inexact 109 | floordiv -0x1.bcfea94be48e6p+158 0x1.dde69c1267a85p+52 -> -0x1.dcbefc6ebc8dap+105 Inexact 110 | 111 | # Some cases where Python's // on floats gets the wrong result. 112 | floordiv 0x1.0e31636b07d9dp-898 0x1.c68968514f16bp-954 -> 0x1.3059e434dd2bep+55 Inexact 113 | floordiv 0x1.2bb44bbf6a807p-537 0x1.94a4d2cd73882p-589 -> 0x1.7b3809b6af846p+51 114 | 115 | # Overflow and underflow. (The latter shouldn't be possible unless 116 | # emin >= 0, which we currently don't check.) 117 | floordiv 0x1p1000 0x1p-1000 -> Infinity Inexact Overflow 118 | floordiv 0x1p512 0x1p-512 -> Infinity Inexact Overflow 119 | floordiv 0x1p511 0x1p-512 -> 0x1p1023 120 | floordiv 0x1p-1000 0x1p1000 -> 0x0p0 121 | 122 | # An extreme case where the floor of the quotient is exactly 123 | # representable but the quotient is not. 124 | floordiv 0x1.ff2e8e6fb6a62p+157 0x1.ff973c8000001p+52 -> 0x1.ff973c7ffffffp+104 125 | floordiv -0x1.ff2e8e6fb6a62p+157 0x1.ff973c8000001p+52 -> -0x1.ff973c7ffffffp+104 Inexact 126 | # ... and where neither are. 127 | floordiv 0x1.ff2e8e6fb6a62p+158 0x1.ff973c8000001p+52 -> 0x1.ff973c7ffffffp+105 Inexact 128 | floordiv -0x1.ff2e8e6fb6a62p+158 0x1.ff973c8000001p+52 -> -0x1.ff973c7ffffffp+105 Inexact 129 | 130 | #### Halfway cases: exact quotient is within 1 of a halfway case. 131 | # Exact quotient is 0x1.b6cb791cacbf37ffffffffffffb6de167b388b7fc8b3666a53bb....p+105 132 | # floordiv result is 1 smaller than halfway case, rounds down (towards zero) 133 | floordiv 0x1.800000000003bp+158 0x1.c0104a4a58bd7p+52 -> 0x1.b6cb791cacbf3p+105 Inexact 134 | # floordiv result *is* halfway case, rounds down (away from zero) 135 | floordiv -0x1.800000000003bp+158 0x1.c0104a4a58bd7p+52 -> -0x1.b6cb791cacbf4p+105 Inexact 136 | 137 | # Exact quotient is 0x1.98aa85ad41b278000000000000441c6b9ce0480bae415da0f245....p+105 138 | # floordiv result *is* halfway case, rounds up (away from zero) 139 | floordiv 0x1.8000000000021p+158 0x1.e118cf408df51p+52 -> 0x1.98aa85ad41b28p+105 Inexact 140 | # floordiv result one smaller than halfway case; rounds down (away from zero) 141 | floordiv -0x1.8000000000021p+158 0x1.e118cf408df51p+52 -> -0x1.98aa85ad41b28p+105 Inexact 142 | 143 | 144 | #### Check that the rounding mode is being respected. 145 | floordiv 0x1p53 0x0.fffffffffffff8p0 -> 0x1p53 Inexact 146 | floordiv 0x1p53 0x0.fffffffffffff0p0 -> 0x20000000000002p0 147 | floordiv 0x1p53 0x0.ffffffffffffe8p0 -> 0x20000000000004p0 Inexact 148 | 149 | context RoundTowardPositive 150 | floordiv 0x1p53 0x0.fffffffffffff8p0 -> 0x20000000000002p0 Inexact 151 | floordiv 0x1p53 0x0.fffffffffffff0p0 -> 0x20000000000002p0 152 | floordiv 0x1p53 0x0.ffffffffffffe8p0 -> 0x20000000000004p0 Inexact 153 | floordiv 0x1.ff2e8e6fb6a62p+157 0x1.ff973c8000001p+52 -> 0x1.ff973c7ffffffp+104 154 | floordiv -0x1.ff2e8e6fb6a62p+157 0x1.ff973c8000001p+52 -> -0x1.ff973c7ffffffp+104 Inexact 155 | 156 | context RoundTowardNegative 157 | floordiv 0x1p53 0x0.fffffffffffff8p0 -> 0x20000000000000p0 Inexact 158 | floordiv 0x1p53 0x0.fffffffffffff0p0 -> 0x20000000000002p0 159 | floordiv 0x1p53 0x0.ffffffffffffe8p0 -> 0x20000000000002p0 Inexact 160 | floordiv 0x1.ff2e8e6fb6a62p+157 0x1.ff973c8000001p+52 -> 0x1.ff973c7ffffffp+104 161 | floordiv -0x1.ff2e8e6fb6a62p+157 0x1.ff973c8000001p+52 -> -0x1.ff973c8000000p+104 Inexact 162 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 2 | 3 | # Copyright 2009--2019 Mark Dickinson. 4 | # 5 | # This file is part of the bigfloat package. 6 | # 7 | # The bigfloat package is free software: you can redistribute it and/or modify 8 | # it under the terms of the GNU Lesser General Public License as published by 9 | # the Free Software Foundation, either version 3 of the License, or (at your 10 | # option) any later version. 11 | # 12 | # The bigfloat package is distributed in the hope that it will be useful, but 13 | # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 | # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License 15 | # for more details. 16 | # 17 | # You should have received a copy of the GNU Lesser General Public License 18 | # along with the bigfloat package. If not, see . 19 | 20 | import os 21 | 22 | from setuptools import setup, Extension 23 | 24 | 25 | DESCRIPTION = """\ 26 | Arbitrary-precision correctly-rounded floating-point arithmetic, via MPFR.\ 27 | """ 28 | 29 | LONG_DESCRIPTION = """\ 30 | The ``bigfloat`` package is a Python package providing arbitrary-precision 31 | correctly-rounded binary floating-point arithmetic. It is implemented as a 32 | `Cython `_ wrapper around the `GNU MPFR library 33 | `_. A couple of lines of Python code should give the 34 | idea:: 35 | 36 | >>> from bigfloat import * 37 | >>> with precision(200) + RoundTowardZero: 38 | ... print(sqrt(2)) 39 | ... 40 | 1.4142135623730950488016887242096980785696718753769480731766796 41 | >>> with quadruple_precision: 42 | ... const_pi() 43 | ... 44 | BigFloat.exact('3.14159265358979323846264338327950280', precision=113) 45 | 46 | Features 47 | -------- 48 | 49 | - Supports Python 2 (version 2.7) and Python 3 (version 3.5 or later). 50 | 51 | - Exactly reproducible correctly-rounded results across platforms; 52 | precisely-defined semantics compatible with the IEEE 754-2008 standard. 53 | 54 | - Support for mixed-type operations with Python integers and floats. 55 | 56 | - Support for emulating IEEE 754 arithmetic in any of the IEEE binary 57 | interchange formats described in IEEE 754-2008. Infinities, NaNs, 58 | signed zeros, and subnormals are all supported. 59 | 60 | - Easy control of rounding modes and precisions via ``Context`` objects 61 | and Python's ``with`` statement. 62 | 63 | Documentation 64 | ------------- 65 | 66 | Full `package documentation `_ is hosted at 67 | Read the Docs. Read on for a quick tour. 68 | 69 | A quick tour 70 | ------------ 71 | 72 | The ``bigfloat`` package is small and simple to use. Here's a quick 73 | tour of some of its features. 74 | 75 | For demonstration purposes, start with:: 76 | 77 | >>> from bigfloat import * 78 | 79 | Note that this import shadows some builtin Python functions, namely ``abs``, 80 | ``max``, ``min``, ``pow``, ``round`` and (on Python 2 only) ``cmp``. In normal 81 | usage you'll probably only want to import the classes and functions that you 82 | actually need. 83 | 84 | The main class is the ``BigFloat`` class:: 85 | 86 | >>> BigFloat(1) # can be constructed from an integer, float or string 87 | BigFloat.exact('1.0000000000000000', precision=53) 88 | >>> BigFloat('3.14159') ** 2 / 6.0 # can combine with ints and floats 89 | BigFloat.exact('1.6449312880166664', precision=53) 90 | >>> BigFloat('0.1', precision(200)) # high-precision value from string 91 | BigFloat.exact('0.1000000000000000000000000000000000000000000000000000 92 | 0000000002', precision=200) 93 | 94 | Newly-created ``BigFloat`` instances refer to the current *context* to 95 | determine what precision and rounding modes to use. This current 96 | context is represented by a ``Context`` instance, and can be retrieved 97 | by calling ``getcontext``:: 98 | 99 | >>> getcontext() 100 | Context(precision=53, emax=1073741823, emin=-1073741823, 101 | subnormalize=False, rounding=ROUND_TIES_TO_EVEN) 102 | 103 | The ``precision(200)`` argument passed to the ``BigFloat`` constructor 104 | above is also an example of a ``Context``:: 105 | 106 | >>> precision(200) 107 | Context(precision=200) 108 | 109 | The context used for a calculation can be set using the ``setcontext`` 110 | function, but a better way to make a temporary change to the context 111 | is to use Python's ``with`` statement:: 112 | 113 | >>> with precision(1000): 114 | ... print sqrt(2) 115 | ... 116 | 1.41421356237309504880168872420969807856967187537694807317667973 117 | 7990732478462107038850387534327641572735013846230912297024924836 118 | 0558507372126441214970999358314132226659275055927557999505011527 119 | 8206057147010955997160597027453459686201472851741864088919860955 120 | 232923048430871432145083976260362799525140798964 121 | 122 | Here, ``sqrt`` is one of a number of mathematical functions that the 123 | ``bigfloat`` package exports. As you can see, these functions operate on 124 | integers and floats as well as ``BigFloat`` instances, but always 125 | return a ``BigFloat`` instance. 126 | 127 | Rounding modes can be controlled similarly. Here are upper and lower 128 | bounds for π, accurate to 53 significant bits:: 129 | 130 | >>> with RoundTowardPositive: 131 | ... const_pi() 132 | ... 133 | BigFloat.exact('3.1415926535897936', precision=53) 134 | >>> with RoundTowardNegative: 135 | ... const_pi() 136 | ... 137 | BigFloat.exact('3.1415926535897931', precision=53) 138 | 139 | And as you'd expect, ``with`` statements like those above can be 140 | nested. ``Context`` objects can also be combined using addition:: 141 | 142 | >>> with RoundTowardPositive + precision(24): 143 | ... BigFloat(1) / 3 144 | ... 145 | BigFloat.exact('0.333333343', precision=24) 146 | 147 | Various ``Context`` objects corresponding to IEEE 754 interchange 148 | formats are predefined:: 149 | 150 | >>> quadruple_precision 151 | Context(precision=113, emax=16384, emin=-16493, subnormalize=True) 152 | >>> half_precision 153 | Context(precision=11, emax=16, emin=-23, subnormalize=True) 154 | >>> with half_precision: 155 | log(2) 156 | ... 157 | BigFloat.exact('0.69336', precision=11) 158 | 159 | Installation 160 | ------------ 161 | 162 | The ``bigfloat`` package is `available on the Python package index 163 | `_, and can be installed in the usual 164 | way using ``easy_install`` or ``pip``. Alternatively, the development sources 165 | may be downloaded from the project's `homepage 166 | `_ on GitHub. 167 | 168 | For more comprehensive installation instructions, please see the `full 169 | documentation `_. 170 | 171 | Feedback 172 | -------- 173 | 174 | Feedback is welcome! Please use the `GitHub issue tracker 175 | `_ to report issues. 176 | Alternatively, you can contact Mark Dickinson directly at dickinsm@gmail.com 177 | with suggestions, complaints, bug reports, etc. 178 | 179 | License 180 | ------- 181 | 182 | The bigfloat package is copyright (C) 2009--2019 Mark Dickinson 183 | 184 | The bigfloat package is free software: you can redistribute it and/or modify 185 | it under the terms of the GNU Lesser General Public License as published by 186 | the Free Software Foundation, either version 3 of the License, or (at your 187 | option) any later version. 188 | 189 | The bigfloat package is distributed in the hope that it will be useful, but 190 | WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 191 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License 192 | for more details. 193 | 194 | You should have received a copy of the GNU Lesser General Public License 195 | along with the bigfloat package. If not, see . 196 | 197 | Links 198 | ----- 199 | - `Documentation at Read the Docs `_ 200 | - `Python package index `_ 201 | - `Project homepage at GitHub `_ 202 | - `Issue tracker `_ 203 | """ 204 | 205 | # During package development we want to use Cython, but the distributed 206 | # egg shouldn't use Cython. We use the presence of PKG-INFO to determine 207 | # which of these is true. 208 | if os.path.exists("PKG-INFO"): 209 | USE_CYTHON = False 210 | else: 211 | USE_CYTHON = True 212 | 213 | 214 | if USE_CYTHON: 215 | from Cython.Build import cythonize 216 | 217 | extensions = cythonize( 218 | Extension("mpfr", ["mpfr.pyx"], libraries=["mpfr", "gmp"],) 219 | ) 220 | else: 221 | extensions = [ 222 | Extension("mpfr", ["mpfr.c"], libraries=["mpfr", "gmp"],), 223 | ] 224 | 225 | 226 | CLASSIFIERS = """\ 227 | Development Status :: 4 - Beta 228 | Intended Audience :: Developers 229 | Intended Audience :: Education 230 | Intended Audience :: Science/Research 231 | License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3) 232 | Operating System :: OS Independent 233 | Programming Language :: Python :: 2 234 | Programming Language :: Python :: 2.7 235 | Programming Language :: Python :: 3 236 | Programming Language :: Python :: 3.5 237 | Programming Language :: Python :: 3.6 238 | Programming Language :: Python :: 3.7 239 | Programming Language :: Python :: 3.8 240 | Programming Language :: Python :: Implementation :: CPython 241 | Topic :: Scientific/Engineering :: Mathematics 242 | """.splitlines() 243 | 244 | 245 | def get_version_info(): 246 | """Extract version information as a dictionary from version.py.""" 247 | version_info = {} 248 | with open(os.path.join("bigfloat", "version.py"), "r") as f: 249 | version_code = compile(f.read(), "version.py", "exec") 250 | exec(version_code, version_info) 251 | return version_info 252 | 253 | 254 | version_info = get_version_info() 255 | 256 | setup( 257 | name="bigfloat", 258 | version=version_info["release"], 259 | description=DESCRIPTION, 260 | long_description=LONG_DESCRIPTION, 261 | long_description_content_type="text/x-rst", 262 | install_requires=["six"], 263 | author="Mark Dickinson", 264 | author_email="dickinsm@gmail.com", 265 | url="http://github.com/mdickinson/bigfloat", 266 | classifiers=CLASSIFIERS, 267 | platforms=["Linux", "OS X"], 268 | license="GNU Library or Lesser General Public License (LGPL)", 269 | ext_modules=extensions, 270 | packages=["bigfloat", "bigfloat.test"], 271 | package_data={"bigfloat.test": ["test_data/*.bft"]}, 272 | ) 273 | -------------------------------------------------------------------------------- /docs/source/conf.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | # 4 | # bigfloat documentation build configuration file, created by 5 | # sphinx-quickstart on Sun Jun 29 15:53:52 2014. 6 | # 7 | # This file is execfile()d with the current directory set to its 8 | # containing dir. 9 | # 10 | # Note that not all possible configuration values are present in this 11 | # autogenerated file. 12 | # 13 | # All configuration values have a default; values that are commented out 14 | # serve to show the default. 15 | 16 | import os 17 | import sys 18 | 19 | import bigfloat.version 20 | 21 | 22 | # We need to mock out the mpfr module for the doc builds, since 23 | # Read the Docs doesn't support building extension modules. 24 | class MockMpfr(object): 25 | MPFR_RNDN = 0 26 | 27 | MPFR_RNDZ = 1 28 | 29 | MPFR_RNDU = 2 30 | 31 | MPFR_RNDD = 3 32 | 33 | MPFR_RNDA = 4 34 | 35 | MPFR_RNDF = 5 36 | 37 | MPFR_EMIN_DEFAULT = -1073741823 38 | 39 | MPFR_EMAX_DEFAULT = 1073741823 40 | 41 | MPFR_PREC_MIN = 2 42 | 43 | MPFR_PREC_MAX = 9223372036854775807 44 | 45 | Mpfr_t = object 46 | 47 | MPFR_VERSION_MAJOR = 3 48 | 49 | MPFR_VERSION_MINOR = 1 50 | 51 | def mpfr_get_emin_max(self): 52 | return 4611686018427387903 53 | 54 | def mpfr_get_emax_min(self): 55 | return -4611686018427387903 56 | 57 | def mpfr_set_emin(self, precision): 58 | pass 59 | 60 | def mpfr_set_emax(self, precision): 61 | pass 62 | 63 | def __getattr__(self, name): 64 | return None 65 | 66 | 67 | # For the doc build, replace 'mpfr' extension module with a dummy 68 | # object. 69 | sys.modules["mpfr"] = MockMpfr() 70 | 71 | # If extensions (or modules to document with autodoc) are in another directory, 72 | # add these directories to sys.path here. If the directory is relative to the 73 | # documentation root, use os.path.abspath to make it absolute, like shown here. 74 | package_dir = os.path.abspath(os.path.join(os.path.pardir, os.path.pardir)) 75 | sys.path.insert(0, package_dir) 76 | 77 | # -- General configuration ------------------------------------------------ 78 | 79 | # If your documentation needs a minimal Sphinx version, state it here. 80 | # needs_sphinx = '1.0' 81 | 82 | # Add any Sphinx extension module names here, as strings. They can be 83 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 84 | # ones. 85 | extensions = [ 86 | "sphinx.ext.autodoc", 87 | "sphinx.ext.doctest", 88 | "sphinx.ext.intersphinx", 89 | "sphinx.ext.coverage", 90 | "sphinx.ext.mathjax", 91 | ] 92 | 93 | # Add any paths that contain templates here, relative to this directory. 94 | templates_path = ["_templates"] 95 | 96 | # The suffix of source filenames. 97 | source_suffix = ".rst" 98 | 99 | # The encoding of source files. 100 | # source_encoding = 'utf-8-sig' 101 | 102 | # The master toctree document. 103 | master_doc = "index" 104 | 105 | # General information about the project. 106 | project = "bigfloat" 107 | copyright = "2009--2019, Mark Dickinson" 108 | 109 | # The version info for the project you're documenting, acts as replacement for 110 | # |version| and |release|, also used in various other places throughout the 111 | # built documents. 112 | # 113 | # The short X.Y version. 114 | version = bigfloat.version.version 115 | 116 | # The full version, including alpha/beta/rc tags. 117 | release = bigfloat.version.release 118 | 119 | # The language for content autogenerated by Sphinx. Refer to documentation 120 | # for a list of supported languages. 121 | # language = None 122 | 123 | # There are two options for replacing |today|: either, you set today to some 124 | # non-false value, then it is used: 125 | # today = '' 126 | # Else, today_fmt is used as the format for a strftime call. 127 | # today_fmt = '%B %d, %Y' 128 | 129 | # List of patterns, relative to source directory, that match files and 130 | # directories to ignore when looking for source files. 131 | exclude_patterns = [] 132 | 133 | # The reST default role (used for this markup: `text`) to use for all 134 | # documents. 135 | # default_role = None 136 | 137 | # If true, '()' will be appended to :func: etc. cross-reference text. 138 | add_function_parentheses = False 139 | 140 | # If true, the current module name will be prepended to all description 141 | # unit titles (such as .. function::). 142 | # add_module_names = True 143 | 144 | # If true, sectionauthor and moduleauthor directives will be shown in the 145 | # output. They are ignored by default. 146 | # show_authors = False 147 | 148 | # The name of the Pygments (syntax highlighting) style to use. 149 | pygments_style = "sphinx" 150 | 151 | # A list of ignored prefixes for module index sorting. 152 | # modindex_common_prefix = [] 153 | 154 | # If true, keep warnings as "system message" paragraphs in the built documents. 155 | # keep_warnings = False 156 | 157 | 158 | # -- Options for HTML output ---------------------------------------------- 159 | 160 | # The theme to use for HTML and HTML Help pages. See the documentation for 161 | # a list of builtin themes. 162 | html_theme = "default" 163 | 164 | # Theme options are theme-specific and customize the look and feel of a theme 165 | # further. For a list of options available for each theme, see the 166 | # documentation. 167 | # html_theme_options = {} 168 | 169 | # Add any paths that contain custom themes here, relative to this directory. 170 | # html_theme_path = [] 171 | 172 | # The name for this set of Sphinx documents. If None, it defaults to 173 | # " v documentation". 174 | # html_title = None 175 | 176 | # A shorter title for the navigation bar. Default is the same as html_title. 177 | # html_short_title = None 178 | 179 | # The name of an image file (relative to this directory) to place at the top 180 | # of the sidebar. 181 | # html_logo = None 182 | 183 | # The name of an image file (within the static path) to use as favicon of the 184 | # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 185 | # pixels large. 186 | # html_favicon = None 187 | 188 | # Add any paths that contain custom static files (such as style sheets) here, 189 | # relative to this directory. They are copied after the builtin static files, 190 | # so a file named "default.css" will overwrite the builtin "default.css". 191 | # html_static_path = ['_static'] 192 | 193 | # Add any extra paths that contain custom files (such as robots.txt or 194 | # .htaccess) here, relative to this directory. These files are copied 195 | # directly to the root of the documentation. 196 | # html_extra_path = [] 197 | 198 | # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, 199 | # using the given strftime format. 200 | # html_last_updated_fmt = '%b %d, %Y' 201 | 202 | # If true, SmartyPants will be used to convert quotes and dashes to 203 | # typographically correct entities. 204 | # html_use_smartypants = True 205 | 206 | # Custom sidebar templates, maps document names to template names. 207 | # html_sidebars = {} 208 | 209 | # Additional templates that should be rendered to pages, maps page names to 210 | # template names. 211 | # html_additional_pages = {} 212 | 213 | # If false, no module index is generated. 214 | # html_domain_indices = True 215 | 216 | # If false, no index is generated. 217 | # html_use_index = True 218 | 219 | # If true, the index is split into individual pages for each letter. 220 | # html_split_index = False 221 | 222 | # If true, links to the reST sources are added to the pages. 223 | # html_show_sourcelink = True 224 | 225 | # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. 226 | # html_show_sphinx = True 227 | 228 | # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. 229 | # html_show_copyright = True 230 | 231 | # If true, an OpenSearch description file will be output, and all pages will 232 | # contain a tag referring to it. The value of this option must be the 233 | # base URL from which the finished HTML is served. 234 | # html_use_opensearch = '' 235 | 236 | # This is the file name suffix for HTML files (e.g. ".xhtml"). 237 | # html_file_suffix = None 238 | 239 | # Output file base name for HTML help builder. 240 | htmlhelp_basename = "bigfloatdoc" 241 | 242 | 243 | # -- Options for LaTeX output --------------------------------------------- 244 | 245 | latex_elements = {} 246 | 247 | # Grouping the document tree into LaTeX files. List of tuples 248 | # (source start file, target name, title, 249 | # author, documentclass [howto, manual, or own class]). 250 | latex_documents = [ 251 | ( 252 | "index", 253 | "bigfloat.tex", 254 | "bigfloat Documentation", 255 | "Mark Dickinson", 256 | "manual", 257 | ), 258 | ] 259 | 260 | # The name of an image file (relative to this directory) to place at the top of 261 | # the title page. 262 | # latex_logo = None 263 | 264 | # For "manual" documents, if this is true, then toplevel headings are parts, 265 | # not chapters. 266 | # latex_use_parts = False 267 | 268 | # If true, show page references after internal links. 269 | # latex_show_pagerefs = False 270 | 271 | # If true, show URL addresses after external links. 272 | # latex_show_urls = False 273 | 274 | # Documents to append as an appendix to all manuals. 275 | # latex_appendices = [] 276 | 277 | # If false, no module index is generated. 278 | # latex_domain_indices = True 279 | 280 | 281 | # -- Options for manual page output --------------------------------------- 282 | 283 | # One entry per manual page. List of tuples 284 | # (source start file, name, description, authors, manual section). 285 | man_pages = [ 286 | ("index", "bigfloat", "bigfloat Documentation", ["Mark Dickinson"], 1) 287 | ] 288 | 289 | # If true, show URL addresses after external links. 290 | # man_show_urls = False 291 | 292 | 293 | # -- Options for Texinfo output ------------------------------------------- 294 | 295 | # Grouping the document tree into Texinfo files. List of tuples 296 | # (source start file, target name, title, author, 297 | # dir menu entry, description, category) 298 | texinfo_documents = [ 299 | ( 300 | "index", 301 | "bigfloat", 302 | "bigfloat Documentation", 303 | "Mark Dickinson", 304 | "bigfloat", 305 | "One line description of project.", 306 | "Miscellaneous", 307 | ), 308 | ] 309 | 310 | # Documents to append as an appendix to all manuals. 311 | # texinfo_appendices = [] 312 | 313 | # If false, no module index is generated. 314 | # texinfo_domain_indices = True 315 | 316 | # How to display URL addresses: 'footnote', 'no', or 'inline'. 317 | # texinfo_show_urls = 'footnote' 318 | 319 | # If true, do not generate a @detailmenu in the "Top" node's menu. 320 | # texinfo_no_detailmenu = False 321 | 322 | 323 | # Example configuration for intersphinx: refer to the Python standard library. 324 | intersphinx_mapping = {"python": ("http://docs.python.org/3/", None)} 325 | 326 | 327 | # Workaround for failing PDF build due to a Unicode minus sign. 328 | def setup(app): 329 | from sphinx.util.texescape import tex_replacements 330 | 331 | tex_replacements.append((u"\u2212", u"-"),) 332 | -------------------------------------------------------------------------------- /bigfloat/test/test_context.py: -------------------------------------------------------------------------------- 1 | # Copyright 2009--2019 Mark Dickinson. 2 | # 3 | # This file is part of the bigfloat package. 4 | # 5 | # The bigfloat package is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU Lesser General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or (at your 8 | # option) any later version. 9 | # 10 | # The bigfloat package is distributed in the hope that it will be useful, but 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 | # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License 13 | # for more details. 14 | # 15 | # You should have received a copy of the GNU Lesser General Public License 16 | # along with the bigfloat package. If not, see . 17 | 18 | import threading 19 | import unittest 20 | 21 | from six.moves import queue 22 | 23 | import mpfr 24 | from bigfloat.context import ( 25 | getcontext, 26 | Context, 27 | DefaultContext, 28 | precision, 29 | RoundAwayFromZero, 30 | RoundTiesToEven, 31 | RoundTowardNegative, 32 | RoundTowardPositive, 33 | RoundTowardZero, 34 | _temporary_exponent_bounds, 35 | ) 36 | from bigfloat.ieee import quadruple_precision 37 | from bigfloat.rounding_mode import ( 38 | ROUND_TIES_TO_EVEN, 39 | ROUND_TOWARD_ZERO, 40 | ROUND_TOWARD_POSITIVE, 41 | ROUND_TOWARD_NEGATIVE, 42 | ROUND_AWAY_FROM_ZERO, 43 | ) 44 | 45 | all_rounding_modes = [ 46 | ROUND_TIES_TO_EVEN, 47 | ROUND_TOWARD_ZERO, 48 | ROUND_TOWARD_POSITIVE, 49 | ROUND_TOWARD_NEGATIVE, 50 | ROUND_AWAY_FROM_ZERO, 51 | ] 52 | 53 | 54 | class ContextTests(unittest.TestCase): 55 | def test__temporary_exponent_bounds(self): 56 | # Failed calls to _temporary_exponent_bounds shouldn't affect emin or 57 | # emax. 58 | original_emin = mpfr.mpfr_get_emin() 59 | original_emax = mpfr.mpfr_get_emax() 60 | 61 | # Call to _temporary_exponent_bounds should restore original values. 62 | with _temporary_exponent_bounds(-10, 10): 63 | self.assertEqual(mpfr.mpfr_get_emin(), -10) 64 | self.assertEqual(mpfr.mpfr_get_emax(), 10) 65 | self.assertEqual(mpfr.mpfr_get_emin(), original_emin) 66 | self.assertEqual(mpfr.mpfr_get_emax(), original_emax) 67 | 68 | # Even erroneous calls should restore originals. 69 | with self.assertRaises(OverflowError): 70 | with _temporary_exponent_bounds(-10, 10 ** 100): 71 | pass 72 | self.assertEqual(mpfr.mpfr_get_emin(), original_emin) 73 | self.assertEqual(mpfr.mpfr_get_emax(), original_emax) 74 | 75 | with self.assertRaises(OverflowError): 76 | with _temporary_exponent_bounds(-(10 ** 100), 10): 77 | pass 78 | self.assertEqual(mpfr.mpfr_get_emin(), original_emin) 79 | self.assertEqual(mpfr.mpfr_get_emax(), original_emax) 80 | 81 | with self.assertRaises(OverflowError): 82 | with _temporary_exponent_bounds(-(10 ** 100), 10 ** 100): 83 | pass 84 | self.assertEqual(mpfr.mpfr_get_emin(), original_emin) 85 | self.assertEqual(mpfr.mpfr_get_emax(), original_emax) 86 | 87 | def test_attributes(self): 88 | c = Context( 89 | emin=-999, 90 | emax=999, 91 | precision=100, 92 | subnormalize=True, 93 | rounding=ROUND_TIES_TO_EVEN, 94 | ) 95 | self.assertIsInstance(c.precision, int) 96 | self.assertIsInstance(c.emax, int) 97 | self.assertIsInstance(c.emin, int) 98 | self.assertIsInstance(c.subnormalize, bool) 99 | self.assertIn(c.rounding, all_rounding_modes) 100 | 101 | def test_bad_rounding_mode(self): 102 | with self.assertRaises(ValueError): 103 | Context(rounding=-1) 104 | 105 | def test_default_context(self): 106 | self.assertEqual( 107 | DefaultContext, quadruple_precision + RoundTiesToEven, 108 | ) 109 | 110 | def test_rounding_contexts(self): 111 | with RoundTiesToEven: 112 | self.assertEqual(getcontext().rounding, ROUND_TIES_TO_EVEN) 113 | with RoundTowardPositive: 114 | self.assertEqual(getcontext().rounding, ROUND_TOWARD_POSITIVE) 115 | with RoundTowardNegative: 116 | self.assertEqual(getcontext().rounding, ROUND_TOWARD_NEGATIVE) 117 | with RoundTiesToEven: 118 | self.assertEqual(getcontext().rounding, ROUND_TIES_TO_EVEN) 119 | with RoundAwayFromZero: 120 | self.assertEqual(getcontext().rounding, ROUND_AWAY_FROM_ZERO) 121 | 122 | # Rounding contexts should not affect existing settings for 123 | # precision, exponents, etc. 124 | original_contexts = [ 125 | Context( 126 | precision=234, 127 | emin=-9999, 128 | emax=9999, 129 | subnormalize=True, 130 | rounding=ROUND_TOWARD_NEGATIVE, 131 | ), 132 | Context( 133 | precision=5, 134 | emin=-10, 135 | emax=10, 136 | subnormalize=False, 137 | rounding=ROUND_AWAY_FROM_ZERO, 138 | ), 139 | ] 140 | rounding_contexts = [ 141 | RoundTiesToEven, 142 | RoundTowardPositive, 143 | RoundTowardNegative, 144 | RoundTowardZero, 145 | RoundAwayFromZero, 146 | ] 147 | 148 | for original_context in original_contexts: 149 | for rounding_context in rounding_contexts: 150 | with original_context: 151 | with rounding_context: 152 | self.assertEqual( 153 | getcontext().precision, original_context.precision, 154 | ) 155 | self.assertEqual( 156 | getcontext().emin, original_context.emin, 157 | ) 158 | self.assertEqual( 159 | getcontext().emax, original_context.emax, 160 | ) 161 | self.assertEqual( 162 | getcontext().subnormalize, 163 | original_context.subnormalize, 164 | ) 165 | self.assertEqual( 166 | getcontext().rounding, rounding_context.rounding, 167 | ) 168 | 169 | def test_hashable(self): 170 | # create equal but non-identical contexts 171 | c1 = Context( 172 | emin=-999, 173 | emax=999, 174 | precision=100, 175 | subnormalize=True, 176 | rounding=ROUND_TOWARD_POSITIVE, 177 | ) 178 | c2 = Context( 179 | emax=999, emin=-999, rounding=ROUND_TOWARD_POSITIVE 180 | ) + Context(precision=100, subnormalize=True) 181 | self.assertEqual(hash(c1), hash(c2)) 182 | self.assertEqual(c1, c2) 183 | self.assertIs(c1 == c2, True) 184 | self.assertIs(c1 != c2, False) 185 | 186 | # distinct contexts 187 | d1 = Context( 188 | emin=-999, 189 | emax=999, 190 | precision=100, 191 | subnormalize=True, 192 | rounding=ROUND_TOWARD_POSITIVE, 193 | ) 194 | d2 = Context( 195 | emin=-999, 196 | emax=999, 197 | precision=101, 198 | subnormalize=True, 199 | rounding=ROUND_TOWARD_POSITIVE, 200 | ) 201 | self.assertIs(d1 != d2, True) 202 | self.assertIs(d1 == d2, False) 203 | 204 | def test_with(self): 205 | # check use of contexts in with statements 206 | c = Context( 207 | emin=-123, 208 | emax=456, 209 | precision=1729, 210 | subnormalize=True, 211 | rounding=ROUND_TOWARD_POSITIVE, 212 | ) 213 | d = Context( 214 | emin=0, 215 | emax=10585, 216 | precision=20, 217 | subnormalize=False, 218 | rounding=ROUND_TOWARD_NEGATIVE, 219 | ) 220 | 221 | with c: 222 | # check nested with 223 | with d: 224 | self.assertEqual(getcontext().precision, d.precision) 225 | self.assertEqual(getcontext().emin, d.emin) 226 | self.assertEqual(getcontext().emax, d.emax) 227 | self.assertEqual(getcontext().subnormalize, d.subnormalize) 228 | self.assertEqual(getcontext().rounding, d.rounding) 229 | 230 | # check context is restored on normal exit 231 | self.assertEqual(getcontext().precision, c.precision) 232 | self.assertEqual(getcontext().emin, c.emin) 233 | self.assertEqual(getcontext().emax, c.emax) 234 | self.assertEqual(getcontext().subnormalize, c.subnormalize) 235 | self.assertEqual(getcontext().rounding, c.rounding) 236 | 237 | # check context is restored on abnormal exit, and that exceptions 238 | # raised within the with block are propagated 239 | try: 240 | with d: 241 | raise ValueError 242 | except ValueError: 243 | pass 244 | else: 245 | self.fail("ValueError not propagated from with block") 246 | 247 | self.assertEqual(getcontext().precision, c.precision) 248 | self.assertEqual(getcontext().emin, c.emin) 249 | self.assertEqual(getcontext().emax, c.emax) 250 | self.assertEqual(getcontext().subnormalize, c.subnormalize) 251 | self.assertEqual(getcontext().rounding, c.rounding) 252 | 253 | def test_context_initialised_in_background_thread(self): 254 | # Regression test for mdickinson/bigfloat#78. 255 | 256 | # Timeout for blocking waits, so that a badly written test or 257 | # an unexpected failure mode doesn't cause the whole test suite 258 | # to block. 259 | SAFETY_TIMEOUT = 10.0 260 | 261 | def target(result_queue, precision_changed, continue_event): 262 | # Change the context in a background thread. Put computed 263 | # precisions on a results queue for testing in the main thread. 264 | # We use events to pause execution of the background thread 265 | # so that we can effectively test that the main thread is 266 | # unaffected at that point. 267 | try: 268 | result_queue.put(("PREC", getcontext().precision)) 269 | with precision(20): 270 | result_queue.put(("PREC", getcontext().precision)) 271 | precision_changed.set() 272 | if not continue_event.wait(timeout=SAFETY_TIMEOUT): 273 | raise RuntimeError("continue_event not received") 274 | 275 | result_queue.put(("PREC", getcontext().precision)) 276 | except BaseException as e: 277 | result_queue.put(("EXC", str(e))) 278 | result_queue.put(("DONE",)) 279 | 280 | result_queue = queue.Queue() 281 | precision_changed = threading.Event() 282 | continue_event = threading.Event() 283 | 284 | default_precision = DefaultContext.precision 285 | 286 | self.assertEqual(getcontext().precision, default_precision) 287 | 288 | thread = threading.Thread( 289 | target=target, 290 | args=(result_queue, precision_changed, continue_event), 291 | ) 292 | thread.start() 293 | try: 294 | precision_changed.wait(timeout=SAFETY_TIMEOUT) 295 | # At this point, the precision in the background thread has 296 | # been changed, but our precision should be unaltered. 297 | self.assertEqual(getcontext().precision, default_precision) 298 | continue_event.set() 299 | finally: 300 | thread.join() 301 | 302 | # Collect messages from the background thread. 303 | messages = [] 304 | while True: 305 | message = result_queue.get(timeout=SAFETY_TIMEOUT) 306 | if message[0] == "DONE": 307 | break 308 | messages.append(message) 309 | 310 | self.assertEqual( 311 | messages, 312 | [ 313 | ("PREC", DefaultContext.precision), 314 | ("PREC", 20), 315 | ("PREC", DefaultContext.precision), 316 | ], 317 | ) 318 | 319 | 320 | if __name__ == "__main__": 321 | unittest.main() 322 | -------------------------------------------------------------------------------- /bigfloat/context.py: -------------------------------------------------------------------------------- 1 | # Copyright 2009--2019 Mark Dickinson. 2 | # 3 | # This file is part of the bigfloat package. 4 | # 5 | # The bigfloat package is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU Lesser General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or (at your 8 | # option) any later version. 9 | # 10 | # The bigfloat package is distributed in the hope that it will be useful, but 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 | # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License 13 | # for more details. 14 | # 15 | # You should have received a copy of the GNU Lesser General Public License 16 | # along with the bigfloat package. If not, see . 17 | 18 | import contextlib 19 | import threading 20 | 21 | 22 | import mpfr 23 | 24 | from bigfloat.rounding_mode import ( 25 | RoundingMode, 26 | ROUND_TIES_TO_EVEN, 27 | ROUND_TOWARD_POSITIVE, 28 | ROUND_TOWARD_NEGATIVE, 29 | ROUND_TOWARD_ZERO, 30 | ROUND_AWAY_FROM_ZERO, 31 | ) 32 | 33 | EMAX_MAX = mpfr.MPFR_EMAX_DEFAULT 34 | EMIN_MIN = mpfr.MPFR_EMIN_DEFAULT 35 | 36 | PRECISION_MIN = mpfr.MPFR_PREC_MIN 37 | PRECISION_MAX = mpfr.MPFR_PREC_MAX 38 | 39 | EMAX_MIN = max(mpfr.MPFR_EMIN_DEFAULT, mpfr.mpfr_get_emax_min()) 40 | EMIN_MAX = min(mpfr.MPFR_EMAX_DEFAULT, mpfr.mpfr_get_emin_max()) 41 | 42 | 43 | class Context(object): 44 | """ 45 | Information about output format and rounding mode. 46 | 47 | A context provides information about the output format for a 48 | particular operation (target precision, minimum and maximum 49 | exponents, and whether to use gradual underflow), and the 50 | rounding mode used to round the true result to that format. 51 | 52 | Attributes 53 | ---------- 54 | 'precision' is the precision in bits (for example, 53 for 55 | standard IEEE double precision). 56 | 'subnormalize' is True for formats that have gradual underflow 57 | and False otherwise. 58 | 'emin' is the minimum exponent; for example, -1073 for IEEE 754 59 | double precision 60 | 'emax' is the maximum exponent; for example, 1024 for IEEE 754 61 | double precision. 62 | 'rounding' is the rounding mode. 63 | 64 | Note that exponent values are relative to a significand scaled to have 65 | absolute value in the range [0.5, 1.0), and that ``emin`` takes 66 | the subnormal range into account when ``subnormalize`` is ``True``. 67 | """ 68 | 69 | # Contexts are supposed to be immutable. We make the attributes 70 | # of a Context private, and provide properties to access them in 71 | # order to discourage users from trying to set the attributes 72 | # directly. 73 | 74 | def __new__( 75 | cls, 76 | precision=None, 77 | emin=None, 78 | emax=None, 79 | subnormalize=None, 80 | rounding=None, 81 | ): 82 | if precision is not None and not ( 83 | PRECISION_MIN <= precision <= PRECISION_MAX 84 | ): 85 | raise ValueError( 86 | "Precision p should satisfy %d <= p <= %d." 87 | % (PRECISION_MIN, PRECISION_MAX) 88 | ) 89 | if emin is not None and not EMIN_MIN <= emin <= EMIN_MAX: 90 | raise ValueError( 91 | "exponent bound emin should satisfy " 92 | "%d <= emin <= %d" % (EMIN_MIN, EMIN_MAX) 93 | ) 94 | if emax is not None and not EMAX_MIN <= emax <= EMAX_MAX: 95 | raise ValueError( 96 | "exponent bound emax should satisfy " 97 | "%d <= emax <= %d" % (EMAX_MIN, EMAX_MAX) 98 | ) 99 | if rounding is not None: 100 | rounding = RoundingMode(rounding) 101 | if subnormalize is not None and subnormalize not in [False, True]: 102 | raise ValueError("subnormalize should be either False or True") 103 | self = object.__new__(cls) 104 | self._precision = precision 105 | self._emin = emin 106 | self._emax = emax 107 | self._subnormalize = subnormalize 108 | self._rounding = rounding 109 | return self 110 | 111 | def __add__(self, other): 112 | """For contexts self and other, self + other is a new Context 113 | combining self and other: for attributes that are defined in 114 | both self and other, the attribute from other takes 115 | precedence.""" 116 | 117 | return Context( 118 | precision=( 119 | other.precision 120 | if other.precision is not None 121 | else self.precision 122 | ), 123 | emin=other.emin if other.emin is not None else self.emin, 124 | emax=other.emax if other.emax is not None else self.emax, 125 | subnormalize=( 126 | other.subnormalize 127 | if other.subnormalize is not None 128 | else self.subnormalize 129 | ), 130 | rounding=( 131 | other.rounding if other.rounding is not None else self.rounding 132 | ), 133 | ) 134 | 135 | def __eq__(self, other): 136 | return ( 137 | self.precision == other.precision 138 | and self.emin == other.emin 139 | and self.emax == other.emax 140 | and self.subnormalize == other.subnormalize 141 | and self.rounding == other.rounding 142 | ) 143 | 144 | def __ne__(self, other): 145 | return not (self == other) 146 | 147 | def __hash__(self): 148 | return hash( 149 | ( 150 | self.precision, 151 | self.emin, 152 | self.emax, 153 | self.subnormalize, 154 | self.rounding, 155 | ) 156 | ) 157 | 158 | @property 159 | def precision(self): 160 | return self._precision 161 | 162 | @property 163 | def rounding(self): 164 | return self._rounding 165 | 166 | @property 167 | def emin(self): 168 | return self._emin 169 | 170 | @property 171 | def emax(self): 172 | return self._emax 173 | 174 | @property 175 | def subnormalize(self): 176 | return self._subnormalize 177 | 178 | def __repr__(self): 179 | args = [] 180 | if self.precision is not None: 181 | args.append("precision=%r" % self.precision) 182 | if self.emax is not None: 183 | args.append("emax=%r" % self.emax) 184 | if self.emin is not None: 185 | args.append("emin=%r" % self.emin) 186 | if self.subnormalize is not None: 187 | args.append("subnormalize=%r" % self.subnormalize) 188 | if self.rounding is not None: 189 | args.append("rounding=%r" % self.rounding) 190 | return "Context(%s)" % ", ".join(args) 191 | 192 | __str__ = __repr__ 193 | 194 | def __enter__(self): 195 | _pushcontext(self) 196 | 197 | def __exit__(self, *args): 198 | _popcontext() 199 | 200 | 201 | # some useful contexts 202 | 203 | # DefaultContext is the context that the module always starts with. 204 | DefaultContext = Context( 205 | rounding=ROUND_TIES_TO_EVEN, 206 | precision=113, 207 | emax=16384, 208 | emin=-16493, 209 | subnormalize=True, 210 | ) 211 | 212 | # EmptyContext is useful for situations where a context is 213 | # required, but no change to the current context is desirable 214 | EmptyContext = Context() 215 | 216 | # WideExponentContext has the largest exponent range allowed 217 | # by MPFR; precision and rounding mode are not specified. 218 | WideExponentContext = Context( 219 | emax=EMAX_MAX, emin=EMIN_MIN, subnormalize=False, 220 | ) 221 | 222 | 223 | # thread-local variables: 224 | # __bigfloat_context__: current context 225 | # __context_stack__: context stack, used by with statement 226 | 227 | local = threading.local() 228 | 229 | 230 | def getcontext(_local=local): 231 | """ 232 | Return the current context. 233 | 234 | Also initialises the context the first time it's called in each thread. 235 | 236 | """ 237 | try: 238 | return _local.__bigfloat_context__ 239 | except AttributeError: 240 | context = _local.__bigfloat_context__ = DefaultContext 241 | return context 242 | 243 | 244 | def setcontext(context, _local=local): 245 | """ 246 | Set the current context to that given. 247 | 248 | Attributes provided by ``context`` override those in the current 249 | context. If ``context`` doesn't specify a particular attribute, 250 | the attribute from the current context shows through. 251 | 252 | """ 253 | oldcontext = getcontext() 254 | _local.__bigfloat_context__ = oldcontext + context 255 | 256 | 257 | def _pushcontext(context, _local=local): 258 | try: 259 | context_stack = _local.__context_stack__ 260 | except AttributeError: 261 | context_stack = _local.__context_stack__ = [] 262 | context_stack.append(getcontext()) 263 | setcontext(context) 264 | 265 | 266 | def _popcontext(_local=local): 267 | # It's safe to assume that __context_stack__ is already initialised and 268 | # non-empty here, since any _popcontext call will have been preceded by a 269 | # corresponding _pushcontext call. 270 | setcontext(_local.__context_stack__.pop()) 271 | 272 | 273 | # Don't contaminate the namespace. 274 | del threading, local 275 | 276 | 277 | def precision(prec): 278 | """ 279 | Return context specifying the given precision. 280 | 281 | ``precision(prec)`` is exactly equivalent to ``Context(precision=prec)``. 282 | 283 | """ 284 | return Context(precision=prec) 285 | 286 | 287 | def rounding(rnd): 288 | """ 289 | Return a context giving the specified rounding mode. 290 | 291 | ``rounding(rnd)`` is exactly equivalent to ``Context(rounding=rnd)``. 292 | 293 | """ 294 | return Context(rounding=rnd) 295 | 296 | 297 | def extra_precision(prec): 298 | """ 299 | Return copy of the current context with the precision increased by 300 | ``prec``. Equivalent to ``Context(precision=getcontext().precision + p)``. 301 | 302 | >>> getcontext().precision 303 | 53 304 | >>> extra_precision(10).precision 305 | 63 306 | >>> with extra_precision(20): 307 | ... gamma(1.5) 308 | ... 309 | BigFloat.exact('0.88622692545275801364912', precision=73) 310 | 311 | """ 312 | c = getcontext() 313 | return Context(precision=c.precision + prec) 314 | 315 | 316 | @contextlib.contextmanager 317 | def _temporary_exponent_bounds(emin, emax): 318 | old_emin = mpfr.mpfr_get_emin() 319 | mpfr.mpfr_set_emin(emin) 320 | try: 321 | old_emax = mpfr.mpfr_get_emax() 322 | mpfr.mpfr_set_emax(emax) 323 | try: 324 | yield 325 | finally: 326 | mpfr.mpfr_set_emax(old_emax) 327 | finally: 328 | mpfr.mpfr_set_emin(old_emin) 329 | 330 | 331 | def _apply_function_in_context(cls, f, args, context): 332 | """ Apply an MPFR function 'f' to the given arguments 'args', rounding to 333 | the given context. Returns a new Mpfr object with precision taken from 334 | the current context. 335 | 336 | """ 337 | rounding = context.rounding 338 | bf = mpfr.Mpfr_t.__new__(cls) 339 | mpfr.mpfr_init2(bf, context.precision) 340 | args = (bf,) + args + (rounding,) 341 | ternary = f(*args) 342 | with _temporary_exponent_bounds(context.emin, context.emax): 343 | ternary = mpfr.mpfr_check_range(bf, ternary, rounding) 344 | if context.subnormalize: 345 | # mpfr_subnormalize doesn't set underflow and 346 | # subnormal flags, so we do that ourselves. We choose 347 | # to set the underflow flag for *all* cases where the 348 | # 'after rounding' result is smaller than the smallest 349 | # normal number, even if that result is exact. 350 | 351 | # if bf is zero but ternary is nonzero, the underflow 352 | # flag will already have been set by mpfr_check_range; 353 | underflow = ( 354 | mpfr.mpfr_number_p(bf) 355 | and not mpfr.mpfr_zero_p(bf) 356 | and ( 357 | mpfr.mpfr_get_exp(bf) 358 | < context.precision - 1 + context.emin 359 | ) 360 | ) 361 | if underflow: 362 | mpfr.mpfr_set_underflow() 363 | ternary = mpfr.mpfr_subnormalize(bf, ternary, rounding) 364 | if ternary: 365 | mpfr.mpfr_set_inexflag() 366 | return bf 367 | 368 | 369 | def _apply_function_in_current_context(cls, f, args, context): 370 | with (context if context is not None else EmptyContext): 371 | return _apply_function_in_context(cls, f, args, getcontext()) 372 | 373 | 374 | # provided rounding modes are implemented as contexts, so that 375 | # they can be used directly in with statements 376 | RoundTiesToEven = rounding(ROUND_TIES_TO_EVEN) 377 | RoundTowardPositive = rounding(ROUND_TOWARD_POSITIVE) 378 | RoundTowardNegative = rounding(ROUND_TOWARD_NEGATIVE) 379 | RoundTowardZero = rounding(ROUND_TOWARD_ZERO) 380 | RoundAwayFromZero = rounding(ROUND_AWAY_FROM_ZERO) 381 | -------------------------------------------------------------------------------- /bigfloat/test/test_formatting.py: -------------------------------------------------------------------------------- 1 | # Copyright 2009--2019 Mark Dickinson. 2 | # 3 | # This file is part of the bigfloat package. 4 | # 5 | # The bigfloat package is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU Lesser General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or (at your 8 | # option) any later version. 9 | # 10 | # The bigfloat package is distributed in the hope that it will be useful, but 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 | # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License 13 | # for more details. 14 | # 15 | # You should have received a copy of the GNU Lesser General Public License 16 | # along with the bigfloat package. If not, see . 17 | 18 | import unittest 19 | 20 | from bigfloat import ( 21 | BigFloat, 22 | double_precision, 23 | RoundTiesToEven, 24 | getcontext, 25 | setcontext, 26 | ) 27 | 28 | 29 | DefaultTestContext = double_precision + RoundTiesToEven 30 | 31 | 32 | class TestFormatting(unittest.TestCase): 33 | def setUp(self): 34 | self._original_context = getcontext() 35 | setcontext(DefaultTestContext) 36 | 37 | def tearDown(self): 38 | setcontext(self._original_context) 39 | del self._original_context 40 | 41 | def test_format(self): 42 | # Fixed precision formatting. 43 | test_triples = [ 44 | (BigFloat(2), ".6f", "2.000000"), 45 | # 'F' behaves the same as 'f' except for infinities and nans. 46 | (BigFloat(2), ".6F", "2.000000"), 47 | # Extra zeros in the precision should be fine. 48 | (BigFloat(2), ".06f", "2.000000"), 49 | (BigFloat(2), ".5f", "2.00000"), 50 | # . only retained with 'alternate' formatting 51 | (BigFloat(2), ".0f", "2"), 52 | # Default precision is 6. 53 | (BigFloat(2), "f", "2.000000"), 54 | (BigFloat("nan"), "f", "nan"), 55 | (BigFloat("-nan"), "f", "nan"), 56 | (BigFloat("inf"), "f", "inf"), 57 | (BigFloat("-inf"), "f", "-inf"), 58 | (BigFloat("nan"), "F", "NAN"), 59 | (BigFloat("-nan"), "F", "NAN"), 60 | (BigFloat("inf"), "F", "INF"), 61 | (BigFloat("-inf"), "F", "-INF"), 62 | # Rounding behaviour. 63 | (BigFloat("3.1415926535"), ".6f", "3.141593"), 64 | (BigFloat("3.1415926535"), ".5f", "3.14159"), 65 | (BigFloat("3.1415926535"), ".4f", "3.1416"), 66 | (BigFloat("3.1415926535"), ".3f", "3.142"), 67 | (BigFloat("3.1415926535"), ".2f", "3.14"), 68 | (BigFloat("3.1415926535"), ".1f", "3.1"), 69 | (BigFloat("3.1415926535"), ".0f", "3"), 70 | # Sign specification. 71 | (BigFloat(+2), "+.3f", "+2.000"), 72 | (BigFloat(-2), "+.3f", "-2.000"), 73 | (BigFloat(+2), " .3f", " 2.000"), 74 | (BigFloat(-2), " .3f", "-2.000"), 75 | (BigFloat(+2), "-.3f", "2.000"), 76 | (BigFloat(-2), "-.3f", "-2.000"), 77 | (BigFloat(+2), ".3f", "2.000"), 78 | (BigFloat(-2), ".3f", "-2.000"), 79 | # With infinities and nans; note that MPFR doesn't include 80 | # these signs. 81 | (BigFloat("+inf"), "+.3f", "+inf"), 82 | (BigFloat("-inf"), "+.3f", "-inf"), 83 | (BigFloat("+nan"), "+.3f", "+nan"), 84 | (BigFloat("+inf"), "-.3f", "inf"), 85 | (BigFloat("-inf"), "-.3f", "-inf"), 86 | (BigFloat("+nan"), "-.3f", "nan"), 87 | (BigFloat("+inf"), " .3f", " inf"), 88 | (BigFloat("-inf"), " .3f", "-inf"), 89 | (BigFloat("+nan"), " .3f", " nan"), 90 | # Alternate formatting. 91 | (BigFloat(2), "#.0f", "2."), 92 | (BigFloat(2), "+#.0f", "+2."), 93 | # Minimum field width. 94 | (BigFloat(2), "10.3f", " 2.000"), 95 | (BigFloat(2), "6.3f", " 2.000"), 96 | (BigFloat(2), "5.3f", "2.000"), 97 | (BigFloat(2), "4.3f", "2.000"), 98 | (BigFloat(2), "1.3f", "2.000"), 99 | # Minimum field width in combination with sign. 100 | (BigFloat(2), "+10.3f", " +2.000"), 101 | (BigFloat(-23), "+10.3f", " -23.000"), 102 | # Zero padding. 103 | (BigFloat(2), "010.3f", "000002.000"), 104 | (BigFloat(2), "+010.3f", "+00002.000"), 105 | (BigFloat(2), " 010.3f", " 00002.000"), 106 | (BigFloat(2), "0010.3f", "000002.000"), 107 | # Alignment and filling. 108 | (BigFloat(2), "<10.3f", "2.000 "), 109 | (BigFloat(2), ">10.3f", " 2.000"), 110 | (BigFloat(2), "^10.3f", " 2.000 "), 111 | (BigFloat(2), "<10.2f", "2.00 "), 112 | (BigFloat(2), ">10.2f", " 2.00"), 113 | (BigFloat(2), "^10.2f", " 2.00 "), 114 | (BigFloat(2), "<4.2f", "2.00"), 115 | (BigFloat(2), ">4.2f", "2.00"), 116 | (BigFloat(2), "^4.2f", "2.00"), 117 | (BigFloat(2), "<3.2f", "2.00"), 118 | (BigFloat(2), ">3.2f", "2.00"), 119 | (BigFloat(2), "^3.2f", "2.00"), 120 | (BigFloat(2), "X<10.3f", "2.000XXXXX"), 121 | (BigFloat(2), "X>10.3f", "XXXXX2.000"), 122 | (BigFloat(2), "X^10.3f", "XX2.000XXX"), 123 | (BigFloat(2), "X<10.2f", "2.00XXXXXX"), 124 | (BigFloat(2), "X>10.2f", "XXXXXX2.00"), 125 | (BigFloat(2), "X^10.2f", "XXX2.00XXX"), 126 | (BigFloat(2), "X<4.2f", "2.00"), 127 | (BigFloat(2), "X>4.2f", "2.00"), 128 | (BigFloat(2), "X^4.2f", "2.00"), 129 | (BigFloat(2), "X<3.2f", "2.00"), 130 | (BigFloat(2), "X>3.2f", "2.00"), 131 | (BigFloat(2), "X^3.2f", "2.00"), 132 | (BigFloat(2), "X=+10.3f", "+XXXX2.000"), 133 | (BigFloat(2), " =+10.3f", "+ 2.000"), 134 | (BigFloat(2), "0=+10.3f", "+00002.000"), 135 | (BigFloat(2), "\x00=+10.3f", "+\x00\x00\x00\x002.000"), 136 | (BigFloat(2), "\n=+10.3f", "+\n\n\n\n2.000"), 137 | # e-style formatting 138 | (BigFloat(2), ".6e", "2.000000e+00"), 139 | (BigFloat(3.141592653589793), ".6e", "3.141593e+00"), 140 | (BigFloat(3.141592653589793), ".6E", "3.141593E+00"), 141 | (BigFloat(314.1592653589793), ".6e", "3.141593e+02"), 142 | (BigFloat(314.1592653589793), ".6E", "3.141593E+02"), 143 | (BigFloat("nan"), "e", "nan"), 144 | (BigFloat("-nan"), "e", "nan"), 145 | (BigFloat("inf"), "e", "inf"), 146 | (BigFloat("-inf"), "e", "-inf"), 147 | (BigFloat("nan"), "E", "NAN"), 148 | (BigFloat("-nan"), "E", "NAN"), 149 | (BigFloat("inf"), "E", "INF"), 150 | (BigFloat("-inf"), "E", "-INF"), 151 | (BigFloat(314.1592653589793), ".0e", "3e+02"), 152 | (BigFloat(314.1592653589793), "#.0e", "3.e+02"), 153 | (BigFloat(314.1592653589793), "e", "3.1415926535897933e+02"), 154 | (BigFloat(314.1592653589793), "6e", "3.1415926535897933e+02"), 155 | # g-style formatting 156 | (BigFloat(3.141592653589793), ".7g", "3.141593"), 157 | (BigFloat(3.141592653589793), ".7G", "3.141593"), 158 | (BigFloat(314.1592653589793), ".7g", "314.1593"), 159 | (BigFloat(31415.92653589793), ".7g", "31415.93"), 160 | (BigFloat(3141592.653589793), ".7g", "3141593"), 161 | (BigFloat(3141592.653589793), ".7G", "3141593"), 162 | (BigFloat(31415926.53589793), ".7g", "3.141593e+07"), 163 | (BigFloat(31415926.53589793), ".7G", "3.141593E+07"), 164 | (BigFloat("nan"), "g", "nan"), 165 | (BigFloat("-nan"), "g", "nan"), 166 | (BigFloat("inf"), "g", "inf"), 167 | (BigFloat("-inf"), "g", "-inf"), 168 | (BigFloat("nan"), "G", "NAN"), 169 | (BigFloat("-nan"), "G", "NAN"), 170 | (BigFloat("inf"), "G", "INF"), 171 | (BigFloat("-inf"), "G", "-INF"), 172 | (BigFloat(314.1592653589793), ".0g", "3e+02"), 173 | (BigFloat(314.1592653589793), ".1g", "3e+02"), 174 | (BigFloat(314.1592653589793), "#.0g", "3.e+02"), 175 | (BigFloat(314.1592653589793), "#.1g", "3.e+02"), 176 | (BigFloat(314.1592653589793), "g", "314.159"), 177 | (BigFloat(314.1592653589793), "6g", "314.159"), 178 | # Trailing zeros are stripped, except in alternate style. 179 | (BigFloat(2), ".6g", "2"), 180 | (BigFloat(0.000023), ".6g", "2.3e-05"), 181 | (BigFloat(0.00023), ".6g", "0.00023"), 182 | (BigFloat(2.3), ".6g", "2.3"), 183 | (BigFloat(230), ".6g", "230"), 184 | (BigFloat(230000), ".6g", "230000"), 185 | (BigFloat(2300000), ".6g", "2.3e+06"), 186 | (BigFloat(2), "#.6g", "2.00000"), 187 | # %-formatting 188 | (BigFloat(3.141592653589793), ".2%", "314.16%"), 189 | (BigFloat(3.141592653589793), ".1%", "314.2%"), 190 | (BigFloat(3.141592653589793), ".0%", "314%"), 191 | (BigFloat(3.141592653589793), "%", "314.159265%"), 192 | (BigFloat(0.0234), ".3%", "2.340%"), 193 | (BigFloat(0.00234), ".3%", "0.234%"), 194 | (BigFloat(0.000234), ".3%", "0.023%"), 195 | (BigFloat(0.000234), ".3U%", "0.024%"), 196 | (BigFloat(0.0000234), ".3%", "0.002%"), 197 | (BigFloat(0.00000234), ".3%", "0.000%"), 198 | (BigFloat(0.00000234), ".3Y%", "0.001%"), 199 | (BigFloat(-3.141592653589793), ".2%", "-314.16%"), 200 | (BigFloat(-3.141592653589793), ".1%", "-314.2%"), 201 | (BigFloat(-3.141592653589793), ".0%", "-314%"), 202 | (BigFloat(-3.141592653589793), "%", "-314.159265%"), 203 | (BigFloat(-0.0234), ".3%", "-2.340%"), 204 | (BigFloat(-0.00234), ".3%", "-0.234%"), 205 | (BigFloat(-0.000234), ".3%", "-0.023%"), 206 | (BigFloat(-0.000234), ".3U%", "-0.023%"), 207 | (BigFloat(-0.0000234), ".3%", "-0.002%"), 208 | (BigFloat(-0.00000234), ".3%", "-0.000%"), 209 | (BigFloat(-0.00000234), ".3Y%", "-0.001%"), 210 | (BigFloat("0"), ".3%", "0.000%"), 211 | (BigFloat("-0"), ".3%", "-0.000%"), 212 | # We should see the '%' even on infinities and nans. 213 | (BigFloat("inf"), ".3%", "inf%"), 214 | (BigFloat("-inf"), ".3%", "-inf%"), 215 | (BigFloat("nan"), ".3%", "nan%"), 216 | (BigFloat("inf"), "+.3%", "+inf%"), 217 | (BigFloat("-inf"), "+.3%", "-inf%"), 218 | (BigFloat("nan"), "+.3%", "+nan%"), 219 | # Hexadecimal formatting. It's not 100% clear how MPFR 220 | # chooses the exponent here. 221 | (BigFloat(1.5), ".6a", "0x1.800000p+0"), 222 | (BigFloat(1.5), ".5a", "0x1.80000p+0"), 223 | (BigFloat(1.5), ".1a", "0x1.8p+0"), 224 | (BigFloat(1.5), ".0a", "0xcp-3"), 225 | (BigFloat(1.5), ".6A", "0X1.800000P+0"), 226 | (BigFloat(3.0), ".6a", "0x3.000000p+0"), 227 | (BigFloat(3.141592653589793), ".6a", "0x3.243f6bp+0"), 228 | (BigFloat(3.141592653589793), ".5a", "0x3.243f7p+0"), 229 | (BigFloat(3.141592653589793), ".4a", "0x3.243fp+0"), 230 | (BigFloat(3.141592653589793), ".3a", "0x3.244p+0"), 231 | (BigFloat(3.141592653589793), ".2a", "0x3.24p+0"), 232 | (BigFloat(3.141592653589793), ".1a", "0x3.2p+0"), 233 | (BigFloat(3.141592653589793), ".0a", "0xdp-2"), 234 | # With no precision, outputs enough digits to give an 235 | # exact representation. 236 | (BigFloat(3.141592653589793), "a", "0x3.243f6a8885a3p+0"), 237 | (BigFloat(10.0), ".6a", "0xa.000000p+0"), 238 | (BigFloat(16.0), ".6a", "0x1.000000p+4"), 239 | (BigFloat("nan"), "a", "nan"), 240 | (BigFloat("-nan"), "a", "nan"), 241 | (BigFloat("inf"), "a", "inf"), 242 | (BigFloat("-inf"), "a", "-inf"), 243 | (BigFloat("nan"), "A", "NAN"), 244 | (BigFloat("-nan"), "A", "NAN"), 245 | (BigFloat("inf"), "A", "INF"), 246 | (BigFloat("-inf"), "A", "-INF"), 247 | # Binary formatting. 248 | (BigFloat("2.25"), "b", "1.001p+1"), 249 | (BigFloat("-2.25"), "b", "-1.001p+1"), 250 | (BigFloat("nan"), "b", "nan"), 251 | (BigFloat("inf"), "b", "inf"), 252 | (BigFloat("-inf"), "b", "-inf"), 253 | # Rounding mode. 254 | # Round up. 255 | (BigFloat("-56.127"), ".2Uf", "-56.12"), 256 | (BigFloat("-56.125"), ".2Uf", "-56.12"), 257 | (BigFloat("-56.123"), ".2Uf", "-56.12"), 258 | (BigFloat("56.123"), ".2Uf", "56.13"), 259 | (BigFloat("56.125"), ".2Uf", "56.13"), 260 | (BigFloat("56.127"), ".2Uf", "56.13"), 261 | # Round down. 262 | (BigFloat("-56.127"), ".2Df", "-56.13"), 263 | (BigFloat("-56.125"), ".2Df", "-56.13"), 264 | (BigFloat("-56.123"), ".2Df", "-56.13"), 265 | (BigFloat("56.123"), ".2Df", "56.12"), 266 | (BigFloat("56.125"), ".2Df", "56.12"), 267 | (BigFloat("56.127"), ".2Df", "56.12"), 268 | # Round away from zero. 269 | (BigFloat("-56.127"), ".2Yf", "-56.13"), 270 | (BigFloat("-56.125"), ".2Yf", "-56.13"), 271 | (BigFloat("-56.123"), ".2Yf", "-56.13"), 272 | (BigFloat("56.123"), ".2Yf", "56.13"), 273 | (BigFloat("56.125"), ".2Yf", "56.13"), 274 | (BigFloat("56.127"), ".2Yf", "56.13"), 275 | # Round toward zero. 276 | (BigFloat("-56.127"), ".2Zf", "-56.12"), 277 | (BigFloat("-56.125"), ".2Zf", "-56.12"), 278 | (BigFloat("-56.123"), ".2Zf", "-56.12"), 279 | (BigFloat("56.123"), ".2Zf", "56.12"), 280 | (BigFloat("56.125"), ".2Zf", "56.12"), 281 | (BigFloat("56.127"), ".2Zf", "56.12"), 282 | # Round to nearest (ties to even). 283 | (BigFloat("-56.127"), ".2Nf", "-56.13"), 284 | (BigFloat("-56.125"), ".2Nf", "-56.12"), 285 | (BigFloat("-56.123"), ".2Nf", "-56.12"), 286 | (BigFloat("56.123"), ".2Nf", "56.12"), 287 | (BigFloat("56.125"), ".2Nf", "56.12"), 288 | (BigFloat("56.127"), ".2Nf", "56.13"), 289 | # Missing rounding mode implies round to nearest. 290 | (BigFloat("-56.127"), ".2f", "-56.13"), 291 | (BigFloat("-56.125"), ".2f", "-56.12"), 292 | (BigFloat("-56.123"), ".2f", "-56.12"), 293 | (BigFloat("56.123"), ".2f", "56.12"), 294 | (BigFloat("56.125"), ".2f", "56.12"), 295 | (BigFloat("56.127"), ".2f", "56.13"), 296 | # Missing type behaves like str formatting. 297 | (BigFloat("123"), ".0", "1e+02"), 298 | (BigFloat("123"), ".1", "1e+02"), 299 | (BigFloat("123"), ".2", "1.2e+02"), 300 | (BigFloat("123"), ".2U", "1.3e+02"), 301 | (BigFloat("123"), ".2D", "1.2e+02"), 302 | (BigFloat("123"), ".3", "123"), 303 | # 'alternate' flag is currently ignored. 304 | (BigFloat("123"), "#.3", "123"), 305 | (BigFloat("123"), ".4", "123.0"), 306 | (BigFloat("123"), "#.4", "123.0"), 307 | (BigFloat("123"), ".0", "1e+02"), 308 | (BigFloat("123"), "", "123.00000000000000"), 309 | (BigFloat("nan"), "", "nan"), 310 | (BigFloat("inf"), "", "inf"), 311 | (BigFloat("-inf"), "", "-inf"), 312 | ] 313 | for bf, fmt, expected_output in test_triples: 314 | result = format(bf, fmt) 315 | self.assertEqual( 316 | result, expected_output, msg=(bf, fmt, expected_output) 317 | ) 318 | 319 | def test_empty_format_matches_str(self): 320 | test_values = [ 321 | BigFloat("0.0"), 322 | BigFloat("-0.0"), 323 | BigFloat("1.0"), 324 | BigFloat("-2.3"), 325 | BigFloat("1e100"), 326 | BigFloat("1e-100"), 327 | BigFloat("nan"), 328 | BigFloat("inf"), 329 | BigFloat("-inf"), 330 | ] 331 | for value in test_values: 332 | self.assertEqual(str(value), format(value, "")) 333 | 334 | def test_invalid_formats(self): 335 | invalid_formats = [ 336 | # Can't specify fill/align *and* zero padding at once ... 337 | "X<010.2f", 338 | ">010.2f", 339 | " ^010.2f", 340 | "=010.2f", 341 | # ... even if the fill/align matches the zero padding! 342 | "0=010.2f", 343 | # a . must be followed by a precision. 344 | ".f", 345 | "10.g", 346 | ] 347 | for fmt in invalid_formats: 348 | with self.assertRaises(ValueError): 349 | format(BigFloat(2), fmt) 350 | -------------------------------------------------------------------------------- /docs/source/tutorial/index.rst: -------------------------------------------------------------------------------- 1 | Tutorial 2 | -------- 3 | 4 | .. currentmodule:: bigfloat 5 | 6 | Start by importing the contents of the package with: 7 | 8 | >>> from bigfloat import * 9 | 10 | You should be a little bit careful here: this import brings a fairly large 11 | number of functions into the current namespace, some of which shadow existing 12 | Python builtins, namely :func:`abs`, :func:`max`, :func:`min`, :func:`pow`, 13 | :func:`round`, :func:`sum`, and (on Python 2 only) :func:`cmp`. In normal 14 | usage you'll probably only want to import the classes and functions that you 15 | actually need. 16 | 17 | 18 | :class:`BigFloat` construction 19 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 20 | 21 | The main type of interest is the :class:`BigFloat` class. The 22 | :class:`BigFloat` type is an immutable binary floating-point type. A 23 | :class:`BigFloat` instance can be created from an integer, a float or 24 | a string: 25 | 26 | >>> BigFloat(123) 27 | BigFloat.exact('123.000000000000000000000000000000000', precision=113) 28 | >>> BigFloat("-4.56") 29 | BigFloat.exact('-4.55999999999999999999999999999999966', precision=113) 30 | 31 | Each :class:`BigFloat` instance has both a *value* and a *precision*. 32 | The precision gives the number of bits used to store the significand 33 | of the :class:`BigFloat`. The *value* of a finite nonzero 34 | :class:`BigFloat` with precision ``p`` is a real number of the form 35 | ``(-1)**s * m * 2**e``, where the *sign* ``s`` is either ``0`` or 36 | ``1``, the *significand* ``m`` is a number in the half-open interval 37 | [0.5, 1.0) that can be expressed in the form ``n/2**p`` for some 38 | integer ``n``, and ``e`` is an integer giving the *exponent*. In 39 | addition, zeros (positive and negative), infinities and NaNs are 40 | representable. Just like Python floats, the printed form of a 41 | :class:`BigFloat` shows only a decimal approximation to the exact 42 | stored value, for the benefit of human readers. 43 | 44 | The precision of a newly-constructed :class:`BigFloat` instance is 45 | dictated by the *current precision*, which defaults to ``113`` (the precision 46 | of the IEEE 754 "binary128" format, a.k.a. quadruple precision). This 47 | setting can be overridden by supplying the ``context`` keyword 48 | argument to the constructor: 49 | 50 | >>> BigFloat(-4.56, context=precision(24)) 51 | BigFloat.exact('-4.55999994', precision=24) 52 | 53 | The first argument to the :class:`BigFloat` constructor is rounded to 54 | the correct precision using the *current rounding mode*, which 55 | defaults to :data:`RoundTiesToEven`; again, this can be overridden with 56 | the ``context`` keyword argument: 57 | 58 | >>> BigFloat('3.14') 59 | BigFloat.exact('3.14000000000000000000000000000000011', precision=113) 60 | >>> BigFloat('3.14', context=RoundTowardZero) 61 | BigFloat.exact('3.13999999999999999999999999999999972', precision=113) 62 | >>> BigFloat('3.14', context=RoundTowardPositive + precision(24)) 63 | BigFloat.exact('3.14000010', precision=24) 64 | 65 | More generally, the second argument to the :class:`BigFloat` constructor can be 66 | any instance of the :class:`Context` class. The various rounding modes are all 67 | :class:`Context` instances, and :func:`precision` is a function returning a 68 | :class:`Context`: 69 | 70 | >>> RoundTowardNegative 71 | Context(rounding=ROUND_TOWARD_NEGATIVE) 72 | >>> precision(1000) 73 | Context(precision=1000) 74 | 75 | :class:`Context` instances can be combined by addition, as seen above. 76 | 77 | >>> precision(1000) + RoundTowardNegative 78 | Context(precision=1000, rounding=ROUND_TOWARD_NEGATIVE) 79 | 80 | When adding two contexts that both specify values for a particular 81 | attribute, the value for the right-hand addend takes precedence:: 82 | 83 | >>> c = Context(subnormalize=False, rounding=ROUND_TOWARD_POSITIVE) 84 | >>> double_precision 85 | Context(precision=53, emax=1024, emin=-1073, subnormalize=True) 86 | >>> double_precision + c 87 | Context(precision=53, emax=1024, emin=-1073, subnormalize=False, 88 | rounding=ROUND_TOWARD_POSITIVE) 89 | >>> c + double_precision 90 | Context(precision=53, emax=1024, emin=-1073, subnormalize=True, 91 | rounding=ROUND_TOWARD_POSITIVE) 92 | 93 | The :mod:`bigfloat` package also defines various constant :class:`Context` 94 | instances. For example, :data:`quadruple_precision` is a :class:`Context` 95 | object that corresponds to the IEEE 754 binary128 interchange format:: 96 | 97 | >>> quadruple_precision 98 | Context(precision=113, emax=16384, emin=-16493, subnormalize=True) 99 | >>> BigFloat('1.1', quadruple_precision) 100 | BigFloat.exact('1.10000000000000000000000000000000008', precision=113) 101 | 102 | The current settings for precision and rounding mode are given by the 103 | :ref:`current context `, accessible via the :func:`getcontext` 104 | function: 105 | 106 | >>> getcontext() 107 | Context(precision=113, emax=16384, emin=-16493, subnormalize=True, 108 | rounding=ROUND_TIES_TO_EVEN) 109 | 110 | There's also a :func:`setcontext` function for changing the current 111 | context; however, the preferred method for making temporary changes to 112 | the current context is to use Python's with statement. More on this below. 113 | 114 | Note that (in contrast to Python's standard library :mod:`decimal` module), 115 | :class:`Context` instances are immutable. 116 | 117 | There's a second method for constructing :class:`BigFloat` 118 | instances: :meth:`BigFloat.exact`. Just like the usual constructor, 119 | :meth:`BigFloat.exact` accepts integers, floats and strings. However, 120 | for integers and floats it performs an exact conversion, creating a 121 | :class:`BigFloat` instance with precision large enough to hold the 122 | integer or float exactly (regardless of the current precision 123 | setting): 124 | 125 | >>> BigFloat.exact(-123) 126 | BigFloat.exact('-123.0', precision=7) 127 | >>> BigFloat.exact(7**30) 128 | BigFloat.exact('22539340290692258087863249.0', precision=85) 129 | >>> BigFloat.exact(-56.7) 130 | BigFloat.exact('-56.700000000000003', precision=53) 131 | 132 | For strings, :meth:`BigFloat.exact` accepts a second ``precision`` argument, 133 | and always rounds using the :data:`ROUND_TIES_TO_EVEN` rounding mode. 134 | 135 | >>> BigFloat.exact('1.1', precision=80) 136 | BigFloat.exact('1.1000000000000000000000003', precision=80) 137 | 138 | The result of a call to :meth:`BigFloat.exact` is independent of the current 139 | context; this is why the :func:`repr` of a :class:`BigFloat` is expressed in 140 | terms of :meth:`BigFloat.exact`. The :class:`str` of a :class:`BigFloat` looks 141 | prettier, but doesn't supply enough information to recover that 142 | :class:`BigFloat` exactly if you don't know the precision: 143 | 144 | >>> print(BigFloat('1e1000', precision(20))) 145 | 9.9999988e+999 146 | >>> print(BigFloat('1e1000', precision(21))) 147 | 9.9999988e+999 148 | 149 | Arithmetic on :class:`BigFloat` instances 150 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 151 | 152 | All the usual arithmetic operations apply to :class:`BigFloat` instances, and 153 | those instances can be freely mixed with integers and floats (but not strings!) 154 | in those operations: 155 | 156 | >>> BigFloat(1234)/3 157 | BigFloat.exact('411.333333333333333333333333333333317', precision=113) 158 | >>> BigFloat('1e1233')**0.5 159 | BigFloat.exact('3.16227766016837933199889354443271851e+616', precision=113) 160 | 161 | As with the :class:`BigFloat` constructor, the precision for the result is 162 | taken from the current context, as is the rounding mode used to round 163 | the exact mathematical result to the nearest :class:`BigFloat`. 164 | 165 | For mixed-type operations, the integer or float is converted *exactly* 166 | to a :class:`BigFloat` before the operation (as though the 167 | :meth:`BigFloat.exact` constructor had been applied to it). So 168 | there's only a single point where precision might be lost: namely, 169 | when the result of the operation is rounded to the nearest value 170 | representable as a :class:`BigFloat`. 171 | 172 | .. note:: 173 | 174 | The current precision and rounding mode even apply to the unary 175 | plus and minus operations. In particular, ``+x`` is not 176 | necessarily a no-op for a :class:`BigFloat` instance x: 177 | 178 | >>> BigFloat.exact(7**100) 179 | BigFloat.exact('323447650962475799134464776910021681085720319890462540093389 180 | 5331391691459636928060001.0', precision=281) 181 | >>> +BigFloat.exact(7**100) 182 | BigFloat.exact('3.23447650962475799134464776910021692e+84', precision=113) 183 | 184 | This makes the unary plus operator useful as a way to round a 185 | result produced in a different context to the current context. 186 | 187 | For each arithmetic operation the :mod:`bigfloat` package exports a 188 | corresponding function. For example, the :func:`div` function 189 | corresponds to usual (true) division: 190 | 191 | >>> 355/BigFloat(113) 192 | BigFloat.exact('3.14159292035398230088495575221238935', precision=113) 193 | >>> div(355, 113) 194 | BigFloat.exact('3.14159292035398230088495575221238935', precision=113) 195 | 196 | This is useful for a couple of reasons: one reason is that it makes it 197 | possible to use ``div(x, y)`` in contexts where a :class:`BigFloat` result is 198 | desired but where one or both of ``x`` and ``y`` might be an integer or float. 199 | But a more important reason is that these functions, like the :class:`BigFloat` 200 | constructor, accept an extra ``context`` keyword argument giving a 201 | context for the operation:: 202 | 203 | >>> div(355, 113, context=single_precision) 204 | BigFloat.exact('3.14159298', precision=24) 205 | 206 | Similarly, the :func:`sub` function corresponds to Python's subtraction 207 | operation. To fully appreciate some of the subtleties of the ways 208 | that binary arithmetic operations might be performed, note the 209 | difference in the results of the following: 210 | 211 | >>> x = 10**16+1 # integer, not exactly representable as a float 212 | >>> y = 10**16. # 10.**16 is exactly representable as a float 213 | >>> x - y 214 | 0.0 215 | >>> BigFloat(x, double_precision) - BigFloat(y, double_precision) 216 | BigFloat.exact('0', precision=53) 217 | >>> sub(x, y, double_precision) 218 | BigFloat.exact('1.0000000000000000', precision=53) 219 | 220 | For the first subtraction, the integer is first converted to a float, 221 | losing accuracy, and then the subtraction is performed, giving a 222 | result of 0.0. The second case is similar: ``x`` and ``y`` are both 223 | explicitly converted to :class:`BigFloat` instances, and the conversion of 224 | ``x`` again loses precision. In the third case, ``x`` and ``y`` are 225 | *implicitly* converted to :class:`BigFloat` instances, and that conversion is 226 | exact, so the subtraction produces exactly the right answer. 227 | 228 | Comparisons between :class:`BigFloat` instances and integers or floats also 229 | behave as you'd expect them to; for these, there's no need for a 230 | corresponding function. 231 | 232 | Mathematical functions 233 | ^^^^^^^^^^^^^^^^^^^^^^ 234 | 235 | The :mod:`bigfloat` package provides a number of standard mathematical 236 | functions. These functions follow the same rules as the arithmetic 237 | operations above: 238 | 239 | - the arguments can be integers, floats or :class:`BigFloat` instances 240 | 241 | - integers and float arguments are converted exactly to :class:`BigFloat` 242 | instances before the function is applied 243 | 244 | - the result is a :class:`BigFloat` instance, with the precision of 245 | the result, and the rounding mode used to obtain the result, taken 246 | from the current context. 247 | 248 | - attributes of the current context can be overridden by providing 249 | an additional ``context`` keyword argument. 250 | 251 | Here are some examples:: 252 | 253 | >>> sqrt(1729, context=RoundTowardZero) 254 | BigFloat.exact('41.5812457725835818902802091854716460', precision=113) 255 | >>> sqrt(1729, context=RoundTowardPositive) 256 | BigFloat.exact('41.5812457725835818902802091854716521', precision=113) 257 | >>> atanh(0.5, context=precision(20)) 258 | BigFloat.exact('0.54930592', precision=20) 259 | >>> const_catalan(precision(1000)) 260 | BigFloat.exact('0.9159655941772190150546035149323841107741493742816721342664 261 | 9811962176301977625476947935651292611510624857442261919619957903589880332585 262 | 9059431594737481158406995332028773319460519038727478164087865909024706484152 263 | 1630002287276409423882599577415088163974702524820115607076448838078733704899 264 | 00864775113226027', precision=1000) 265 | >>> 4*exp(-const_pi()/2/agm(1, pow(10, -100))) 266 | BigFloat.exact('1.00000000000000000000000000000000730e-100', precision=113) 267 | 268 | For a full list of the supported functions, see the :ref:`standard functions` 269 | section of the :ref:`api reference`. 270 | 271 | Controlling the precision and rounding mode 272 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 273 | 274 | We've seen one way of controlling precision and rounding mode, via the 275 | ``context`` keyword argument. There's another way that's often more 276 | convenient, especially when a single context change is supposed to apply to 277 | multiple operations: contexts can be used directly in Python's :ref:`with 278 | ` statement. 279 | 280 | For example, here we compute high-precision upper and lower-bounds for 281 | the thousandth harmonic number: 282 | 283 | >>> with precision(100): 284 | ... with RoundTowardNegative: # lower bound 285 | ... lower_bound = sum(div(1, n) for n in range(1, 1001)) 286 | ... with RoundTowardPositive: # upper bound 287 | ... upper_bound = sum(div(1, n) for n in range(1, 1001)) 288 | ... 289 | >>> lower_bound 290 | BigFloat.exact('7.4854708605503449126565182015873', precision=100) 291 | >>> upper_bound 292 | BigFloat.exact('7.4854708605503449126565182077593', precision=100) 293 | 294 | The effect of the with statement is to change the current context for 295 | the duration of the with block; when the block exits, the previous 296 | context is restored. With statements can be nested, as seen above. 297 | Let's double-check the above results using the asymptotic formula for 298 | the nth harmonic number [#harmonic]_: 299 | 300 | >>> n = 1000 301 | >>> with precision(100): 302 | ... approx = log(n) + const_euler() + div(1, 2*n) - 1/(12*sqr(n)) 303 | ... 304 | >>> approx 305 | BigFloat.exact('7.4854708605503365793271531207983', precision=100) 306 | 307 | The error in this approximation should be approximately -1/(120*n**4). 308 | Let's check it: 309 | 310 | >>> error = approx - lower_bound 311 | >>> error 312 | BigFloat.exact('-8.33332936508078900174283813097652403e-15', precision=113) 313 | >>> -1/(120*pow(n, 4)) 314 | BigFloat.exact('-8.33333333333333333333333333333333391e-15', precision=113) 315 | 316 | A more permanent change to the context can be effected using the 317 | :func:`setcontext` function, which takes a single argument of type 318 | :class:`Context`: 319 | 320 | >>> setcontext(precision(30)) 321 | >>> sqrt(2) 322 | BigFloat.exact('1.4142135624', precision=30) 323 | >>> setcontext(RoundTowardZero) 324 | >>> sqrt(2) 325 | BigFloat.exact('1.4142135605', precision=30) 326 | 327 | An important point here is that in any place that a context is used, 328 | only the attributes specified by that context are changed. For 329 | example, the context ``precision(30)`` only has the ``precision`` 330 | attribute, so only that attribute is affected by the :func:`setcontext` 331 | call; the other attributes are not changed. Similarly, the 332 | ``setcontext(RoundTowardZero)`` line above doesn't affect the 333 | precision. 334 | 335 | There's a :data:`DefaultContext` constant giving the default context, so 336 | you can always restore the original default context as follows: 337 | 338 | >>> setcontext(DefaultContext) 339 | 340 | .. note:: 341 | 342 | If :func:`setcontext` is used within a with statement, its effects 343 | only last for the duration of the block following the with 344 | statement. 345 | 346 | 347 | Flags 348 | ^^^^^ 349 | 350 | The :mod:`bigfloat` package also provides five global flags: 'Inexact', 351 | 'Overflow', 'ZeroDivision', 'Underflow', and 'NanFlag', along with methods to 352 | set and test these flags: 353 | 354 | >>> set_flagstate(set()) # clear all flags 355 | >>> get_flagstate() 356 | set() 357 | >>> exp(10**100) 358 | BigFloat.exact('inf', precision=113) 359 | >>> get_flagstate() 360 | {'Overflow', 'Inexact'} 361 | 362 | These flags show that overflow occurred, and that the given result 363 | (infinity) was inexact. The flags are sticky: none of the standard 364 | operations ever clears a flag: 365 | 366 | 367 | >>> sqrt(2) 368 | BigFloat.exact('1.41421356237309504880168872420969798', precision=113) 369 | >>> get_flagstate() # overflow flag still set from the exp call 370 | {'Overflow', 'Inexact'} 371 | >>> set_flagstate(set()) # clear all flags 372 | >>> sqrt(2) 373 | BigFloat.exact('1.41421356237309504880168872420969798', precision=113) 374 | >>> get_flagstate() # sqrt only sets the inexact flag 375 | {'Inexact'} 376 | 377 | The functions :func:`clear_flag`, :func:`set_flag` and 378 | :func:`test_flag` allow clearing, setting and testing of individual 379 | flags. 380 | 381 | Support for these flags is preliminary, and the API may change in 382 | future versions. 383 | 384 | 385 | .. rubric:: Footnotes 386 | 387 | .. [#harmonic] See http://mathworld.wolfram.com/HarmonicNumber.html 388 | -------------------------------------------------------------------------------- /cmpfr.pxd: -------------------------------------------------------------------------------- 1 | # Copyright 2009--2019 Mark Dickinson. 2 | # 3 | # This file is part of the bigfloat package. 4 | # 5 | # The bigfloat package is free software: you can redistribute it and/or modify 6 | # it under the terms of the GNU Lesser General Public License as published by 7 | # the Free Software Foundation, either version 3 of the License, or (at your 8 | # option) any later version. 9 | # 10 | # The bigfloat package is distributed in the hope that it will be useful, but 11 | # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 | # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License 13 | # for more details. 14 | # 15 | # You should have received a copy of the GNU Lesser General Public License 16 | # along with the bigfloat package. If not, see . 17 | 18 | # mpfr.h needs declarations from stdio.h. 19 | cdef extern from "stdio.h": 20 | pass 21 | 22 | cimport cgmp 23 | 24 | cdef extern from "mpfr.h": 25 | # MPFR type declarations 26 | ctypedef int mpfr_prec_t 27 | ctypedef int mpfr_sign_t 28 | ctypedef unsigned int mpfr_flags_t 29 | ctypedef cgmp.mp_exp_t mpfr_exp_t 30 | 31 | ctypedef struct __mpfr_struct: 32 | mpfr_prec_t _mpfr_prec 33 | mpfr_sign_t _mpfr_sign 34 | mpfr_exp_t _mpfr_exp 35 | cgmp.mp_limb_t *_mpfr_d 36 | 37 | # We don't export the mpfr_t type; it's not useful for Cython code, since 38 | # Cython (as of version 0.14.1) doesn't seem to understand it properly: the 39 | # generated C code includes temporary variables of type mpfr_t and 40 | # assignments from one object of type mpfr_t to another, which isn't valid 41 | # C. So we comment out the definition here in order to catch any 42 | # accidental declarations using mpfr_t below. 43 | 44 | # ctypedef __mpfr_struct mpfr_t[1] 45 | ctypedef __mpfr_struct *mpfr_ptr 46 | 47 | # MPFR rounding modes 48 | ctypedef enum mpfr_rnd_t: 49 | MPFR_RNDN = 0 50 | MPFR_RNDZ 51 | MPFR_RNDU 52 | MPFR_RNDD 53 | MPFR_RNDA 54 | MPFR_RNDF 55 | MPFR_RNDNA = -1 56 | 57 | # Free cache policy 58 | ctypedef enum mpfr_free_cache_t: 59 | MPFR_FREE_LOCAL_CACHE = 1 60 | MPFR_FREE_GLOBAL_CACHE = 2 61 | 62 | # Limits 63 | mpfr_prec_t MPFR_PREC_MIN 64 | mpfr_prec_t MPFR_PREC_MAX 65 | 66 | mpfr_exp_t MPFR_EMIN_DEFAULT 67 | mpfr_exp_t MPFR_EMAX_DEFAULT 68 | 69 | # Flags 70 | mpfr_flags_t MPFR_FLAGS_UNDERFLOW 71 | mpfr_flags_t MPFR_FLAGS_OVERFLOW 72 | mpfr_flags_t MPFR_FLAGS_NAN 73 | mpfr_flags_t MPFR_FLAGS_INEXACT 74 | mpfr_flags_t MPFR_FLAGS_ERANGE 75 | mpfr_flags_t MPFR_FLAGS_DIVBY0 76 | mpfr_flags_t MPFR_FLAGS_ALL 77 | 78 | 79 | ########################################################################### 80 | # 5.1 Initialization Functions 81 | ########################################################################### 82 | 83 | void mpfr_init2(mpfr_ptr x, mpfr_prec_t prec) 84 | void mpfr_clear(mpfr_ptr x) 85 | void mpfr_init(mpfr_ptr x) 86 | void mpfr_set_default_prec(mpfr_prec_t prec) 87 | mpfr_prec_t mpfr_get_default_prec() 88 | void mpfr_set_prec(mpfr_ptr x, mpfr_prec_t prec) 89 | mpfr_prec_t mpfr_get_prec(mpfr_ptr x) 90 | 91 | 92 | ########################################################################### 93 | # 5.2 Assignment Functions 94 | ########################################################################### 95 | 96 | int mpfr_set(mpfr_ptr rop, mpfr_ptr op, mpfr_rnd_t rnd) 97 | int mpfr_set_ui(mpfr_ptr rop, unsigned long int op, mpfr_rnd_t rnd) 98 | int mpfr_set_si(mpfr_ptr rop, long int op, mpfr_rnd_t rnd) 99 | int mpfr_set_d(mpfr_ptr rop, double op, mpfr_rnd_t rnd) 100 | int mpfr_set_z(mpfr_ptr rop, cgmp.mpz_ptr op, mpfr_rnd_t rnd) 101 | int mpfr_set_ui_2exp( 102 | mpfr_ptr rop, unsigned long int op, mpfr_exp_t e, mpfr_rnd_t rnd 103 | ) 104 | int mpfr_set_si_2exp( 105 | mpfr_ptr rop, long int op, mpfr_exp_t e, mpfr_rnd_t rnd 106 | ) 107 | int mpfr_set_z_2exp( 108 | mpfr_ptr rop, cgmp.mpz_ptr op, mpfr_exp_t e, mpfr_rnd_t rnd 109 | ) 110 | int mpfr_set_str( 111 | mpfr_ptr rop, const char *s, int base, mpfr_rnd_t rnd 112 | ) 113 | int mpfr_strtofr( 114 | mpfr_ptr rop, const char *nptr, char **endptr, int base, mpfr_rnd_t rnd 115 | ) 116 | void mpfr_set_nan(mpfr_ptr x) 117 | void mpfr_set_inf(mpfr_ptr x, int sign) 118 | void mpfr_set_zero(mpfr_ptr x, int sign) 119 | void mpfr_swap(mpfr_ptr x, mpfr_ptr y) 120 | 121 | 122 | ########################################################################### 123 | # 5.4 Conversion Functions 124 | ########################################################################### 125 | 126 | double mpfr_get_d(mpfr_ptr op, mpfr_rnd_t rnd) 127 | long int mpfr_get_si(mpfr_ptr op, mpfr_rnd_t rnd) 128 | unsigned long int mpfr_get_ui(mpfr_ptr op, mpfr_rnd_t rnd) 129 | double mpfr_get_d_2exp(long int *exp, mpfr_ptr op, mpfr_rnd_t rnd) 130 | int mpfr_frexp(mpfr_exp_t *exp, mpfr_ptr y, mpfr_ptr x, mpfr_rnd_t rnd) 131 | mpfr_exp_t mpfr_get_z_2exp(cgmp.mpz_ptr rop, mpfr_ptr op) 132 | int mpfr_get_z(cgmp.mpz_ptr rop, mpfr_ptr op, mpfr_rnd_t rnd) 133 | 134 | char * mpfr_get_str( 135 | char *str, mpfr_exp_t *expptr, int b, 136 | size_t n, mpfr_ptr op, mpfr_rnd_t rnd 137 | ) 138 | void mpfr_free_str(char *str) 139 | int mpfr_fits_ulong_p(mpfr_ptr x, mpfr_rnd_t rnd) 140 | int mpfr_fits_slong_p(mpfr_ptr x, mpfr_rnd_t rnd) 141 | 142 | 143 | ########################################################################### 144 | # 5.5 Basic Arithmetic Functions 145 | ########################################################################### 146 | 147 | int mpfr_add(mpfr_ptr rop, mpfr_ptr op1, mpfr_ptr op2, mpfr_rnd_t rnd) 148 | int mpfr_sub(mpfr_ptr rop, mpfr_ptr op1, mpfr_ptr op2, mpfr_rnd_t rnd) 149 | int mpfr_mul(mpfr_ptr rop, mpfr_ptr op1, mpfr_ptr op2, mpfr_rnd_t rnd) 150 | int mpfr_sqr(mpfr_ptr rop, mpfr_ptr op, mpfr_rnd_t rnd) 151 | int mpfr_div(mpfr_ptr rop, mpfr_ptr op1, mpfr_ptr op2, mpfr_rnd_t rnd) 152 | int mpfr_sqrt(mpfr_ptr rop, mpfr_ptr op, mpfr_rnd_t rnd) 153 | int mpfr_rec_sqrt(mpfr_ptr rop, mpfr_ptr op, mpfr_rnd_t rnd) 154 | int mpfr_cbrt(mpfr_ptr rop, mpfr_ptr op, mpfr_rnd_t rnd) 155 | int mpfr_rootn_ui( 156 | mpfr_ptr top, mpfr_ptr op, unsigned long int k, mpfr_rnd_t rnd 157 | ) 158 | int mpfr_root( 159 | mpfr_ptr top, mpfr_ptr op, unsigned long int k, mpfr_rnd_t rnd 160 | ) 161 | int mpfr_pow(mpfr_ptr rop, mpfr_ptr op1, mpfr_ptr op2, mpfr_rnd_t rnd) 162 | int mpfr_neg(mpfr_ptr rop, mpfr_ptr op, mpfr_rnd_t rnd) 163 | int mpfr_abs(mpfr_ptr rop, mpfr_ptr op, mpfr_rnd_t rnd) 164 | int mpfr_dim(mpfr_ptr rop, mpfr_ptr op1, mpfr_ptr op2, mpfr_rnd_t rnd) 165 | 166 | 167 | ########################################################################### 168 | # 5.6 Comparison Functions 169 | ########################################################################### 170 | 171 | int mpfr_cmp(mpfr_ptr op1, mpfr_ptr op2) 172 | int mpfr_cmpabs(mpfr_ptr op1, mpfr_ptr op2) 173 | int mpfr_nan_p(mpfr_ptr op) 174 | int mpfr_inf_p(mpfr_ptr op) 175 | int mpfr_number_p(mpfr_ptr op) 176 | int mpfr_zero_p(mpfr_ptr op) 177 | int mpfr_regular_p(mpfr_ptr op) 178 | int mpfr_sgn(mpfr_ptr op) 179 | int mpfr_greater_p(mpfr_ptr op1, mpfr_ptr op2) 180 | int mpfr_greaterequal_p(mpfr_ptr op1, mpfr_ptr op2) 181 | int mpfr_less_p(mpfr_ptr op1, mpfr_ptr op2) 182 | int mpfr_lessequal_p(mpfr_ptr op1, mpfr_ptr op2) 183 | int mpfr_equal_p(mpfr_ptr op1, mpfr_ptr op2) 184 | int mpfr_lessgreater_p(mpfr_ptr op1, mpfr_ptr op2) 185 | int mpfr_unordered_p(mpfr_ptr op1, mpfr_ptr op2) 186 | 187 | 188 | ########################################################################### 189 | # 5.7 Special Functions 190 | ########################################################################### 191 | 192 | int mpfr_log(mpfr_ptr rop, mpfr_ptr op, mpfr_rnd_t rnd) 193 | int mpfr_log_ui(mpfr_ptr rop, unsigned long op, mpfr_rnd_t rnd) 194 | int mpfr_log2(mpfr_ptr rop, mpfr_ptr op, mpfr_rnd_t rnd) 195 | int mpfr_log10(mpfr_ptr rop, mpfr_ptr op, mpfr_rnd_t rnd) 196 | 197 | int mpfr_log1p(mpfr_ptr rop, mpfr_ptr op, mpfr_rnd_t rnd) 198 | 199 | int mpfr_exp(mpfr_ptr rop, mpfr_ptr op, mpfr_rnd_t rnd) 200 | int mpfr_exp2(mpfr_ptr rop, mpfr_ptr op, mpfr_rnd_t rnd) 201 | int mpfr_exp10(mpfr_ptr rop, mpfr_ptr op, mpfr_rnd_t rnd) 202 | 203 | int mpfr_expm1(mpfr_ptr rop, mpfr_ptr op, mpfr_rnd_t rnd) 204 | 205 | int mpfr_cos(mpfr_ptr rop, mpfr_ptr op, mpfr_rnd_t rnd) 206 | int mpfr_sin(mpfr_ptr rop, mpfr_ptr op, mpfr_rnd_t rnd) 207 | int mpfr_tan(mpfr_ptr rop, mpfr_ptr op, mpfr_rnd_t rnd) 208 | 209 | int mpfr_sin_cos(mpfr_ptr sop, mpfr_ptr cop, mpfr_ptr op, mpfr_rnd_t rnd) 210 | 211 | int mpfr_sec(mpfr_ptr rop, mpfr_ptr op, mpfr_rnd_t rnd) 212 | int mpfr_csc(mpfr_ptr rop, mpfr_ptr op, mpfr_rnd_t rnd) 213 | int mpfr_cot(mpfr_ptr rop, mpfr_ptr op, mpfr_rnd_t rnd) 214 | 215 | int mpfr_acos(mpfr_ptr rop, mpfr_ptr op, mpfr_rnd_t rnd) 216 | int mpfr_asin(mpfr_ptr rop, mpfr_ptr op, mpfr_rnd_t rnd) 217 | int mpfr_atan(mpfr_ptr rop, mpfr_ptr op, mpfr_rnd_t rnd) 218 | 219 | int mpfr_atan2(mpfr_ptr rop, mpfr_ptr y, mpfr_ptr x, mpfr_rnd_t rnd) 220 | 221 | int mpfr_cosh(mpfr_ptr rop, mpfr_ptr op, mpfr_rnd_t rnd) 222 | int mpfr_sinh(mpfr_ptr rop, mpfr_ptr op, mpfr_rnd_t rnd) 223 | int mpfr_tanh(mpfr_ptr rop, mpfr_ptr op, mpfr_rnd_t rnd) 224 | 225 | int mpfr_sinh_cosh(mpfr_ptr sop, mpfr_ptr cop, mpfr_ptr op, mpfr_rnd_t rnd) 226 | 227 | int mpfr_sech(mpfr_ptr rop, mpfr_ptr op, mpfr_rnd_t rnd) 228 | int mpfr_csch(mpfr_ptr rop, mpfr_ptr op, mpfr_rnd_t rnd) 229 | int mpfr_coth(mpfr_ptr rop, mpfr_ptr op, mpfr_rnd_t rnd) 230 | 231 | int mpfr_acosh(mpfr_ptr rop, mpfr_ptr op, mpfr_rnd_t rnd) 232 | int mpfr_asinh(mpfr_ptr rop, mpfr_ptr op, mpfr_rnd_t rnd) 233 | int mpfr_atanh(mpfr_ptr rop, mpfr_ptr op, mpfr_rnd_t rnd) 234 | 235 | int mpfr_fac_ui(mpfr_ptr rop, unsigned long int op, mpfr_rnd_t rnd) 236 | 237 | int mpfr_eint(mpfr_ptr rop, mpfr_ptr op, mpfr_rnd_t rnd) 238 | int mpfr_li2(mpfr_ptr rop, mpfr_ptr op, mpfr_rnd_t rnd) 239 | int mpfr_gamma(mpfr_ptr rop, mpfr_ptr op, mpfr_rnd_t rnd) 240 | int mpfr_gamma_inc(mpfr_ptr rop, mpfr_ptr op, mpfr_ptr op2, mpfr_rnd_t rnd) 241 | int mpfr_lngamma(mpfr_ptr rop, mpfr_ptr op, mpfr_rnd_t rnd) 242 | int mpfr_lgamma(mpfr_ptr rop, int *signp, mpfr_ptr op, mpfr_rnd_t rnd) 243 | int mpfr_digamma(mpfr_ptr rop, mpfr_ptr op, mpfr_rnd_t rnd) 244 | int mpfr_beta(mpfr_ptr rop, mpfr_ptr op1, mpfr_ptr op2, mpfr_rnd_t rnd) 245 | int mpfr_zeta(mpfr_ptr rop, mpfr_ptr op, mpfr_rnd_t rnd) 246 | int mpfr_zeta_ui(mpfr_ptr rop, unsigned long int op, mpfr_rnd_t rnd) 247 | int mpfr_erf(mpfr_ptr rop, mpfr_ptr op, mpfr_rnd_t rnd) 248 | int mpfr_erfc(mpfr_ptr rop, mpfr_ptr op, mpfr_rnd_t rnd) 249 | int mpfr_j0(mpfr_ptr rop, mpfr_ptr op, mpfr_rnd_t rnd) 250 | int mpfr_j1(mpfr_ptr rop, mpfr_ptr op, mpfr_rnd_t rnd) 251 | int mpfr_jn(mpfr_ptr rop, long int n, mpfr_ptr op, mpfr_rnd_t rnd) 252 | int mpfr_y0(mpfr_ptr rop, mpfr_ptr op, mpfr_rnd_t rnd) 253 | int mpfr_y1(mpfr_ptr rop, mpfr_ptr op, mpfr_rnd_t rnd) 254 | int mpfr_yn(mpfr_ptr rop, long int n, mpfr_ptr op, mpfr_rnd_t rnd) 255 | 256 | int mpfr_fma( 257 | mpfr_ptr rop, mpfr_ptr op1, mpfr_ptr op2, mpfr_ptr op3, mpfr_rnd_t rnd 258 | ) 259 | int mpfr_fms( 260 | mpfr_ptr rop, mpfr_ptr op1, mpfr_ptr op2, mpfr_ptr op3, mpfr_rnd_t rnd 261 | ) 262 | int mpfr_fmma( 263 | mpfr_ptr rop, mpfr_ptr op1, mpfr_ptr op2, mpfr_ptr op3, mpfr_ptr op4, 264 | mpfr_rnd_t rnd 265 | ) 266 | int mpfr_fmms( 267 | mpfr_ptr rop, mpfr_ptr op1, mpfr_ptr op2, mpfr_ptr op3, mpfr_ptr op4, 268 | mpfr_rnd_t rnd 269 | ) 270 | int mpfr_agm(mpfr_ptr rop, mpfr_ptr op1, mpfr_ptr op2, mpfr_rnd_t rnd) 271 | int mpfr_hypot(mpfr_ptr rop, mpfr_ptr x, mpfr_ptr y, mpfr_rnd_t rnd) 272 | 273 | int mpfr_ai(mpfr_ptr rop, mpfr_ptr op, mpfr_rnd_t rnd) 274 | 275 | int mpfr_const_log2(mpfr_ptr rop, mpfr_rnd_t rnd) 276 | int mpfr_const_pi(mpfr_ptr rop, mpfr_rnd_t rnd) 277 | int mpfr_const_euler(mpfr_ptr rop, mpfr_rnd_t rnd) 278 | int mpfr_const_catalan(mpfr_ptr rop, mpfr_rnd_t rnd) 279 | 280 | void mpfr_free_cache() 281 | void mpfr_free_cache2(mpfr_free_cache_t way) 282 | void mpfr_free_pool() 283 | int mpfr_mp_memory_cleanup() 284 | 285 | int mpfr_sum( 286 | mpfr_ptr rop, const mpfr_ptr tab[], unsigned long int n, 287 | mpfr_rnd_t rnd 288 | ) 289 | 290 | ########################################################################### 291 | # 5.9 Formatted Output Functions 292 | ########################################################################### 293 | 294 | int mpfr_asprintf(char **str, const char *template, ...) 295 | 296 | ########################################################################### 297 | # 5.10 Integer and Remainder Related Functions 298 | ########################################################################### 299 | 300 | int mpfr_rint(mpfr_ptr rop, mpfr_ptr op, mpfr_rnd_t rnd) 301 | int mpfr_ceil(mpfr_ptr rop, mpfr_ptr op) 302 | int mpfr_floor(mpfr_ptr rop, mpfr_ptr op) 303 | int mpfr_round(mpfr_ptr rop, mpfr_ptr op) 304 | int mpfr_roundeven(mpfr_ptr rop, mpfr_ptr op) 305 | int mpfr_trunc(mpfr_ptr rop, mpfr_ptr op) 306 | 307 | int mpfr_rint_ceil(mpfr_ptr rop, mpfr_ptr op, mpfr_rnd_t rnd) 308 | int mpfr_rint_floor(mpfr_ptr rop, mpfr_ptr op, mpfr_rnd_t rnd) 309 | int mpfr_rint_round(mpfr_ptr rop, mpfr_ptr op, mpfr_rnd_t rnd) 310 | int mpfr_rint_roundeven(mpfr_ptr rop, mpfr_ptr op, mpfr_rnd_t rnd) 311 | int mpfr_rint_trunc(mpfr_ptr rop, mpfr_ptr op, mpfr_rnd_t rnd) 312 | 313 | int mpfr_frac(mpfr_ptr rop, mpfr_ptr op, mpfr_rnd_t rnd) 314 | int mpfr_modf(mpfr_ptr iop, mpfr_ptr fop, mpfr_ptr op, mpfr_rnd_t rnd) 315 | 316 | int mpfr_fmod(mpfr_ptr r, mpfr_ptr x, mpfr_ptr y, mpfr_rnd_t rnd) 317 | int mpfr_fmodquo( 318 | mpfr_ptr r, long int *q, mpfr_ptr x, mpfr_ptr y, mpfr_rnd_t rnd 319 | ) 320 | int mpfr_remainder(mpfr_ptr r, mpfr_ptr x, mpfr_ptr y, mpfr_rnd_t rnd) 321 | int mpfr_remquo( 322 | mpfr_ptr r, long int *q, mpfr_ptr x, mpfr_ptr y, mpfr_rnd_t rnd 323 | ) 324 | int mpfr_integer_p(mpfr_ptr op) 325 | 326 | 327 | ########################################################################### 328 | # 5.11 Rounding Related Functions 329 | ########################################################################### 330 | 331 | void mpfr_set_default_rounding_mode(mpfr_rnd_t rnd) 332 | mpfr_rnd_t mpfr_get_default_rounding_mode() 333 | int mpfr_prec_round(mpfr_ptr x, mpfr_prec_t prec, mpfr_rnd_t rnd) 334 | int mpfr_can_round( 335 | mpfr_ptr b, mpfr_exp_t err, 336 | mpfr_rnd_t rnd1, mpfr_rnd_t rnd2, 337 | mpfr_prec_t prec 338 | ) 339 | mpfr_prec_t mpfr_min_prec(mpfr_ptr x) 340 | const char *mpfr_print_rnd_mode(mpfr_rnd_t rnd) 341 | 342 | 343 | ########################################################################### 344 | # 5.12 Miscellaneous Functions 345 | ########################################################################### 346 | 347 | void mpfr_nexttoward(mpfr_ptr rop, mpfr_ptr op) 348 | void mpfr_nextabove(mpfr_ptr op) 349 | void mpfr_nextbelow(mpfr_ptr op) 350 | int mpfr_min(mpfr_ptr rop, mpfr_ptr op1, mpfr_ptr op2, mpfr_rnd_t rnd) 351 | int mpfr_max(mpfr_ptr rop, mpfr_ptr op1, mpfr_ptr op2, mpfr_rnd_t rnd) 352 | mpfr_exp_t mpfr_get_exp(mpfr_ptr x) 353 | int mpfr_set_exp(mpfr_ptr x, mpfr_exp_t exp) 354 | int mpfr_signbit(mpfr_ptr op) 355 | int mpfr_setsign(mpfr_ptr rop, mpfr_ptr op, int s, mpfr_rnd_t rnd) 356 | int mpfr_copysign(mpfr_ptr rop, mpfr_ptr op1, mpfr_ptr op2, mpfr_rnd_t rnd) 357 | const char *mpfr_get_version() 358 | int MPFR_VERSION 359 | int MPFR_VERSION_MAJOR 360 | int MPFR_VERSION_MINOR 361 | int MPFR_VERSION_PATCHLEVEL 362 | const char *MPFR_VERSION_STRING 363 | int MPFR_VERSION_NUM(int major, int minor, int patchlevel) 364 | const char *mpfr_get_patches() 365 | int mpfr_buildopt_tls_p() 366 | int mpfr_buildopt_float128_p() 367 | int mpfr_buildopt_decimal_p() 368 | int mpfr_buildopt_gmpinternals_p() 369 | int mpfr_buildopt_sharedcache_p() 370 | const char *mpfr_buildopt_tune_case() 371 | 372 | 373 | ########################################################################### 374 | # 5.13 Exception Related Functions 375 | ########################################################################### 376 | 377 | mpfr_exp_t mpfr_get_emin() 378 | mpfr_exp_t mpfr_get_emax() 379 | int mpfr_set_emin(mpfr_exp_t exp) 380 | int mpfr_set_emax(mpfr_exp_t exp) 381 | mpfr_exp_t mpfr_get_emin_min() 382 | mpfr_exp_t mpfr_get_emin_max() 383 | mpfr_exp_t mpfr_get_emax_min() 384 | mpfr_exp_t mpfr_get_emax_max() 385 | int mpfr_check_range(mpfr_ptr x, int t, mpfr_rnd_t rnd) 386 | int mpfr_subnormalize(mpfr_ptr x, int t, mpfr_rnd_t rnd) 387 | 388 | void mpfr_clear_underflow() 389 | void mpfr_clear_overflow() 390 | void mpfr_clear_divby0() 391 | void mpfr_clear_nanflag() 392 | void mpfr_clear_inexflag() 393 | void mpfr_clear_erangeflag() 394 | 395 | void mpfr_set_underflow() 396 | void mpfr_set_overflow() 397 | void mpfr_set_divby0() 398 | void mpfr_set_nanflag() 399 | void mpfr_set_inexflag() 400 | void mpfr_set_erangeflag() 401 | 402 | void mpfr_clear_flags() 403 | 404 | int mpfr_underflow_p() 405 | int mpfr_overflow_p() 406 | int mpfr_divby0_p() 407 | int mpfr_nanflag_p() 408 | int mpfr_inexflag_p() 409 | int mpfr_erangeflag_p() 410 | 411 | void mpfr_flags_clear(mpfr_flags_t mask) 412 | void mpfr_flags_set(mpfr_flags_t mask) 413 | mpfr_flags_t mpfr_flags_test(mpfr_flags_t mask) 414 | mpfr_flags_t mpfr_flags_save() 415 | void mpfr_flags_restore(mpfr_flags_t flags, mpfr_flags_t mask) 416 | --------------------------------------------------------------------------------