├── .circleci └── config.yml ├── .clang-format ├── .clang-tidy ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md └── workflows │ └── gh_actions_ci.yml ├── .gitignore ├── .vscode └── settings.json ├── CMakeLists.txt ├── COPYING ├── README.md ├── benchmark ├── CMakeLists.txt ├── integer1_dot_product_signed.cpp ├── integer1_dot_product_unsigned.cpp ├── integer1_int_conversion.cpp ├── integer1_sort_signed.cpp ├── integer1_sort_unsigned.cpp ├── integer1_uint_conversion.cpp ├── integer1_vec_div_signed.cpp ├── integer1_vec_div_unsigned.cpp ├── integer1_vec_gcd_signed.cpp ├── integer1_vec_lcm_signed.cpp ├── integer1_vec_lshift_signed.cpp ├── integer1_vec_lshift_unsigned.cpp ├── integer1_vec_mul_signed.cpp ├── integer1_vec_mul_unsigned.cpp ├── integer2_dot_product_signed.cpp ├── integer2_dot_product_unsigned.cpp ├── integer2_int_conversion.cpp ├── integer2_sort_signed.cpp ├── integer2_sort_unsigned.cpp ├── integer2_uint_conversion.cpp ├── integer2_vec_div_signed.cpp ├── integer2_vec_div_unsigned.cpp ├── integer2_vec_lshift_signed.cpp ├── integer2_vec_lshift_unsigned.cpp ├── integer2_vec_mul_signed.cpp ├── integer2_vec_mul_unsigned.cpp ├── real_alloc.cpp ├── track_malloc.cpp ├── track_malloc.hpp ├── utils.cpp └── utils.hpp ├── cmake ├── Findmp++_FLINT.cmake ├── Findmp++_GMP.cmake ├── Findmp++_MPC.cmake ├── Findmp++_MPFR.cmake ├── Findmp++_quadmath.cmake └── yacma │ ├── LICENSE │ ├── README.md │ ├── YACMACompilerLinkerSettings.cmake │ ├── YACMAPythonSetup.cmake │ └── YACMAThreadingSetup.cmake ├── codecov.yml ├── config.hpp.in ├── doc ├── Makefile ├── _static │ ├── integer1_dot_product_signed.png │ ├── integer1_dot_product_unsigned.png │ ├── integer1_sort_signed.png │ ├── integer1_sort_unsigned.png │ ├── integer1_vec_div_signed.png │ ├── integer1_vec_div_unsigned.png │ ├── integer1_vec_gcd_signed.png │ ├── integer1_vec_lcm_signed.png │ ├── integer1_vec_lshift_signed.png │ ├── integer1_vec_lshift_unsigned.png │ ├── integer1_vec_mul_signed.png │ ├── integer1_vec_mul_unsigned.png │ ├── integer2_dot_product_signed.png │ ├── integer2_dot_product_unsigned.png │ ├── integer2_sort_signed.png │ ├── integer2_sort_unsigned.png │ ├── integer2_vec_div_signed.png │ ├── integer2_vec_div_unsigned.png │ ├── integer2_vec_lshift_signed.png │ ├── integer2_vec_lshift_unsigned.png │ ├── integer2_vec_mul_signed.png │ └── integer2_vec_mul_unsigned.png ├── benchmarks.rst ├── changelog.rst ├── complex.rst ├── complex128.rst ├── concepts.rst ├── conf.py.in ├── definitions.rst ├── exceptions.rst ├── fwd_decl.rst ├── index.rst ├── installation.rst ├── integer.rst ├── integer_benchmarks.rst ├── interactive_notebooks.rst ├── make.bat ├── namespaces.rst ├── notebooks │ ├── integer_arithmetic.ipynb │ ├── integer_basics.ipynb │ ├── integer_bit_fiddling.ipynb │ ├── integer_comparison.ipynb │ ├── integer_formatted_output.ipynb │ ├── integer_s11n.ipynb │ └── real_basics.ipynb ├── rational.rst ├── real.rst ├── real128.rst ├── reference.rst ├── tutorial.rst ├── tutorial_api.rst ├── tutorial_boost_s11n.rst ├── tutorial_commonops.rst ├── tutorial_complex.rst ├── tutorial_complex128.rst ├── tutorial_constr.rst ├── tutorial_integer.rst ├── tutorial_io.rst ├── tutorial_numtower.rst ├── tutorial_prelim.rst ├── tutorial_pybind11.rst ├── tutorial_rational.rst ├── tutorial_real.rst ├── tutorial_real128.rst ├── utilities.rst └── versioning.rst ├── environment.yml ├── include └── mp++ │ ├── complex.hpp │ ├── complex128.hpp │ ├── concepts.hpp │ ├── detail │ ├── fmt.hpp │ ├── gmp.hpp │ ├── integer_literals.hpp │ ├── mpc.hpp │ ├── mpfr.hpp │ ├── parse_complex.hpp │ ├── rational_literals.hpp │ ├── real128_literal.hpp │ ├── real_literals.hpp │ ├── type_traits.hpp │ ├── utils.hpp │ └── visibility.hpp │ ├── exceptions.hpp │ ├── extra │ └── pybind11.hpp │ ├── fwd.hpp │ ├── integer.hpp │ ├── mp++.hpp │ ├── rational.hpp │ ├── real.hpp │ ├── real128.hpp │ └── type_name.hpp ├── mp++-config.cmake.in ├── src ├── complex.cpp ├── complex128.cpp ├── detail │ ├── arb.cpp │ ├── mpfr_arb_cleanup.cpp │ ├── parse_complex.cpp │ └── utils.cpp ├── integer.cpp ├── rational.cpp ├── real.cpp ├── real128.cpp └── type_name.cpp ├── test ├── CMakeLists.txt ├── catch.hpp ├── catch_main.cpp ├── complex128_arith.cpp ├── complex128_basic.cpp ├── complex128_hyper.cpp ├── complex128_io.cpp ├── complex128_literal.cpp ├── complex128_logexp.cpp ├── complex128_operators.cpp ├── complex128_pow.cpp ├── complex128_roots.cpp ├── complex128_trig.cpp ├── complex_agm.cpp ├── complex_arith.cpp ├── complex_basic.cpp ├── complex_cmp.cpp ├── complex_hyper.cpp ├── complex_io.cpp ├── complex_literals.cpp ├── complex_logexp.cpp ├── complex_mul_div_2.cpp ├── complex_operators.cpp ├── complex_pow.cpp ├── complex_rootofunity.cpp ├── complex_roots.cpp ├── complex_trig.cpp ├── concepts.cpp ├── global_header.cpp ├── integer_abs.cpp ├── integer_addsub_ui_si.cpp ├── integer_arith.cpp ├── integer_arith_ops_01.cpp ├── integer_arith_ops_02.cpp ├── integer_arith_ops_03.cpp ├── integer_basic_01.cpp ├── integer_basic_02.cpp ├── integer_basic_03.cpp ├── integer_basic_04.cpp ├── integer_bin.cpp ├── integer_bitwise.cpp ├── integer_caches.cpp ├── integer_divexact.cpp ├── integer_divexact_gcd.cpp ├── integer_even_odd.cpp ├── integer_fac.cpp ├── integer_gcd_lcm.cpp ├── integer_get_mpz_t.cpp ├── integer_hash.cpp ├── integer_is_zero_one.cpp ├── integer_limb_size_nbits.cpp ├── integer_literals.cpp ├── integer_neg.cpp ├── integer_nextprime.cpp ├── integer_pow.cpp ├── integer_probab_prime_p.cpp ├── integer_rel.cpp ├── integer_roots.cpp ├── integer_set_zero_one.cpp ├── integer_sqr.cpp ├── integer_sqrm.cpp ├── integer_stream_format.cpp ├── integer_swap.cpp ├── integer_tdiv_q.cpp ├── integer_view.cpp ├── interop_test.cpp ├── pybind11 │ ├── CMakeLists.txt │ ├── pybind11_test_01.cpp │ └── run_pybind11_test_01.py ├── rational_abs.cpp ├── rational_arith.cpp ├── rational_arith_ops_01.cpp ├── rational_arith_ops_02.cpp ├── rational_arith_ops_03.cpp ├── rational_basic_01.cpp ├── rational_basic_02.cpp ├── rational_binomial.cpp ├── rational_hash.cpp ├── rational_inv.cpp ├── rational_is_zero_one.cpp ├── rational_literals.cpp ├── rational_neg.cpp ├── rational_pow.cpp ├── rational_rel.cpp ├── rational_stream_format.cpp ├── real128_arith.cpp ├── real128_basic.cpp ├── real128_bessel.cpp ├── real128_comparisons.cpp ├── real128_constants.cpp ├── real128_fdim.cpp ├── real128_fmax_fmin.cpp ├── real128_fpmanip.cpp ├── real128_hash.cpp ├── real128_hyperbolic.cpp ├── real128_ieee.cpp ├── real128_intrem.cpp ├── real128_io.cpp ├── real128_literal.cpp ├── real128_logexp.cpp ├── real128_miscfunctions.cpp ├── real128_naninffinite.cpp ├── real128_operators.cpp ├── real128_pow.cpp ├── real128_roots.cpp ├── real128_signbit.cpp ├── real128_trig.cpp ├── real_arith.cpp ├── real_basic.cpp ├── real_bessel.cpp ├── real_cmp.cpp ├── real_constants.cpp ├── real_gamma.cpp ├── real_get_set_z_2exp.cpp ├── real_hash.cpp ├── real_hyper.cpp ├── real_intrem.cpp ├── real_io.cpp ├── real_literals.cpp ├── real_logexp.cpp ├── real_mul_div_2.cpp ├── real_neg_abs.cpp ├── real_nextafter.cpp ├── real_operators.cpp ├── real_other_specfunc.cpp ├── real_polylogs.cpp ├── real_pow.cpp ├── real_roots.cpp ├── real_s11n.cpp ├── real_trig.cpp ├── test_utils.hpp ├── type_name.cpp ├── type_traits.cpp └── utils.cpp └── tools ├── appveyor-download.cmd ├── circleci_conda_arm64.sh ├── circleci_conda_coverage.sh ├── circleci_conda_docs.sh ├── circleci_conda_release.sh ├── circleci_focal_clang9_debuggmp_unstable.sh ├── circleci_focal_clang9_msan.sh ├── gha_conda_asan.sh ├── gha_conda_tsan.sh ├── gha_conda_ubsan.sh ├── gha_debuggmp.sh ├── gha_osx.sh ├── sample_project ├── CMakeLists.txt └── main.cpp └── travis_ubuntu_ppc64.sh /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2.1 2 | 3 | jobs: 4 | conda_coverage: 5 | docker: 6 | - image: cimg/base:current 7 | resource_class: large 8 | steps: 9 | - checkout 10 | - run: 11 | name: Build and test 12 | command: bash ./tools/circleci_conda_coverage.sh 13 | conda_release: 14 | docker: 15 | - image: cimg/base:current 16 | resource_class: large 17 | steps: 18 | - checkout 19 | - run: 20 | name: Build and test 21 | command: bash ./tools/circleci_conda_release.sh 22 | conda_docs: 23 | docker: 24 | - image: cimg/base:current 25 | resource_class: large 26 | steps: 27 | - checkout 28 | - run: 29 | name: Build and test 30 | command: bash ./tools/circleci_conda_docs.sh 31 | focal_clang9_debuggmp_unstable: 32 | docker: 33 | - image: circleci/buildpack-deps:focal 34 | steps: 35 | - checkout 36 | - run: 37 | name: Build and test 38 | command: bash ./tools/circleci_focal_clang9_debuggmp_unstable.sh 39 | focal_clang9_msan_00: 40 | docker: 41 | - image: circleci/buildpack-deps:focal 42 | steps: 43 | - checkout 44 | - run: 45 | name: Build and test 46 | command: bash ./tools/circleci_focal_clang9_msan.sh 47 | environment: 48 | TEST_NSPLIT: 2 49 | SPLIT_TEST_NUM: 0 50 | focal_clang9_msan_01: 51 | docker: 52 | - image: circleci/buildpack-deps:focal 53 | steps: 54 | - checkout 55 | - run: 56 | name: Build and test 57 | command: bash ./tools/circleci_focal_clang9_msan.sh 58 | environment: 59 | TEST_NSPLIT: 2 60 | SPLIT_TEST_NUM: 1 61 | conda_arm64: 62 | machine: 63 | image: ubuntu-2204:current 64 | resource_class: arm.large 65 | steps: 66 | - checkout 67 | - run: 68 | name: Build and test 69 | command: bash ./tools/circleci_conda_arm64.sh 70 | 71 | workflows: 72 | version: 2.1 73 | all_builds: 74 | jobs: 75 | # - focal_clang9_msan_00 76 | # - focal_clang9_msan_01 77 | - conda_coverage 78 | - conda_release 79 | # - focal_clang9_debuggmp_unstable 80 | - conda_docs 81 | - conda_arm64 82 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | Language: Cpp 2 | AccessModifierOffset: -4 3 | AlignAfterOpenBracket: true 4 | AlignConsecutiveAssignments: false 5 | AlignEscapedNewlinesLeft: false 6 | AlignOperands: true 7 | AlignTrailingComments: true 8 | AllowAllParametersOfDeclarationOnNextLine: true 9 | AllowShortBlocksOnASingleLine: false 10 | AllowShortCaseLabelsOnASingleLine: false 11 | AllowShortFunctionsOnASingleLine: Empty 12 | AllowShortIfStatementsOnASingleLine: false 13 | AllowShortLoopsOnASingleLine: false 14 | AlwaysBreakAfterDefinitionReturnType: None 15 | AlwaysBreakBeforeMultilineStrings: false 16 | AlwaysBreakTemplateDeclarations: true 17 | BinPackArguments: true 18 | BinPackParameters: true 19 | BreakBeforeBinaryOperators: All 20 | BreakBeforeBraces: Linux 21 | BreakBeforeTernaryOperators: true 22 | BreakConstructorInitializersBeforeComma: false 23 | ColumnLimit: 120 24 | ConstructorInitializerAllOnOneLineOrOnePerLine: false 25 | ConstructorInitializerIndentWidth: 4 26 | ContinuationIndentWidth: 4 27 | Cpp11BracedListStyle: true 28 | DerivePointerAlignment: false 29 | DisableFormat: false 30 | ExperimentalAutoDetectBinPacking: false 31 | IndentCaseLabels: true 32 | IndentWidth: 4 33 | IndentWrappedFunctionNames: false 34 | KeepEmptyLinesAtTheStartOfBlocks: true 35 | MacroBlockBegin: '' 36 | MacroBlockEnd: '' 37 | MaxEmptyLinesToKeep: 1 38 | NamespaceIndentation: None 39 | ObjCBlockIndentWidth: 2 40 | ObjCSpaceAfterProperty: false 41 | ObjCSpaceBeforeProtocolList: true 42 | PenaltyBreakBeforeFirstCallParameter: 19 43 | PenaltyBreakComment: 22312 44 | PenaltyBreakFirstLessLess: 120 45 | PenaltyBreakString: 2123 46 | PenaltyExcessCharacter: 1000000 47 | PenaltyReturnTypeOnItsOwnLine: 60 48 | PointerAlignment: Right 49 | SpaceAfterCStyleCast: false 50 | SpaceBeforeAssignmentOperators: true 51 | SpaceBeforeParens: ControlStatements 52 | SpaceInEmptyParentheses: false 53 | SpacesBeforeTrailingComments: 1 54 | SpacesInAngles: false 55 | SpacesInContainerLiterals: false 56 | SpacesInCStyleCastParentheses: false 57 | SpacesInParentheses: false 58 | SpacesInSquareBrackets: false 59 | Standard: Cpp11 60 | TabWidth: 4 61 | UseTab: Never 62 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: "[BUG]" 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Environment (please complete the following information):** 27 | - OS: [e.g. Linux] 28 | - Installation method: [e.g. conda, source] 29 | - Version: [e.g. 2.15] 30 | 31 | **Additional context** 32 | Add any other context about the problem here. 33 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: "[FEATURE]" 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/workflows/gh_actions_ci.yml: -------------------------------------------------------------------------------- 1 | name: GitHub CI 2 | on: 3 | push: 4 | branches: 5 | - master 6 | pull_request: 7 | branches: 8 | - master 9 | jobs: 10 | osx_13_x86: 11 | runs-on: macos-13 12 | steps: 13 | - uses: actions/checkout@v4 14 | - name: Build 15 | run: bash tools/gha_osx.sh 16 | osx_14_arm64: 17 | runs-on: macos-14 18 | steps: 19 | - uses: actions/checkout@v4 20 | - name: Build 21 | run: bash tools/gha_osx.sh 22 | conda_asan: 23 | runs-on: ubuntu-latest 24 | steps: 25 | - uses: actions/checkout@v4 26 | - name: Build 27 | run: bash tools/gha_conda_asan.sh 28 | conda_ubsan: 29 | runs-on: ubuntu-latest 30 | steps: 31 | - uses: actions/checkout@v4 32 | - name: Build 33 | run: bash tools/gha_conda_ubsan.sh 34 | conda_tsan: 35 | runs-on: ubuntu-latest 36 | steps: 37 | - uses: actions/checkout@v4 38 | - name: Build 39 | run: bash tools/gha_conda_tsan.sh 40 | conda_debuggmp: 41 | runs-on: ubuntu-latest 42 | steps: 43 | - uses: actions/checkout@v4 44 | - name: Build 45 | run: bash tools/gha_debuggmp.sh 46 | windows_2022: 47 | runs-on: windows-2022 48 | steps: 49 | - uses: actions/checkout@v4 50 | - uses: conda-incubator/setup-miniconda@v3 51 | with: 52 | auto-update-conda: true 53 | python-version: "3.10" 54 | channels: conda-forge 55 | channel-priority: strict 56 | - uses: ilammy/msvc-dev-cmd@v1 57 | - name: Build 58 | shell: pwsh 59 | run: | 60 | conda install -y cmake gmp mpfr libflint mpc fmt libboost-devel 61 | mkdir build 62 | cd build 63 | cmake ../ -G "Visual Studio 17 2022" -A x64 -DCMAKE_CXX_STANDARD=20 -DMPPP_BUILD_TESTS=yes -DMPPP_WITH_BOOST_S11N=yes -DMPPP_WITH_FMT=yes -DMPPP_WITH_MPFR=yes -DMPPP_WITH_MPC=yes -DMPPP_WITH_FLINT=yes -DMPPP_ENABLE_IPO=yes 64 | cmake --build . --config Release -j2 65 | copy Release\mp++.dll test\Release\ 66 | ctest -j4 -V -C Release 67 | binder_cache: 68 | runs-on: ubuntu-latest 69 | if: github.ref == 'refs/heads/master' 70 | steps: 71 | - name: cache binder build on mybinder.org 72 | uses: jupyterhub/repo2docker-action@master 73 | with: 74 | NO_PUSH: true 75 | MYBINDERORG_TAG: ${{ github.event.ref }} # This builds the container on mybinder.org with the branch that was pushed on. 76 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Build dirs. 2 | build* 3 | 4 | # Documentation. 5 | doc/_build/ 6 | doc/notebooks/.ipynb_checkpoints 7 | # This is auto-generated. 8 | doc/conf.py 9 | 10 | # Temp files. 11 | *~ 12 | *.bak 13 | 14 | # .orig files from patch. 15 | *.orig 16 | 17 | # Editor bits. 18 | .cache/ 19 | 20 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.exclude": { 3 | "**/.git": true, 4 | "build*": true, 5 | "doc/_build/": true 6 | } 7 | } -------------------------------------------------------------------------------- /benchmark/real_alloc.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016-2023 Francesco Biscani (bluescarni@gmail.com) 2 | // 3 | // This file is part of the mp++ library. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla 6 | // Public License v. 2.0. If a copy of the MPL was not distributed 7 | // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | #include 10 | 11 | #include 12 | 13 | #include 14 | 15 | #include "track_malloc.hpp" 16 | 17 | using real = mppp::real; 18 | using mpfr_float = boost::multiprecision::mpfr_float; 19 | 20 | // An example taken from here: 21 | // https://www.boost.org/doc/libs/1_72_0/libs/multiprecision/doc/html/boost_multiprecision/intro.html#boost_multiprecision.intro.expression_templates 22 | template 23 | T test_function(const T &x, bool move = false) 24 | { 25 | T a[7] = {T{1.}, T{2.}, T{3.}, T{4.}, T{5.}, T{6.}, T{7.}}; 26 | 27 | if (move) { 28 | return (((((std::move(a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]; 29 | } else { 30 | return (((((a[6] * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]; 31 | } 32 | } 33 | 34 | int main() 35 | { 36 | real arg1{42.}; 37 | mpfr_float arg2{42.}; 38 | 39 | { 40 | mppp_bench::malloc_tracker t{"bmp::mpfr_float"}; 41 | test_function(arg2); 42 | } 43 | { 44 | mppp_bench::malloc_tracker t{"mppp::real"}; 45 | test_function(arg1); 46 | } 47 | { 48 | mppp_bench::malloc_tracker t{"bmp::mpfr_float + move"}; 49 | test_function(arg2, true); 50 | } 51 | { 52 | mppp_bench::malloc_tracker t{"mppp::real + move"}; 53 | test_function(arg1, true); 54 | } 55 | 56 | return 0; 57 | } 58 | -------------------------------------------------------------------------------- /benchmark/track_malloc.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016-2023 Francesco Biscani (bluescarni@gmail.com) 2 | // 3 | // This file is part of the mp++ library. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla 6 | // Public License v. 2.0. If a copy of the MPL was not distributed 7 | // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | #include "track_malloc.hpp" 10 | 11 | #if defined(MPPP_HAVE_GLIBC) 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | namespace mppp_bench 18 | { 19 | 20 | namespace detail 21 | { 22 | 23 | namespace 24 | { 25 | 26 | // The tracking counter. This will be increased 27 | // each time the malloc() override below is 28 | // invoked. 29 | std::atomic malloc_counter(0); 30 | 31 | } // namespace 32 | 33 | } // namespace detail 34 | 35 | } // namespace mppp_bench 36 | 37 | // NOTE: see here for an explanation: 38 | // https://stackoverflow.com/questions/17803456/an-alternative-for-the-deprecated-malloc-hook-functionality-of-glibc 39 | extern "C" void *__libc_malloc(std::size_t size); 40 | 41 | // NOTE: apparently it is not necessary to declare 42 | // this function as visible. 43 | extern "C" void *malloc(std::size_t size) 44 | { 45 | ++mppp_bench::detail::malloc_counter; 46 | return ::__libc_malloc(size); 47 | } 48 | 49 | namespace mppp_bench 50 | { 51 | 52 | malloc_tracker::malloc_tracker(const char *s) : m_name(s), m_count(detail::malloc_counter.load()) {} 53 | 54 | malloc_tracker::~malloc_tracker() 55 | { 56 | // NOTE: compute the total number of allocations 57 | // before outputting to stream, so that we avoid 58 | // counting possible allocations from stream operations. 59 | const auto tot_nalloc = detail::malloc_counter.load() - m_count; 60 | std::cout << "Tracker '" << m_name << "' observed " << tot_nalloc << " malloc() calls." << std::endl; 61 | } 62 | 63 | } // namespace mppp_bench 64 | 65 | #endif 66 | -------------------------------------------------------------------------------- /benchmark/track_malloc.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016-2023 Francesco Biscani (bluescarni@gmail.com) 2 | // 3 | // This file is part of the mp++ library. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla 6 | // Public License v. 2.0. If a copy of the MPL was not distributed 7 | // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | #ifndef MPPP_BENCHMARK_TRACK_MALLOC_HPP 10 | #define MPPP_BENCHMARK_TRACK_MALLOC_HPP 11 | 12 | // Machinery to check the presence of GLIBC. See: 13 | // https://sourceforge.net/p/predef/wiki/Libraries/ 14 | #include 15 | 16 | #if defined(__GNU_LIBRARY__) || defined(__GLIBC__) 17 | 18 | #define MPPP_HAVE_GLIBC 19 | 20 | #endif 21 | 22 | #if defined(MPPP_HAVE_GLIBC) 23 | 24 | #include 25 | #include 26 | 27 | namespace mppp_bench 28 | { 29 | 30 | struct __attribute__((visibility("default"))) malloc_tracker { 31 | explicit malloc_tracker(const char *); 32 | ~malloc_tracker(); 33 | // NOTE: it is important than m_name 34 | // is inited befor m_count, so that 35 | // we don't end up counting allocations 36 | // from the string. 37 | std::string m_name; 38 | std::size_t m_count; 39 | }; 40 | 41 | } // namespace mppp_bench 42 | 43 | #else 44 | 45 | namespace mppp_bench 46 | { 47 | 48 | struct malloc_tracker { 49 | explicit malloc_tracker(const char *) {} 50 | ~malloc_tracker() {} 51 | }; 52 | 53 | } // namespace mppp_bench 54 | 55 | #endif 56 | 57 | #endif 58 | -------------------------------------------------------------------------------- /benchmark/utils.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016-2023 Francesco Biscani (bluescarni@gmail.com) 2 | // 3 | // This file is part of the mp++ library. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla 6 | // Public License v. 2.0. If a copy of the MPL was not distributed 7 | // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | 18 | #include 19 | 20 | #include "utils.hpp" 21 | 22 | namespace mppp_benchmark 23 | { 24 | 25 | simple_timer::simple_timer() : m_start(std::chrono::high_resolution_clock::now()) {} 26 | 27 | double simple_timer::elapsed() const 28 | { 29 | return static_cast( 30 | std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - m_start) 31 | .count()); 32 | } 33 | 34 | void warmup() 35 | { 36 | fmt::print("Warming up"); 37 | for (auto volatile counter = 0ull; counter < 1000000000ull; ++counter) { 38 | if (counter % 100000000ull == 0u) { 39 | fmt::print("."); 40 | std::cout.flush(); 41 | } 42 | } 43 | fmt::print(" Done\n"); 44 | } 45 | 46 | namespace detail 47 | { 48 | 49 | std::string filename_from_abs_path(const std::string &s) 50 | { 51 | return boost::filesystem::path(s).stem().string(); 52 | } 53 | 54 | } // namespace detail 55 | 56 | const char *res_print_format = "{:16}: {:>5.0f}ms, res = {}\n"; 57 | 58 | namespace detail 59 | { 60 | 61 | namespace 62 | { 63 | 64 | constexpr auto py_script = R"(data = {0} 65 | 66 | if __name__ == '__main__': 67 | import matplotlib as mpl 68 | import matplotlib.pyplot as plt 69 | 70 | mpl.use('Agg') 71 | 72 | plt.style.use('seaborn') 73 | 74 | x_pos = list(range(len(data))) 75 | labels, height = map(list, zip(*data)) 76 | 77 | plt.barh(x_pos, height) 78 | plt.yticks(x_pos, labels) 79 | plt.title('{1}') 80 | plt.xlabel('Time (ms)') 81 | for i, v in enumerate(height): 82 | plt.text(v, i, " "+str(v), va='center', fontweight='bold') 83 | plt.tight_layout() 84 | 85 | plt.savefig('{1}.png', bbox_inches='tight', dpi=250) 86 | )"; 87 | 88 | } 89 | 90 | } // namespace detail 91 | 92 | void write_out(data_t bdata, const std::string &benchmark_name) 93 | { 94 | // Order the benchmark data according to performance. 95 | using rec_t = data_t::value_type; 96 | std::sort(bdata.begin(), bdata.end(), [](const rec_t &p1, const rec_t &p2) { return p1.second > p2.second; }); 97 | 98 | // Create the Python list with the result data. 99 | std::string py_data_list = "["; 100 | for (const auto &p : bdata) { 101 | py_data_list += fmt::format("('{}', {:.0f}), ", p.first, p.second); 102 | } 103 | py_data_list += "]"; 104 | 105 | // Write out the Python script. 106 | std::ofstream of(benchmark_name + ".py", std::ios_base::trunc); 107 | of.exceptions(std::ios_base::failbit); 108 | of << fmt::format(detail::py_script, py_data_list, benchmark_name); 109 | } 110 | 111 | } // namespace mppp_benchmark 112 | -------------------------------------------------------------------------------- /benchmark/utils.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016-2023 Francesco Biscani (bluescarni@gmail.com) 2 | // 3 | // This file is part of the mp++ library. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla 6 | // Public License v. 2.0. If a copy of the MPL was not distributed 7 | // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | #ifndef MPPP_BENCHMARK_UTILS_HPP 10 | #define MPPP_BENCHMARK_UTILS_HPP 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | namespace mppp_benchmark 18 | { 19 | 20 | // A simple RAII timer class, using std::chrono. It will print, upon destruction, 21 | // the time elapsed since construction (in ms). 22 | class simple_timer 23 | { 24 | public: 25 | simple_timer(); 26 | double elapsed() const; 27 | 28 | private: 29 | const std::chrono::high_resolution_clock::time_point m_start; 30 | }; 31 | 32 | // Warmup function. 33 | void warmup(); 34 | 35 | namespace detail 36 | { 37 | 38 | std::string filename_from_abs_path(const std::string &); 39 | 40 | } 41 | 42 | // Small macro to get the file name of the current translation 43 | // unit, stripping away the path and the extension. This 44 | // will be used as the benchmark name. 45 | #define mppp_benchmark_name() mppp_benchmark::detail::filename_from_abs_path(__FILE__) 46 | 47 | // Format strings. 48 | extern const char *res_print_format; 49 | 50 | // Benchmark result data type. 51 | using data_t = std::vector>; 52 | 53 | // Write out the Python plotting file. 54 | void write_out(data_t, const std::string &); 55 | 56 | } // namespace mppp_benchmark 57 | 58 | #endif 59 | -------------------------------------------------------------------------------- /cmake/Findmp++_FLINT.cmake: -------------------------------------------------------------------------------- 1 | if(MPPP_FLINT_INCLUDE_DIR AND MPPP_FLINT_LIBRARY) 2 | # Already in cache, be silent 3 | set(mp++_FLINT_FIND_QUIETLY TRUE) 4 | endif() 5 | 6 | find_path(MPPP_FLINT_INCLUDE_DIR NAMES flint/flint.h) 7 | find_library(MPPP_FLINT_LIBRARY NAMES flint) 8 | 9 | include(FindPackageHandleStandardArgs) 10 | 11 | find_package_handle_standard_args(mp++_FLINT DEFAULT_MSG MPPP_FLINT_INCLUDE_DIR MPPP_FLINT_LIBRARY) 12 | 13 | mark_as_advanced(MPPP_FLINT_INCLUDE_DIR MPPP_FLINT_LIBRARY) 14 | 15 | # NOTE: this has been adapted from CMake's FindPNG.cmake. 16 | if(mp++_FLINT_FOUND AND NOT TARGET mp++::FLINT) 17 | add_library(mp++::FLINT UNKNOWN IMPORTED) 18 | set_target_properties(mp++::FLINT PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${MPPP_FLINT_INCLUDE_DIR}" 19 | IMPORTED_LINK_INTERFACE_LANGUAGES "C" 20 | IMPORTED_LOCATION "${MPPP_FLINT_LIBRARY}") 21 | endif() 22 | -------------------------------------------------------------------------------- /cmake/Findmp++_GMP.cmake: -------------------------------------------------------------------------------- 1 | # Originally copied from the KDE project repository: 2 | # http://websvn.kde.org/trunk/KDE/kdeutils/cmake/modules/FindGMP.cmake?view=markup&pathrev=675218 3 | 4 | # Copyright (c) 2006, Laurent Montel, 5 | # Copyright (c) 2008-2023 Francesco Biscani, 6 | 7 | # Redistribution and use in source and binary forms, with or without 8 | # modification, are permitted provided that the following conditions 9 | # are met: 10 | # 11 | # 1. Redistributions of source code must retain the copyright 12 | # notice, this list of conditions and the following disclaimer. 13 | # 2. Redistributions in binary form must reproduce the copyright 14 | # notice, this list of conditions and the following disclaimer in the 15 | # documentation and/or other materials provided with the distribution. 16 | # 3. The name of the author may not be used to endorse or promote products 17 | # derived from this software without specific prior written permission. 18 | # 19 | # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 20 | # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21 | # OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22 | # IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 23 | # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 24 | # NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28 | # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | # ------------------------------------------------------------------------------------------ 30 | 31 | if(MPPP_GMP_INCLUDE_DIR AND MPPP_GMP_LIBRARY) 32 | # Already in cache, be silent 33 | set(mp++_GMP_FIND_QUIETLY TRUE) 34 | endif() 35 | 36 | find_path(MPPP_GMP_INCLUDE_DIR NAMES gmp.h) 37 | find_library(MPPP_GMP_LIBRARY NAMES gmp) 38 | 39 | include(FindPackageHandleStandardArgs) 40 | 41 | find_package_handle_standard_args(mp++_GMP DEFAULT_MSG MPPP_GMP_INCLUDE_DIR MPPP_GMP_LIBRARY) 42 | 43 | mark_as_advanced(MPPP_GMP_INCLUDE_DIR MPPP_GMP_LIBRARY) 44 | 45 | # NOTE: this has been adapted from CMake's FindPNG.cmake. 46 | if(mp++_GMP_FOUND AND NOT TARGET mp++::GMP) 47 | add_library(mp++::GMP UNKNOWN IMPORTED) 48 | set_target_properties(mp++::GMP PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${MPPP_GMP_INCLUDE_DIR}" 49 | IMPORTED_LINK_INTERFACE_LANGUAGES "C" IMPORTED_LOCATION "${MPPP_GMP_LIBRARY}") 50 | endif() 51 | -------------------------------------------------------------------------------- /cmake/Findmp++_MPC.cmake: -------------------------------------------------------------------------------- 1 | # Originally copied from the KDE project repository: 2 | # http://websvn.kde.org/trunk/KDE/kdeutils/cmake/modules/FindGMP.cmake?view=markup&pathrev=675218 3 | 4 | # Copyright (c) 2006, Laurent Montel, 5 | # Copyright (c) 2008-2023 Francesco Biscani, 6 | 7 | # Redistribution and use in source and binary forms, with or without 8 | # modification, are permitted provided that the following conditions 9 | # are met: 10 | # 11 | # 1. Redistributions of source code must retain the copyright 12 | # notice, this list of conditions and the following disclaimer. 13 | # 2. Redistributions in binary form must reproduce the copyright 14 | # notice, this list of conditions and the following disclaimer in the 15 | # documentation and/or other materials provided with the distribution. 16 | # 3. The name of the author may not be used to endorse or promote products 17 | # derived from this software without specific prior written permission. 18 | # 19 | # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 20 | # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21 | # OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22 | # IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 23 | # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 24 | # NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28 | # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | # ------------------------------------------------------------------------------------------ 30 | 31 | if(MPPP_MPC_INCLUDE_DIR AND MPPP_MPC_LIBRARY) 32 | # Already in cache, be silent 33 | set(mp++_MPC_FIND_QUIETLY TRUE) 34 | endif() 35 | 36 | find_path(MPPP_MPC_INCLUDE_DIR NAMES mpc.h) 37 | find_library(MPPP_MPC_LIBRARY NAMES mpc) 38 | 39 | include(FindPackageHandleStandardArgs) 40 | 41 | find_package_handle_standard_args(mp++_MPC DEFAULT_MSG MPPP_MPC_INCLUDE_DIR MPPP_MPC_LIBRARY) 42 | 43 | mark_as_advanced(MPPP_MPC_INCLUDE_DIR MPPP_MPC_LIBRARY) 44 | 45 | # NOTE: this has been adapted from CMake's FindPNG.cmake. 46 | if(mp++_MPC_FOUND AND NOT TARGET mp++::MPC) 47 | add_library(mp++::MPC UNKNOWN IMPORTED) 48 | set_target_properties(mp++::MPC PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${MPPP_MPC_INCLUDE_DIR}" 49 | IMPORTED_LINK_INTERFACE_LANGUAGES "C" IMPORTED_LOCATION "${MPPP_MPC_LIBRARY}") 50 | endif() 51 | -------------------------------------------------------------------------------- /cmake/Findmp++_MPFR.cmake: -------------------------------------------------------------------------------- 1 | # Originally copied from the KDE project repository: 2 | # http://websvn.kde.org/trunk/KDE/kdeutils/cmake/modules/FindGMP.cmake?view=markup&pathrev=675218 3 | 4 | # Copyright (c) 2006, Laurent Montel, 5 | # Copyright (c) 2008-2023 Francesco Biscani, 6 | 7 | # Redistribution and use in source and binary forms, with or without 8 | # modification, are permitted provided that the following conditions 9 | # are met: 10 | # 11 | # 1. Redistributions of source code must retain the copyright 12 | # notice, this list of conditions and the following disclaimer. 13 | # 2. Redistributions in binary form must reproduce the copyright 14 | # notice, this list of conditions and the following disclaimer in the 15 | # documentation and/or other materials provided with the distribution. 16 | # 3. The name of the author may not be used to endorse or promote products 17 | # derived from this software without specific prior written permission. 18 | # 19 | # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 20 | # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21 | # OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22 | # IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 23 | # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 24 | # NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28 | # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | # ------------------------------------------------------------------------------------------ 30 | 31 | if(MPPP_MPFR_INCLUDE_DIR AND MPPP_MPFR_LIBRARY) 32 | # Already in cache, be silent 33 | set(mp++_MPFR_FIND_QUIETLY TRUE) 34 | endif() 35 | 36 | find_path(MPPP_MPFR_INCLUDE_DIR NAMES mpfr.h) 37 | find_library(MPPP_MPFR_LIBRARY NAMES mpfr) 38 | 39 | include(FindPackageHandleStandardArgs) 40 | 41 | find_package_handle_standard_args(mp++_MPFR DEFAULT_MSG MPPP_MPFR_INCLUDE_DIR MPPP_MPFR_LIBRARY) 42 | 43 | mark_as_advanced(MPPP_MPFR_INCLUDE_DIR MPPP_MPFR_LIBRARY) 44 | 45 | # NOTE: this has been adapted from CMake's FindPNG.cmake. 46 | if(mp++_MPFR_FOUND AND NOT TARGET mp++::MPFR) 47 | add_library(mp++::MPFR UNKNOWN IMPORTED) 48 | set_target_properties(mp++::MPFR PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${MPPP_MPFR_INCLUDE_DIR}" 49 | IMPORTED_LINK_INTERFACE_LANGUAGES "C" IMPORTED_LOCATION "${MPPP_MPFR_LIBRARY}") 50 | endif() 51 | -------------------------------------------------------------------------------- /cmake/Findmp++_quadmath.cmake: -------------------------------------------------------------------------------- 1 | # Originally copied from the KDE project repository: 2 | # http://websvn.kde.org/trunk/KDE/kdeutils/cmake/modules/FindGMP.cmake?view=markup&pathrev=675218 3 | 4 | # Copyright (c) 2006, Laurent Montel, 5 | # Copyright (c) 2008-2023 Francesco Biscani, 6 | 7 | # Redistribution and use in source and binary forms, with or without 8 | # modification, are permitted provided that the following conditions 9 | # are met: 10 | # 11 | # 1. Redistributions of source code must retain the copyright 12 | # notice, this list of conditions and the following disclaimer. 13 | # 2. Redistributions in binary form must reproduce the copyright 14 | # notice, this list of conditions and the following disclaimer in the 15 | # documentation and/or other materials provided with the distribution. 16 | # 3. The name of the author may not be used to endorse or promote products 17 | # derived from this software without specific prior written permission. 18 | # 19 | # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 20 | # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21 | # OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22 | # IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 23 | # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 24 | # NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28 | # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | # ------------------------------------------------------------------------------------------ 30 | 31 | include(FindPackageHandleStandardArgs) 32 | include(CMakePushCheckState) 33 | include(CheckCXXSourceCompiles) 34 | 35 | if(MPPP_QUADMATH_INCLUDE_DIR AND MPPP_QUADMATH_LIBRARY) 36 | # Already in cache, be silent 37 | set(mp++_quadmath_FIND_QUIETLY TRUE) 38 | endif() 39 | 40 | find_path(MPPP_QUADMATH_INCLUDE_DIR NAMES quadmath.h) 41 | find_library(MPPP_QUADMATH_LIBRARY NAMES quadmath) 42 | 43 | if(NOT MPPP_QUADMATH_INCLUDE_DIR OR NOT MPPP_QUADMATH_LIBRARY) 44 | cmake_push_check_state(RESET) 45 | list(APPEND CMAKE_REQUIRED_LIBRARIES "quadmath") 46 | CHECK_CXX_SOURCE_COMPILES(" 47 | #include 48 | int main(void){ 49 | __float128 foo = ::sqrtq(123.456); 50 | }" 51 | MPPP_QUADMATH_USE_DIRECTLY 52 | ) 53 | cmake_pop_check_state() 54 | if (MPPP_QUADMATH_USE_DIRECTLY) 55 | set(MPPP_QUADMATH_INCLUDE_DIR "unused" CACHE PATH "" FORCE) 56 | set(MPPP_QUADMATH_LIBRARY "quadmath" CACHE FILEPATH "" FORCE) 57 | endif() 58 | endif() 59 | 60 | find_package_handle_standard_args(mp++_quadmath DEFAULT_MSG MPPP_QUADMATH_LIBRARY MPPP_QUADMATH_INCLUDE_DIR) 61 | 62 | mark_as_advanced(MPPP_QUADMATH_INCLUDE_DIR MPPP_QUADMATH_LIBRARY) 63 | 64 | # NOTE: this has been adapted from CMake's FindPNG.cmake. 65 | if(mp++_quadmath_FOUND AND NOT TARGET mp++::quadmath) 66 | message(STATUS "Creating the 'mp++::quadmath' imported target.") 67 | if(MPPP_QUADMATH_USE_DIRECTLY) 68 | message(STATUS "libquadmath will be included and linked directly.") 69 | # If we are using it directly, we must define an interface library, 70 | # as we do not have the full path to the shared library. 71 | add_library(mp++::quadmath INTERFACE IMPORTED) 72 | set_target_properties(mp++::quadmath PROPERTIES INTERFACE_LINK_LIBRARIES "${MPPP_QUADMATH_LIBRARY}") 73 | else() 74 | # Otherwise, we proceed as usual. 75 | add_library(mp++::quadmath UNKNOWN IMPORTED) 76 | set_target_properties(mp++::quadmath PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${MPPP_QUADMATH_INCLUDE_DIR}" 77 | IMPORTED_LINK_INTERFACE_LANGUAGES "C" 78 | IMPORTED_LOCATION "${MPPP_QUADMATH_LIBRARY}") 79 | endif() 80 | endif() 81 | -------------------------------------------------------------------------------- /cmake/yacma/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016-2022 Francesco Biscani 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /cmake/yacma/README.md: -------------------------------------------------------------------------------- 1 | # yacma 2 | 3 | Yet another CMake modules archive. 4 | -------------------------------------------------------------------------------- /cmake/yacma/YACMAThreadingSetup.cmake: -------------------------------------------------------------------------------- 1 | if(YACMAThreadingSetupIncluded) 2 | return() 3 | endif() 4 | 5 | include(YACMACompilerLinkerSettings) 6 | 7 | # Initial thread setup. See FindThreads.cmake for an explanation. 8 | set(THREADS_PREFER_PTHREAD_FLAG YES) 9 | find_package(Threads REQUIRED) 10 | unset(THREADS_PREFER_PTHREAD_FLAG) 11 | message(STATUS "Thread library: ${CMAKE_THREAD_LIBS_INIT}") 12 | 13 | # Setup variable for threading-specific flags. 14 | set(YACMA_THREADING_CXX_FLAGS) 15 | 16 | # POSIX thread setup. Intended both for UNIX and Windows (the latter when using some sort of 17 | # pthread emulation/wrapper like pthreads-win32). 18 | if(CMAKE_USE_PTHREADS_INIT) 19 | message(STATUS "POSIX threads detected.") 20 | # Detect affinity setting primitives. 21 | include(CheckCXXSymbolExists) 22 | set(CMAKE_REQUIRED_LIBRARIES "${CMAKE_THREAD_LIBS_INIT}") 23 | CHECK_CXX_SYMBOL_EXISTS("pthread_setaffinity_np" "pthread.h" _YACMA_HAVE_PTHREAD_SETAFFINITY) 24 | CHECK_CXX_SYMBOL_EXISTS("pthread_getaffinity_np" "pthread.h" _YACMA_HAVE_PTHREAD_GETAFFINITY) 25 | unset(CMAKE_REQUIRED_LIBRARIES) 26 | if(_YACMA_HAVE_PTHREAD_SETAFFINITY AND _YACMA_HAVE_PTHREAD_GETAFFINITY) 27 | set(YACMA_HAVE_PTHREAD_AFFINITY YES) 28 | else() 29 | set(YACMA_HAVE_PTHREAD_AFFINITY NO) 30 | endif() 31 | if(YACMA_HAVE_PTHREAD_AFFINITY) 32 | message(STATUS "POSIX threads affinity extensions detected.") 33 | else() 34 | message(STATUS "POSIX threads affinity extensions NOT detected.") 35 | endif() 36 | endif() 37 | 38 | if(MINGW) 39 | message(STATUS "Enabling the '-mthreads' flag for MinGW.") 40 | list(APPEND YACMA_THREADING_CXX_FLAGS "-mthreads") 41 | endif() 42 | 43 | # Check if we have thread_local. 44 | # NOTE: we need to double check what happens with OSX's clang here. 45 | list(FIND CMAKE_CXX_COMPILE_FEATURES "cxx_thread_local" YACMA_HAVE_THREAD_LOCAL) 46 | if(${YACMA_HAVE_THREAD_LOCAL} EQUAL -1) 47 | message(STATUS "The 'thread_local' keyword is NOT supported.") 48 | set(YACMA_HAVE_THREAD_LOCAL NO) 49 | else() 50 | message(STATUS "The 'thread_local' keyword is supported.") 51 | set(YACMA_HAVE_THREAD_LOCAL YES) 52 | endif() 53 | 54 | # Final report. 55 | if(YACMA_THREADING_CXX_FLAGS) 56 | message(STATUS "Extra compiler flags for threading: ${YACMA_THREADING_CXX_FLAGS}") 57 | endif() 58 | 59 | # Mark as included. 60 | set(YACMAThreadingSetupIncluded YES) 61 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | coverage: 2 | ignore: 3 | - "test/*" 4 | - "include/mp.*/extra" 5 | 6 | comment: off 7 | -------------------------------------------------------------------------------- /doc/_static/integer1_dot_product_signed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bluescarni/mppp/a85be780cffa57382cd36ee692d55b35d2088505/doc/_static/integer1_dot_product_signed.png -------------------------------------------------------------------------------- /doc/_static/integer1_dot_product_unsigned.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bluescarni/mppp/a85be780cffa57382cd36ee692d55b35d2088505/doc/_static/integer1_dot_product_unsigned.png -------------------------------------------------------------------------------- /doc/_static/integer1_sort_signed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bluescarni/mppp/a85be780cffa57382cd36ee692d55b35d2088505/doc/_static/integer1_sort_signed.png -------------------------------------------------------------------------------- /doc/_static/integer1_sort_unsigned.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bluescarni/mppp/a85be780cffa57382cd36ee692d55b35d2088505/doc/_static/integer1_sort_unsigned.png -------------------------------------------------------------------------------- /doc/_static/integer1_vec_div_signed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bluescarni/mppp/a85be780cffa57382cd36ee692d55b35d2088505/doc/_static/integer1_vec_div_signed.png -------------------------------------------------------------------------------- /doc/_static/integer1_vec_div_unsigned.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bluescarni/mppp/a85be780cffa57382cd36ee692d55b35d2088505/doc/_static/integer1_vec_div_unsigned.png -------------------------------------------------------------------------------- /doc/_static/integer1_vec_gcd_signed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bluescarni/mppp/a85be780cffa57382cd36ee692d55b35d2088505/doc/_static/integer1_vec_gcd_signed.png -------------------------------------------------------------------------------- /doc/_static/integer1_vec_lcm_signed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bluescarni/mppp/a85be780cffa57382cd36ee692d55b35d2088505/doc/_static/integer1_vec_lcm_signed.png -------------------------------------------------------------------------------- /doc/_static/integer1_vec_lshift_signed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bluescarni/mppp/a85be780cffa57382cd36ee692d55b35d2088505/doc/_static/integer1_vec_lshift_signed.png -------------------------------------------------------------------------------- /doc/_static/integer1_vec_lshift_unsigned.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bluescarni/mppp/a85be780cffa57382cd36ee692d55b35d2088505/doc/_static/integer1_vec_lshift_unsigned.png -------------------------------------------------------------------------------- /doc/_static/integer1_vec_mul_signed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bluescarni/mppp/a85be780cffa57382cd36ee692d55b35d2088505/doc/_static/integer1_vec_mul_signed.png -------------------------------------------------------------------------------- /doc/_static/integer1_vec_mul_unsigned.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bluescarni/mppp/a85be780cffa57382cd36ee692d55b35d2088505/doc/_static/integer1_vec_mul_unsigned.png -------------------------------------------------------------------------------- /doc/_static/integer2_dot_product_signed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bluescarni/mppp/a85be780cffa57382cd36ee692d55b35d2088505/doc/_static/integer2_dot_product_signed.png -------------------------------------------------------------------------------- /doc/_static/integer2_dot_product_unsigned.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bluescarni/mppp/a85be780cffa57382cd36ee692d55b35d2088505/doc/_static/integer2_dot_product_unsigned.png -------------------------------------------------------------------------------- /doc/_static/integer2_sort_signed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bluescarni/mppp/a85be780cffa57382cd36ee692d55b35d2088505/doc/_static/integer2_sort_signed.png -------------------------------------------------------------------------------- /doc/_static/integer2_sort_unsigned.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bluescarni/mppp/a85be780cffa57382cd36ee692d55b35d2088505/doc/_static/integer2_sort_unsigned.png -------------------------------------------------------------------------------- /doc/_static/integer2_vec_div_signed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bluescarni/mppp/a85be780cffa57382cd36ee692d55b35d2088505/doc/_static/integer2_vec_div_signed.png -------------------------------------------------------------------------------- /doc/_static/integer2_vec_div_unsigned.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bluescarni/mppp/a85be780cffa57382cd36ee692d55b35d2088505/doc/_static/integer2_vec_div_unsigned.png -------------------------------------------------------------------------------- /doc/_static/integer2_vec_lshift_signed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bluescarni/mppp/a85be780cffa57382cd36ee692d55b35d2088505/doc/_static/integer2_vec_lshift_signed.png -------------------------------------------------------------------------------- /doc/_static/integer2_vec_lshift_unsigned.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bluescarni/mppp/a85be780cffa57382cd36ee692d55b35d2088505/doc/_static/integer2_vec_lshift_unsigned.png -------------------------------------------------------------------------------- /doc/_static/integer2_vec_mul_signed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bluescarni/mppp/a85be780cffa57382cd36ee692d55b35d2088505/doc/_static/integer2_vec_mul_signed.png -------------------------------------------------------------------------------- /doc/_static/integer2_vec_mul_unsigned.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bluescarni/mppp/a85be780cffa57382cd36ee692d55b35d2088505/doc/_static/integer2_vec_mul_unsigned.png -------------------------------------------------------------------------------- /doc/benchmarks.rst: -------------------------------------------------------------------------------- 1 | .. _benchmarks: 2 | 3 | Benchmarks 4 | ========== 5 | 6 | This section contains various benchmarks comparing mp++ to other multiprecision libraries. All benchmarks 7 | were run on an AMD Ryzen 3950x in a 64-bit GNU/Linux environment, using the GCC compiler. 8 | The benchmarking code is available `here `__. 9 | 10 | The benchmark results were last updated on **20200609**, using the following package versions: 11 | 12 | * GCC 10.1, 13 | * mp++ 0.21, 14 | * GMP 6.2.0, 15 | * Boost 1.73.0, 16 | * FLINT 2.5.2. 17 | 18 | .. toctree:: 19 | :maxdepth: 2 20 | 21 | integer_benchmarks.rst 22 | -------------------------------------------------------------------------------- /doc/concepts.rst: -------------------------------------------------------------------------------- 1 | Common concepts 2 | =============== 3 | 4 | .. note:: 5 | 6 | Generic functions and classes in mp++ support `concepts `__ 7 | to constrain the types with which they can be used. C++ concepts are part of the C++20 standard, and they are 8 | currently available only on GCC>=6, Clang>=10 and MSVC>=16.3. When used with compilers which do not 9 | support concepts natively, mp++ will employ a concept emulation layer in order to provide the same functionality as native 10 | C++ concepts. 11 | 12 | Since the syntax of native C++ concepts is clearer than that of the concept emulation layer, the mp++ documentation describes 13 | and refers to concepts in their native C++ form. 14 | 15 | *#include * 16 | 17 | .. cpp:concept:: template mppp::cpp_integral 18 | 19 | This concept is satisfied if ``T`` is an integral C++ type. 20 | 21 | The GCC-style extended 128-bit integral types ``__int128_t`` and ``__uint128_t`` are included as well, if supported 22 | on the current platform/compiler combination (see also the :c:macro:`MPPP_HAVE_GCC_INT128` definition). 23 | 24 | .. cpp:concept:: template mppp::cpp_unsigned_integral 25 | 26 | This concept is satisfied if ``T`` is an unsigned :cpp:concept:`~mppp::cpp_integral`. 27 | 28 | .. cpp:concept:: template mppp::cpp_signed_integral 29 | 30 | This concept is satisfied if ``T`` is a signed :cpp:concept:`~mppp::cpp_integral`. 31 | 32 | .. cpp:concept:: template mppp::cpp_floating_point 33 | 34 | This concept is satisfied if ``T`` is a floating-point C++ type. 35 | 36 | .. cpp:concept:: template mppp::cpp_arithmetic 37 | 38 | This concept is satisfied if ``T`` is either a :cpp:concept:`~mppp::cpp_integral` or 39 | a :cpp:concept:`~mppp::cpp_floating_point` type. 40 | 41 | .. cpp:concept:: template mppp::cpp_complex 42 | 43 | This concept is satisfied if ``T`` is one of the standard complex C++ types: 44 | 45 | * ``std::complex``, 46 | * ``std::complex``, 47 | * ``std::complex``. 48 | 49 | .. cpp:concept:: template mppp::string_type 50 | 51 | This concept is satisfied by C++ string-like types. Specifically, the concept will be true if ``T``, 52 | after the removal of cv qualifiers, is one of the following types: 53 | 54 | * ``std::string``, 55 | * a pointer to (possibly cv qualified) ``char``, 56 | * a ``char`` array of any size. 57 | 58 | Additionally, if at least C++17 is being used, the concept is satisfied also by ``std::string_view`` 59 | (see also the :c:macro:`MPPP_HAVE_STRING_VIEW` definition). 60 | -------------------------------------------------------------------------------- /doc/exceptions.rst: -------------------------------------------------------------------------------- 1 | .. _exceptions: 2 | 3 | Exceptions 4 | ========== 5 | 6 | *#include * 7 | 8 | .. cpp:class:: mppp::zero_division_error final : public std::domain_error 9 | 10 | Exception to signal division by zero. 11 | 12 | This exception inherits all members (including constructors) from 13 | `std::domain_error `_. It will be thrown 14 | when a division by zero involving a multiprecision class is attempted, and the type of the result cannot 15 | represent infinities. 16 | -------------------------------------------------------------------------------- /doc/fwd_decl.rst: -------------------------------------------------------------------------------- 1 | Forward declarations 2 | ==================== 3 | 4 | .. versionadded:: 0.22 5 | 6 | *#include * 7 | 8 | The ``fwd.hpp`` header contains the forward declarations of all 9 | the multiprecision number classes implemented in mp++. 10 | -------------------------------------------------------------------------------- /doc/index.rst: -------------------------------------------------------------------------------- 1 | .. mp++ documentation master file, created by 2 | sphinx-quickstart on Fri Dec 23 14:58:38 2016. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | mp++ 7 | ==== 8 | 9 | mp++ is a C++11/14/17/20 library for multiprecision arithmetic, 10 | featuring: 11 | 12 | * arbitrary-precision integers, 13 | * arbitrary-precision rationals, 14 | * quadruple-precision floats, 15 | * quadruple-precision complex numbers, 16 | * arbitrary-precision floats, 17 | * arbitrary-precision complex numbers. 18 | 19 | Design goals include: 20 | 21 | * excellent performance for small integer and rational 22 | operands, 23 | * easy embeddability in computer algebra systems and 24 | generic C++ libraries, 25 | * a large collection of arbitrary-precision special functions, 26 | * an ergonomic API based on modern C++ idioms. 27 | 28 | Design non-goals include: 29 | 30 | * support for fixed-size wide integrals (i.e., no ``uint512_t``, 31 | try `Boost Multiprecision `__ 32 | instead). 33 | 34 | Built on top of the GNU multiprecision stack (`GMP `__, 35 | `MPFR `__, `MPC `__), 36 | mp++ was initially conceived as a GMP wrapper with special focus on performance with 37 | small operands. In particular, a small buffer optimisation and custom 38 | implementations of basic mathematical primitives are instrumental in 39 | achieving a performance increase, with respect to GMP and other integer 40 | multiprecision libraries, which can be 41 | substantial (see the :ref:`benchmarks ` section). 42 | 43 | Over time, mp++ has accrued many additional features, including 44 | multiprecision real and complex number types, and an expanding 45 | library of special functions (built in part on top of the excellent 46 | `Arb `__ library). 47 | 48 | mp++ is a spinoff of the `Piranha `__ library, released under the 49 | `MPL2 `__ license. 50 | If you are using mp++ as part of your research, teaching, or other 51 | activities, we would be grateful if you could star 52 | the repository and/or cite our work. The DOI of the latest version 53 | and other citation resources are available 54 | at `this link `__. 55 | 56 | .. note:: 57 | 58 | This documentation refers to the latest development version of mp++, and it may describe features 59 | not yet available in mp++'s stable releases. 60 | 61 | .. toctree:: 62 | :maxdepth: 1 63 | 64 | installation.rst 65 | tutorial.rst 66 | interactive_notebooks.rst 67 | reference.rst 68 | benchmarks.rst 69 | changelog.rst 70 | -------------------------------------------------------------------------------- /doc/interactive_notebooks.rst: -------------------------------------------------------------------------------- 1 | .. _interactive notebooks: 2 | 3 | Interactive notebooks 4 | ===================== 5 | 6 | .. only:: html 7 | 8 | .. important:: 9 | 10 | .. raw:: html 11 | 12 |

13 | These tutorials can be launched as online interactive notebooks 14 | thanks to the infrastructure provided by binder. 15 | Look for the rocket icon on top of each page! 16 |

17 | 18 | Integer 19 | ------- 20 | 21 | .. toctree:: 22 | :maxdepth: 1 23 | 24 | notebooks/integer_basics 25 | notebooks/integer_formatted_output 26 | notebooks/integer_arithmetic 27 | notebooks/integer_comparison 28 | notebooks/integer_bit_fiddling 29 | notebooks/integer_s11n 30 | 31 | Real 32 | ---- 33 | 34 | .. toctree:: 35 | :maxdepth: 1 36 | 37 | notebooks/real_basics 38 | -------------------------------------------------------------------------------- /doc/namespaces.rst: -------------------------------------------------------------------------------- 1 | Namespaces 2 | ========== 3 | 4 | All the functionality of the library is included within the ``mppp`` namespace. 5 | The ``inline`` namespace ``mppp::literals`` contains user-defined literals 6 | for the mp++ classes. 7 | 8 | 9 | .. versionadded:: 0.18 10 | 11 | The ``mppp::literals`` inline namespace. 12 | -------------------------------------------------------------------------------- /doc/reference.rst: -------------------------------------------------------------------------------- 1 | .. _reference: 2 | 3 | Reference 4 | ========= 5 | 6 | The following subsections contain the detailed documentation of all of mp++'s public classes and functions. 7 | Before perusing the C++ reference, users are encouraged to first go through the :ref:`tutorial `. 8 | 9 | .. toctree:: 10 | :maxdepth: 1 11 | 12 | versioning.rst 13 | definitions.rst 14 | namespaces.rst 15 | exceptions.rst 16 | concepts.rst 17 | integer.rst 18 | rational.rst 19 | real128.rst 20 | complex128.rst 21 | real.rst 22 | complex.rst 23 | utilities.rst 24 | fwd_decl.rst 25 | -------------------------------------------------------------------------------- /doc/tutorial.rst: -------------------------------------------------------------------------------- 1 | .. _tutorial: 2 | 3 | Tutorial 4 | ======== 5 | 6 | The tutorial is split into several subsections, and it is meant to be read 7 | in a sequential fashion. Users are encouraged to read the tutorial before moving 8 | on to the full :ref:`C++ reference `. 9 | 10 | .. toctree:: 11 | :maxdepth: 1 12 | 13 | tutorial_prelim.rst 14 | tutorial_constr.rst 15 | tutorial_io.rst 16 | tutorial_numtower.rst 17 | tutorial_commonops.rst 18 | tutorial_api.rst 19 | tutorial_integer.rst 20 | tutorial_rational.rst 21 | tutorial_real128.rst 22 | tutorial_complex128.rst 23 | tutorial_real.rst 24 | tutorial_complex.rst 25 | tutorial_boost_s11n.rst 26 | tutorial_pybind11.rst 27 | -------------------------------------------------------------------------------- /doc/tutorial_boost_s11n.rst: -------------------------------------------------------------------------------- 1 | .. _tutorial_boost_s11n: 2 | 3 | Boost.serialization support 4 | =========================== 5 | 6 | Starting from version 0.22, all of mp++'s multiprecision classes support (de)serialisation 7 | via the `Boost.serialization `_ 8 | library, provided that mp++ was compiled with the ``MPPP_WITH_BOOST_S11N`` option enabled 9 | (see the :ref:`installation instructions `). We refer to the documentation 10 | of Boost.serialization (particularly the 11 | `tutorial `_) 12 | for usage examples. Note that, as detailed in the previous sections, 13 | certain classes (such as :cpp:class:`~mppp::integer` and 14 | :cpp:class:`~mppp::real`) also provide a separate, low-level binary serialisation API 15 | which does not depend on Boost.serialization. 16 | 17 | There is an important **caveat** to keep in mind when using mp++'s Boost.serialization support. 18 | The serialisation to/from binary archives is optimised for speed, and no checks are performed 19 | on the validity of the data that is loaded from a binary archive. In other words, a 20 | maliciously-crafted binary archive could lead to the creation of an invalid mp++ object 21 | whose use could then lead to undefined and/or erratic runtime behaviour. Users are thus 22 | advised not to load data from untrusted binary archives. Non-binary archives do not suffer from 23 | these issues. 24 | -------------------------------------------------------------------------------- /doc/tutorial_complex.rst: -------------------------------------------------------------------------------- 1 | .. _tutorial_complex: 2 | 3 | Multiprecision complex numbers tutorial 4 | ======================================= 5 | 6 | TBD 7 | -------------------------------------------------------------------------------- /doc/tutorial_complex128.rst: -------------------------------------------------------------------------------- 1 | .. _tutorial_complex128: 2 | 3 | Quadruple-precision complex numbers tutorial 4 | ============================================ 5 | 6 | TBD 7 | -------------------------------------------------------------------------------- /doc/tutorial_io.rst: -------------------------------------------------------------------------------- 1 | Input and output 2 | ================ 3 | 4 | All of mp++'s multiprecision classes support stream insertion: 5 | 6 | .. code-block:: c++ 7 | 8 | std::cout << int_t{42} << '\n'; // "42" 9 | std::cout << rat_t{-6, 7} << '\n'; // "-6/7" 10 | std::cout << real128{"1.1"} << '\n'; // "1.10000000000000000000000000000000008e+00" 11 | std::cout << real{"1.3", 150} << '\n'; // "1.3000000000000000000000000000000000000000000006" 12 | 13 | Starting from mp++ 0.14, :cpp:class:`~mppp::integer` and :cpp:class:`~mppp::rational` 14 | honour the format flags in output streams: 15 | 16 | .. code-block:: c++ 17 | 18 | #include 19 | #include 20 | 21 | std::cout << std::hex << std::showbase << int_t{42} << '\n'; // "0x2a" 22 | std::cout << std::oct << std::showbase << std::showpos 23 | << std::setw(10) << std::setfill('*') 24 | << int_t{42} << '\n'; // "******+052" 25 | std::cout << std::hex << std::showbase << std::uppercase 26 | << rat_t{227191947ll, 13} << '\n'; // "0XD8AAC8B/0XD" 27 | 28 | Starting from mp++ 0.24, the real and complex floating-point classes also honour the 29 | format flags in output streams: 30 | 31 | .. code-block:: c++ 32 | 33 | #include 34 | #include 35 | 36 | std::cout << std::scientific << std::setprecision(6) << real{1 / 3.} << '\n'; // "3.333333e-01" 37 | std::cout << std::hexfloat << std::uppercase << complex{1.1, 1.3} << '\n'; // "(0X1.199999999999AP+0,0X1.4CCCCCCCCCCCDP+0)" 38 | std::cout << std::fixed << std::showpoint << std::showpos << 42_rq << '\n'; // "+42.000000" 39 | 40 | Starting from mp++ 0.27, all of mp++'s multiprecision classes support formatting via the 41 | `{fmt} `__ library, provided that mp++ has been built with 42 | the ``MPPP_WITH_FMT`` option enabled (see the :ref:`installation instructions `): 43 | 44 | .. code-block:: c++ 45 | 46 | #include 47 | 48 | #include 49 | 50 | std::cout << fmt::format("The answer is {}", int_t{42}); // "The answer is 42" 51 | 52 | All of mp++'s multiprecision classes also provide ``to_string()`` member functions that convert the multiprecision 53 | values into string representations (see, e.g., :cpp:func:`mppp::integer::to_string()`, :cpp:func:`mppp::rational::to_string()`, 54 | etc.). These member functions always return a round-tripping string representation of the multiprecision value: feeding back 55 | the string representation to a constructor from string will initialise a value identical to the original one. 56 | -------------------------------------------------------------------------------- /doc/tutorial_prelim.rst: -------------------------------------------------------------------------------- 1 | Preliminaries 2 | ============= 3 | 4 | In this tutorial, we will assume that the global mp++ header has been included: 5 | 6 | .. code-block:: c++ 7 | 8 | #include 9 | 10 | The ``mp++.hpp`` header will pull in the public mp++ API in its entirety. 11 | It is also possible to include individual mp++ headers instead of ``mp++.hpp``, e.g.: 12 | 13 | .. code-block:: c++ 14 | 15 | #include // For the integer multiprecision class 16 | // and associated functions. 17 | #include // For the rational multiprecision class 18 | // and associated functions. 19 | 20 | Including individual headers rather than the global ``mp++.hpp`` header is in general a good idea 21 | if you don't need all the features provided by mp++, and it may improve compilation times. 22 | 23 | .. warning:: 24 | 25 | Do **not** include headers from the ``mp++/detail`` subdirectory! They contain 26 | implementation details which may change from version to version in incompatible ways. 27 | 28 | We will also assume, for convenience, that mp++'s multiprecision classes have been lifted into the root namespace, 29 | and we will introduce a couple of handy aliases for the :cpp:class:`~mppp::integer` and :cpp:class:`~mppp::rational` 30 | classes: 31 | 32 | .. code-block:: c++ 33 | 34 | using int_t = mppp::integer<1>; 35 | using rat_t = mppp::rational<1>; 36 | 37 | :cpp:class:`~mppp::integer` and :cpp:class:`~mppp::rational` are class templates parametrised over a positive 38 | integral value (referred to as *static size*) which indicates how many limbs will be stored in static storage 39 | before resorting to dynamic memory allocation. In the definitions above, ``int_t`` and ``rat_t`` will store 40 | values of size up to 1 limb without resorting to heap memory allocation. On modern 64-bit architectures, 41 | this means in practice that ``int_t`` will be able to represent in static storage integers whose absolute 42 | value is less than :math:`2^{64}`. A static size of 1 is a good default choice. 43 | 44 | In this tutorial, we will **not** assume that mp++'s functions have been pulled into the global namespace: the mp++ 45 | API is designed around `argument-dependent lookup `__, 46 | which means it is usually possible to call mp++'s functions without prepending ``mppp::`` or employing ``using`` 47 | directives. 48 | -------------------------------------------------------------------------------- /doc/utilities.rst: -------------------------------------------------------------------------------- 1 | Utility functions 2 | ================= 3 | 4 | .. cpp:function:: template std::string mppp::type_name() 5 | 6 | This function will return a string representation 7 | for the name of the input type ``T``. 8 | 9 | If supported by the 10 | current platform/compiler combination, the returned string 11 | will be a human-readable (i.e., demangled) identifier. Otherwise, 12 | a string based on ``typeid(T).name()`` will be returned. 13 | 14 | Example: 15 | 16 | .. code-block:: c++ 17 | 18 | std::cout << type_name() << '\n'; // Prints "std::string const*" on Linux. 19 | 20 | :return: a string representation for the type ``T``. 21 | 22 | :exception unspecified: any exception raised by memory allocation failures. 23 | -------------------------------------------------------------------------------- /doc/versioning.rst: -------------------------------------------------------------------------------- 1 | Versioning 2 | ========== 3 | 4 | Beginning with version 1.0.0, mp++ adopts `semantic versioning `__. 5 | 6 | ABI compatibility is guaranteed only between patch versions. 7 | -------------------------------------------------------------------------------- /environment.yml: -------------------------------------------------------------------------------- 1 | channels: 2 | - conda-forge 3 | dependencies: 4 | - mppp=0.26 5 | - xeus-cling 6 | - jupyterlab 7 | - nlohmann_json 8 | -------------------------------------------------------------------------------- /include/mp++/detail/fmt.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016-2023 Francesco Biscani (bluescarni@gmail.com) 2 | // 3 | // This file is part of the mp++ library. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla 6 | // Public License v. 2.0. If a copy of the MPL was not distributed 7 | // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | #ifndef MPPP_DETAIL_FMT_HPP 10 | #define MPPP_DETAIL_FMT_HPP 11 | 12 | #include 13 | 14 | #include 15 | 16 | #include 17 | 18 | MPPP_BEGIN_NAMESPACE 19 | 20 | namespace detail 21 | { 22 | 23 | struct to_string_formatter { 24 | template 25 | MPPP_CONSTEXPR_20 auto parse(ParseContext &ctx) -> decltype(ctx.begin()) 26 | { 27 | auto it = ctx.begin(); 28 | const auto end = ctx.end(); 29 | 30 | // Handle the special case for the '{}' format string. 31 | if (it == end) { 32 | return it; 33 | } 34 | 35 | // Parse until we get to the end or we find 36 | // the closing bracket '}', ignoring the format 37 | // string. 38 | for (; it != end; ++it) { 39 | if (*it == '}') { 40 | // NOTE: according to the docs, we must return 41 | // an iterator pointing to '}'. 42 | return it; 43 | } 44 | } 45 | 46 | // LCOV_EXCL_START 47 | 48 | // NOTE: strangely enough, fmt::throw_format_error() was promoted 49 | // to the public API in fmt 10 and then promptly deprecated. 50 | #if FMT_VERSION < 100000 || FMT_VERSION >= 110000 51 | throw std::invalid_argument("Invalid format"); 52 | #else 53 | fmt::throw_format_error("Invalid format"); 54 | #endif 55 | 56 | return it; 57 | 58 | // LCOV_EXCL_STOP 59 | } 60 | 61 | template 62 | auto format(const T &x, FormatContext &ctx) const -> decltype(ctx.out()) 63 | { 64 | return fmt::format_to(ctx.out(), "{}", x.to_string()); 65 | } 66 | }; 67 | 68 | } // namespace detail 69 | 70 | MPPP_END_NAMESPACE 71 | 72 | #endif 73 | -------------------------------------------------------------------------------- /include/mp++/detail/gmp.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016-2023 Francesco Biscani (bluescarni@gmail.com) 2 | // 3 | // This file is part of the mp++ library. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla 6 | // Public License v. 2.0. If a copy of the MPL was not distributed 7 | // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | #ifndef MPPP_DETAIL_GMP_HPP 10 | #define MPPP_DETAIL_GMP_HPP 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | 18 | #include 19 | 20 | #if __GNU_MP_VERSION < 5 21 | 22 | #error Minimum supported GMP version is 5. 23 | 24 | #endif 25 | 26 | MPPP_BEGIN_NAMESPACE 27 | 28 | namespace detail 29 | { 30 | 31 | // mpz_t is an array of some struct. 32 | using mpz_struct_t = std::remove_extent<::mpz_t>::type; 33 | // Integral types used for allocation size and number of limbs. 34 | using mpz_alloc_t = decltype(std::declval()._mp_alloc); 35 | using mpz_size_t = decltype(std::declval()._mp_size); 36 | 37 | // Simple RAII holder for GMP integers. 38 | struct mpz_raii { 39 | // NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init, hicpp-member-init) 40 | mpz_raii() 41 | { 42 | mpz_init(&m_mpz); 43 | assert(m_mpz._mp_alloc >= 0); 44 | } 45 | mpz_raii(const mpz_raii &) = delete; 46 | mpz_raii(mpz_raii &&) = delete; 47 | mpz_raii &operator=(const mpz_raii &) = delete; 48 | mpz_raii &operator=(mpz_raii &&) = delete; 49 | ~mpz_raii() 50 | { 51 | // NOTE: even in recent GMP versions, with lazy allocation, 52 | // it seems like the pointer always points to something: 53 | // https://gmplib.org/repo/gmp/file/835f8974ff6e/mpz/init.c 54 | assert(m_mpz._mp_d != nullptr); 55 | mpz_clear(&m_mpz); 56 | } 57 | mpz_struct_t m_mpz; 58 | }; 59 | 60 | // mpq_t is an array of some struct. 61 | using mpq_struct_t = std::remove_extent<::mpq_t>::type; 62 | 63 | // Simple RAII holder for GMP rationals. 64 | struct mpq_raii { 65 | // NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init, hicpp-member-init) 66 | mpq_raii() 67 | { 68 | mpq_init(&m_mpq); 69 | } 70 | mpq_raii(const mpq_raii &) = delete; 71 | mpq_raii(mpq_raii &&) = delete; 72 | mpq_raii &operator=(const mpq_raii &) = delete; 73 | mpq_raii &operator=(mpq_raii &&) = delete; 74 | ~mpq_raii() 75 | { 76 | mpq_clear(&m_mpq); 77 | } 78 | mpq_struct_t m_mpq; 79 | }; 80 | 81 | // mpf_t is an array of some struct. 82 | using mpf_struct_t = std::remove_extent<::mpf_t>::type; 83 | 84 | // Simple RAII holder for GMP floats. 85 | struct mpf_raii { 86 | // NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init, hicpp-member-init) 87 | explicit mpf_raii(::mp_bitcnt_t prec) 88 | { 89 | ::mpf_init2(&m_mpf, prec); 90 | } 91 | mpf_raii(const mpf_raii &) = delete; 92 | mpf_raii(mpf_raii &&) = delete; 93 | mpf_raii &operator=(const mpf_raii &) = delete; 94 | mpf_raii &operator=(mpf_raii &&) = delete; 95 | ~mpf_raii() 96 | { 97 | ::mpf_clear(&m_mpf); 98 | } 99 | mpf_struct_t m_mpf; 100 | }; 101 | } // namespace detail 102 | 103 | MPPP_END_NAMESPACE 104 | 105 | #endif 106 | -------------------------------------------------------------------------------- /include/mp++/detail/mpc.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016-2023 Francesco Biscani (bluescarni@gmail.com) 2 | // 3 | // This file is part of the mp++ library. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla 6 | // Public License v. 2.0. If a copy of the MPL was not distributed 7 | // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | #ifndef MPPP_DETAIL_MPC_HPP 10 | #define MPPP_DETAIL_MPC_HPP 11 | 12 | #include 13 | 14 | #include 15 | 16 | #include 17 | 18 | MPPP_BEGIN_NAMESPACE 19 | 20 | // The MPC structure underlying mpc_t. 21 | using mpc_struct_t = std::remove_extent<::mpc_t>::type; 22 | 23 | MPPP_END_NAMESPACE 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /include/mp++/detail/mpfr.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016-2023 Francesco Biscani (bluescarni@gmail.com) 2 | // 3 | // This file is part of the mp++ library. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla 6 | // Public License v. 2.0. If a copy of the MPL was not distributed 7 | // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | #ifndef MPPP_DETAIL_MPFR_HPP 10 | #define MPPP_DETAIL_MPFR_HPP 11 | 12 | #include 13 | 14 | #include 15 | 16 | #include 17 | 18 | #if MPFR_VERSION_MAJOR < 3 19 | 20 | #error Minimum supported MPFR version is 3. 21 | 22 | #endif 23 | 24 | #if GMP_NAIL_BITS 25 | 26 | // See: 27 | // https://gmplib.org/list-archives/gmp-discuss/2012-November/005189.html 28 | 29 | #error MPFR is incompatible with GMP if nails are enabled. 30 | 31 | #endif 32 | 33 | MPPP_BEGIN_NAMESPACE 34 | 35 | // Minimum precision for a real. 36 | constexpr ::mpfr_prec_t real_prec_min() 37 | { 38 | // NOTE: Arb wants at least 2 bits, so let's 39 | // make sure we don't allow 1-bit numbers. 40 | return MPFR_PREC_MIN > 2 ? MPFR_PREC_MIN : 2; 41 | } 42 | 43 | // Maximum precision for a real. 44 | constexpr ::mpfr_prec_t real_prec_max() 45 | { 46 | // For the max precision, we remove 7 bits from the MPFR_PREC_MAX value (as the MPFR docs warn 47 | // to never set the precision "close" to the max value). 48 | return MPFR_PREC_MAX >> 7; 49 | } 50 | 51 | // The MPFR structure underlying mpfr_t. 52 | using mpfr_struct_t = std::remove_extent<::mpfr_t>::type; 53 | 54 | namespace detail 55 | { 56 | 57 | // Check if a precision value is in the allowed range. 58 | constexpr bool real_prec_check(::mpfr_prec_t p) 59 | { 60 | return p >= real_prec_min() && p <= real_prec_max(); 61 | } 62 | 63 | // Simple RAII holder for MPFR floats. 64 | struct mpfr_raii { 65 | // A constructor from a precision value, will set the value to NaN. 66 | // No check is performed on the precision. 67 | // NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init, hicpp-member-init) 68 | explicit mpfr_raii(::mpfr_prec_t prec) 69 | { 70 | ::mpfr_init2(&m_mpfr, prec); 71 | } 72 | // Disable all the other ctors/assignment ops. 73 | mpfr_raii(const mpfr_raii &) = delete; 74 | mpfr_raii(mpfr_raii &&) = delete; 75 | mpfr_raii &operator=(const mpfr_raii &) = delete; 76 | mpfr_raii &operator=(mpfr_raii &&) = delete; 77 | ~mpfr_raii() 78 | { 79 | ::mpfr_clear(&m_mpfr); 80 | } 81 | mpfr_struct_t m_mpfr; 82 | }; 83 | 84 | } // namespace detail 85 | 86 | MPPP_END_NAMESPACE 87 | 88 | #endif 89 | -------------------------------------------------------------------------------- /include/mp++/detail/parse_complex.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016-2023 Francesco Biscani (bluescarni@gmail.com) 2 | // 3 | // This file is part of the mp++ library. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla 6 | // Public License v. 2.0. If a copy of the MPL was not distributed 7 | // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | #ifndef MPPP_DETAIL_PARSE_COMPLEX_HPP 10 | #define MPPP_DETAIL_PARSE_COMPLEX_HPP 11 | 12 | #include 13 | 14 | #include 15 | 16 | MPPP_BEGIN_NAMESPACE 17 | 18 | namespace detail 19 | { 20 | 21 | std::array parse_complex(const char *); 22 | 23 | } // namespace detail 24 | 25 | MPPP_END_NAMESPACE 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /include/mp++/detail/rational_literals.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016-2023 Francesco Biscani (bluescarni@gmail.com) 2 | // 3 | // This file is part of the mp++ library. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla 6 | // Public License v. 2.0. If a copy of the MPL was not distributed 7 | // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | #ifndef MPPP_DETAIL_RATIONAL_LITERALS_HPP 10 | #define MPPP_DETAIL_RATIONAL_LITERALS_HPP 11 | 12 | #include 13 | 14 | MPPP_BEGIN_NAMESPACE 15 | 16 | inline namespace literals 17 | { 18 | 19 | template 20 | inline rational<1> operator""_q1() 21 | { 22 | return rational<1>{detail::integer_literal_impl<1, Chars...>()}; 23 | } 24 | template 25 | inline rational<2> operator""_q2() 26 | { 27 | return rational<2>{detail::integer_literal_impl<2, Chars...>()}; 28 | } 29 | 30 | template 31 | inline rational<3> operator""_q3() 32 | { 33 | return rational<3>{detail::integer_literal_impl<3, Chars...>()}; 34 | } 35 | 36 | } // namespace literals 37 | 38 | MPPP_END_NAMESPACE 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /include/mp++/detail/real128_literal.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016-2023 Francesco Biscani (bluescarni@gmail.com) 2 | // 3 | // This file is part of the mp++ library. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla 6 | // Public License v. 2.0. If a copy of the MPL was not distributed 7 | // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | #ifndef MPPP_DETAIL_REAL128_LITERAL_HPP 10 | #define MPPP_DETAIL_REAL128_LITERAL_HPP 11 | 12 | #include 13 | 14 | MPPP_BEGIN_NAMESPACE 15 | 16 | inline namespace literals 17 | { 18 | 19 | template 20 | inline real128 operator""_rq() 21 | { 22 | // Turn the sequence of input chars 23 | // into a null-terminated char array. 24 | constexpr char arr[] = {Chars..., '\0'}; 25 | 26 | // Pre-check for binary/octal literals. 27 | if (sizeof...(Chars) >= 2u && arr[0] == '0' 28 | && (arr[1] == 'b' || arr[1] == 'B' || (arr[1] >= '0' && arr[1] <= '7'))) { 29 | throw std::invalid_argument("A real128 cannot be constructed from binary or octal literals"); 30 | } 31 | 32 | return real128(arr); 33 | } 34 | 35 | } // namespace literals 36 | 37 | MPPP_END_NAMESPACE 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /include/mp++/detail/real_literals.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016-2023 Francesco Biscani (bluescarni@gmail.com) 2 | // 3 | // This file is part of the mp++ library. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla 6 | // Public License v. 2.0. If a copy of the MPL was not distributed 7 | // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | #ifndef MPPP_DETAIL_REAL_LITERALS_HPP 10 | #define MPPP_DETAIL_REAL_LITERALS_HPP 11 | 12 | #include 13 | 14 | MPPP_BEGIN_NAMESPACE 15 | 16 | namespace detail 17 | { 18 | 19 | template 20 | inline real real_literal_impl(::mpfr_prec_t prec) 21 | { 22 | // Turn the sequence of input chars 23 | // into a null-terminated char array. 24 | constexpr char arr[] = {Chars..., '\0'}; 25 | 26 | // Pre-check for binary/octal literals. 27 | if (sizeof...(Chars) >= 2u && arr[0] == '0' 28 | && (arr[1] == 'b' || arr[1] == 'B' || (arr[1] >= '0' && arr[1] <= '7'))) { 29 | throw std::invalid_argument("A real cannot be constructed from binary or octal literals"); 30 | } 31 | 32 | // Infer the base. Default is 10, if the string 33 | // contains 'x'/'X' then we assume base 16. 34 | int base = 10; 35 | for (auto c : arr) { 36 | if (c == 'x' || c == 'X') { 37 | base = 16; 38 | break; 39 | } 40 | } 41 | 42 | return real{arr, base, prec}; 43 | } 44 | 45 | } // namespace detail 46 | 47 | inline namespace literals 48 | { 49 | 50 | template 51 | inline real operator""_r128() 52 | { 53 | return detail::real_literal_impl(128); 54 | } 55 | 56 | template 57 | inline real operator""_r256() 58 | { 59 | return detail::real_literal_impl(256); 60 | } 61 | 62 | template 63 | inline real operator""_r512() 64 | { 65 | return detail::real_literal_impl(512); 66 | } 67 | 68 | template 69 | inline real operator""_r1024() 70 | { 71 | return detail::real_literal_impl(1024); 72 | } 73 | 74 | } // namespace literals 75 | 76 | MPPP_END_NAMESPACE 77 | 78 | #endif 79 | -------------------------------------------------------------------------------- /include/mp++/detail/visibility.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016-2023 Francesco Biscani (bluescarni@gmail.com) 2 | // 3 | // This file is part of the mp++ library. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla 6 | // Public License v. 2.0. If a copy of the MPL was not distributed 7 | // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | #ifndef MPPP_DETAIL_VISIBILITY_HPP 10 | #define MPPP_DETAIL_VISIBILITY_HPP 11 | 12 | #include 13 | 14 | // The visibility setup makes sense only for shared 15 | // library builds. 16 | #if defined(MPPP_STATIC_BUILD) 17 | 18 | #define MPPP_DLL_PUBLIC 19 | #define MPPP_DLL_LOCAL 20 | #define MPPP_DLL_PUBLIC_INLINE_CLASS 21 | 22 | #else 23 | 24 | // Convenience macros for setting the visibility of entities 25 | // when building/using the shared library. Mostly inspired by: 26 | // https://gcc.gnu.org/wiki/Visibility 27 | // We check first for Windows, where we assume every compiler 28 | // knows dllexport/dllimport. On other platforms, we use the GCC-like 29 | // syntax for GCC, clang and ICC. Otherwise, we leave the definitions 30 | // empty. 31 | #if defined(_WIN32) || defined(__CYGWIN__) 32 | 33 | #if defined(mppp_EXPORTS) 34 | 35 | #define MPPP_DLL_PUBLIC __declspec(dllexport) 36 | 37 | #else 38 | 39 | #define MPPP_DLL_PUBLIC __declspec(dllimport) 40 | 41 | #endif 42 | 43 | #define MPPP_DLL_LOCAL 44 | 45 | #elif defined(__clang__) || defined(__GNUC__) || defined(__INTEL_COMPILER) 46 | 47 | #define MPPP_DLL_PUBLIC __attribute__((visibility("default"))) 48 | #define MPPP_DLL_LOCAL __attribute__((visibility("hidden"))) 49 | 50 | #else 51 | 52 | #define MPPP_DLL_PUBLIC 53 | #define MPPP_DLL_LOCAL 54 | 55 | #endif 56 | 57 | // NOTE: it seems like on Windows using dllimport/dllexport on inline classes 58 | // is generally not helpful (and potentially harmful), apart from special use cases: 59 | // https://stackoverflow.com/questions/8876279/c-inline-functions-with-dllimport-dllexport 60 | // https://stackoverflow.com/questions/24511376/how-to-dllexport-a-class-derived-from-stdruntime-error 61 | // https://devblogs.microsoft.com/oldnewthing/20140109-00/?p=2123 62 | // Setting the visibility attribute on GCC-like compilers for inline classes, however, seems to be ok. 63 | // Thus, we use a specialised definition for marking "public"ly visible inline classes. 64 | #if defined(_WIN32) || defined(__CYGWIN__) 65 | 66 | #define MPPP_DLL_PUBLIC_INLINE_CLASS 67 | 68 | #else 69 | 70 | #define MPPP_DLL_PUBLIC_INLINE_CLASS MPPP_DLL_PUBLIC 71 | 72 | #endif 73 | 74 | #endif 75 | 76 | #endif 77 | -------------------------------------------------------------------------------- /include/mp++/exceptions.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016-2023 Francesco Biscani (bluescarni@gmail.com) 2 | // 3 | // This file is part of the mp++ library. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla 6 | // Public License v. 2.0. If a copy of the MPL was not distributed 7 | // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | #ifndef MPPP_EXCEPTIONS_HPP 10 | #define MPPP_EXCEPTIONS_HPP 11 | 12 | #include 13 | 14 | #include 15 | #include 16 | 17 | MPPP_BEGIN_NAMESPACE 18 | 19 | // Exception to signal division by zero. 20 | class MPPP_DLL_PUBLIC_INLINE_CLASS zero_division_error final : public std::domain_error 21 | { 22 | public: 23 | using std::domain_error::domain_error; 24 | }; 25 | 26 | MPPP_END_NAMESPACE 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /include/mp++/fwd.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016-2023 Francesco Biscani (bluescarni@gmail.com) 2 | // 3 | // This file is part of the mp++ library. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla 6 | // Public License v. 2.0. If a copy of the MPL was not distributed 7 | // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | #ifndef MPPP_FWD_HPP 10 | #define MPPP_FWD_HPP 11 | 12 | #include 13 | 14 | #include 15 | 16 | MPPP_BEGIN_NAMESPACE 17 | 18 | template 19 | class integer; 20 | 21 | template 22 | class rational; 23 | 24 | #if defined(MPPP_WITH_MPFR) 25 | 26 | class real; 27 | 28 | #endif 29 | 30 | #if defined(MPPP_WITH_MPC) 31 | 32 | class complex; 33 | 34 | #endif 35 | 36 | #if defined(MPPP_WITH_QUADMATH) 37 | 38 | class real128; 39 | class complex128; 40 | 41 | #endif 42 | 43 | MPPP_END_NAMESPACE 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /include/mp++/mp++.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016-2023 Francesco Biscani (bluescarni@gmail.com) 2 | // 3 | // This file is part of the mp++ library. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla 6 | // Public License v. 2.0. If a copy of the MPL was not distributed 7 | // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | #ifndef MPPP_MPPP_HPP 10 | #define MPPP_MPPP_HPP 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #if defined(MPPP_WITH_MPFR) 19 | #include 20 | #endif 21 | 22 | #if defined(MPPP_WITH_MPC) 23 | #include 24 | #endif 25 | 26 | #if defined(MPPP_WITH_QUADMATH) 27 | #include 28 | #include 29 | #endif 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /include/mp++/type_name.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016-2023 Francesco Biscani (bluescarni@gmail.com) 2 | // 3 | // This file is part of the mp++ library. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla 6 | // Public License v. 2.0. If a copy of the MPL was not distributed 7 | // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | #ifndef MPPP_TYPE_NAME_HPP 10 | #define MPPP_TYPE_NAME_HPP 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | #include 18 | 19 | MPPP_BEGIN_NAMESPACE 20 | 21 | namespace detail 22 | { 23 | 24 | MPPP_DLL_PUBLIC std::string demangle_from_typeid(const char *); 25 | 26 | template 27 | inline std::string demangle_impl() 28 | { 29 | return demangle_from_typeid(typeid(T).name()); 30 | } 31 | 32 | #if defined(MPPP_HAVE_GCC_INT128) && defined(__APPLE__) 33 | 34 | // NOTE: on OSX, it seems like typeid() for 128bit types is not implemented. 35 | // Thus, we sidestep typeid() and provide directly the demangled 36 | // names of the bugged types. These are the same names returned on linux. 37 | 38 | template <> 39 | inline std::string demangle_impl<__int128_t>() 40 | { 41 | return "__int128"; 42 | } 43 | 44 | template <> 45 | inline std::string demangle_impl<__int128_t *>() 46 | { 47 | return "__int128*"; 48 | } 49 | 50 | template <> 51 | inline std::string demangle_impl<__int128_t const *>() 52 | { 53 | return "__int128 const*"; 54 | } 55 | 56 | template <> 57 | inline std::string demangle_impl<__uint128_t>() 58 | { 59 | return "__uint128"; 60 | } 61 | 62 | template <> 63 | inline std::string demangle_impl<__uint128_t *>() 64 | { 65 | return "__uint128*"; 66 | } 67 | 68 | template <> 69 | inline std::string demangle_impl<__uint128_t const *>() 70 | { 71 | return "__uint128 const*"; 72 | } 73 | 74 | #endif 75 | 76 | } // namespace detail 77 | 78 | // Determine the name of the type T at runtime. 79 | template 80 | inline std::string type_name() 81 | { 82 | // Get the demangled name without cvref. 83 | auto ret = detail::demangle_impl::type>::type>(); 84 | 85 | // Redecorate it with cv qualifiers. 86 | constexpr unsigned flag = unsigned(std::is_const::type>::value) 87 | + (unsigned(std::is_volatile::type>::value) << 1); 88 | // NOLINTNEXTLINE(hicpp-multiway-paths-covered) 89 | switch (flag) { 90 | case 0u: 91 | // NOTE: handle this explicitly to keep compiler warnings at bay. 92 | break; 93 | case 1u: 94 | ret += " const"; 95 | break; 96 | case 2u: 97 | ret += " volatile"; 98 | break; 99 | case 3u: 100 | ret += " const volatile"; 101 | } 102 | 103 | // Re-add the reference, if necessary. 104 | if (std::is_lvalue_reference::value) { 105 | ret += " &"; 106 | } else if (std::is_rvalue_reference::value) { 107 | ret += " &&"; 108 | } 109 | 110 | return ret; 111 | } 112 | 113 | MPPP_END_NAMESPACE 114 | 115 | #endif 116 | -------------------------------------------------------------------------------- /mp++-config.cmake.in: -------------------------------------------------------------------------------- 1 | # Get current dir. 2 | get_filename_component(_MPPP_CONFIG_SELF_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) 3 | 4 | # Find the deps. Alter the cmake module path. 5 | set(_MPPP_CONFIG_OLD_MODULE_PATH "${CMAKE_MODULE_PATH}") 6 | list(APPEND CMAKE_MODULE_PATH "${_MPPP_CONFIG_SELF_DIR}") 7 | 8 | # Mandatory dep on GMP. 9 | find_package(mp++_GMP REQUIRED) 10 | 11 | # Public optional deps. 12 | if(@MPPP_WITH_MPFR@) 13 | find_package(mp++_MPFR REQUIRED) 14 | endif() 15 | set(mp++_WITH_MPFR @MPPP_WITH_MPFR@) 16 | 17 | if(@MPPP_WITH_MPC@) 18 | find_package(mp++_MPC REQUIRED) 19 | endif() 20 | set(mp++_WITH_MPC @MPPP_WITH_MPC@) 21 | 22 | if(@MPPP_WITH_BOOST_S11N@) 23 | # NOTE: we look for Boost in CONFIG mode first, as that has become the official supported way 24 | # of locating Boost in recent Boost/CMake versions. If we fail, we try again in 25 | # MODULE mode as last resort. 26 | find_package(Boost @_MPPP_MIN_BOOST_VERSION@ QUIET COMPONENTS serialization CONFIG) 27 | if(NOT ${Boost_FOUND}) 28 | find_package(Boost @_MPPP_MIN_BOOST_VERSION@ QUIET MODULE COMPONENTS serialization) 29 | endif() 30 | if(NOT ${Boost_FOUND}) 31 | message(FATAL_ERROR "Could not locate Boost in either CONFIG or MODULE mode.") 32 | endif() 33 | endif() 34 | set(mp++_WITH_BOOST_S11N @MPPP_WITH_BOOST_S11N@) 35 | 36 | if(@MPPP_WITH_FMT@) 37 | find_package(fmt @_MPPP_MIN_FMT_VERSION@ REQUIRED CONFIG) 38 | endif() 39 | set(mp++_WITH_FMT @MPPP_WITH_FMT@) 40 | 41 | # Private optional deps. 42 | set(mp++_WITH_FLINT @MPPP_WITH_FLINT@) 43 | set(mp++_WITH_QUADMATH @MPPP_WITH_QUADMATH@) 44 | 45 | # Export the ABI version. 46 | set(mp++_ABI_VERSION @MPPP_ABI_VERSION@) 47 | 48 | # Restore original module path. 49 | set(CMAKE_MODULE_PATH "${_MPPP_CONFIG_OLD_MODULE_PATH}") 50 | unset(_MPPP_CONFIG_OLD_MODULE_PATH) 51 | 52 | include(${_MPPP_CONFIG_SELF_DIR}/mp++_export.cmake) 53 | 54 | # Clean up. 55 | unset(_MPPP_CONFIG_SELF_DIR) 56 | -------------------------------------------------------------------------------- /src/detail/utils.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016-2023 Francesco Biscani (bluescarni@gmail.com) 2 | // 3 | // This file is part of the mp++ library. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla 6 | // Public License v. 2.0. If a copy of the MPL was not distributed 7 | // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | #include 10 | 11 | #if MPPP_CPLUSPLUS < 201402L 12 | #include 13 | #endif 14 | #include 15 | #include 16 | #if MPPP_CPLUSPLUS >= 201402L 17 | #include 18 | #endif 19 | #include 20 | 21 | #include 22 | 23 | // NOLINTNEXTLINE(modernize-concat-nested-namespaces) 24 | MPPP_BEGIN_NAMESPACE 25 | 26 | namespace detail 27 | { 28 | 29 | #if defined(MPPP_HAVE_GCC_INT128) 30 | 31 | namespace 32 | { 33 | 34 | // Implementation of to_string() for 128bit integers. 35 | template 36 | char *to_string_impl(char (&output)[N], __uint128_t n) 37 | { 38 | // Max 128 uint value needs 39 digits in base 10, plus the terminator. 39 | static_assert(N >= 40u, 40 | "An array of at least 40 characters is needed to convert a 128 bit unsigned integer to string."); 41 | // Sequence of text representations of integers from 0 to 99 (2 digits per number). 42 | constexpr char d2_text[] = "000102030405060708091011121314151617181920212223242526272829303132333435363738394041424" 43 | "344454647484950515253545556575859606162636465666768697071727374757677787980818283848586" 44 | "87888990919293949596979899"; 45 | static_assert(sizeof(d2_text) == 201u, "Invalid size."); 46 | // Place the terminator. 47 | std::size_t idx = 0; 48 | output[idx++] = '\0'; 49 | // Reduce n iteratively by a factor of 100, and print the remainder at each iteration. 50 | auto r = static_cast(n % 100u); 51 | for (; n >= 100u; n = n / 100u, r = static_cast(n % 100u)) { 52 | output[idx++] = d2_text[r * 2u + 1u]; 53 | output[idx++] = d2_text[r * 2u]; 54 | } 55 | // Write the last two digits, skipping the second one if the current 56 | // remainder is not at least 10. 57 | output[idx++] = d2_text[r * 2u + 1u]; 58 | if (r >= 10u) { 59 | output[idx++] = d2_text[r * 2u]; 60 | } 61 | assert(idx <= 40u); 62 | return output + idx; 63 | } 64 | 65 | } // namespace 66 | 67 | std::string to_string(__uint128_t n) 68 | { 69 | char output[40]; 70 | // NOLINTNEXTLINE(llvm-qualified-auto, readability-qualified-auto) 71 | auto o = to_string_impl(output, n); 72 | #if MPPP_CPLUSPLUS >= 201402L 73 | // Now build the string by reading backwards. When reverse iterators are created, 74 | // the original iterator is decreased by one. Hence, we can build the begin directly 75 | // from o (which points 1 past the last written char), and the end from output + 1 76 | // (so that it will point to the terminator). 77 | return std::string(std::make_reverse_iterator(o), std::make_reverse_iterator(output + 1)); 78 | #else 79 | // In C++11, we reverse output and then create the string. 80 | std::reverse(output, o); 81 | return std::string(output); 82 | #endif 83 | } 84 | 85 | std::string to_string(__int128_t n) 86 | { 87 | char output[41]; 88 | const bool neg = n < 0; 89 | // NOLINTNEXTLINE(llvm-qualified-auto, readability-qualified-auto) 90 | auto o = to_string_impl(output, neg ? nint_abs(n) : static_cast<__uint128_t>(n)); 91 | // Add the sign, if needed. 92 | if (neg) { 93 | *(o++) = '-'; 94 | } 95 | #if MPPP_CPLUSPLUS >= 201402L 96 | return std::string(std::make_reverse_iterator(o), std::make_reverse_iterator(output + 1)); 97 | #else 98 | std::reverse(output, o); 99 | return std::string(output); 100 | #endif 101 | } 102 | 103 | #endif 104 | 105 | } // namespace detail 106 | 107 | MPPP_END_NAMESPACE 108 | -------------------------------------------------------------------------------- /src/type_name.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016-2023 Francesco Biscani (bluescarni@gmail.com) 2 | // 3 | // This file is part of the mp++ library. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla 6 | // Public License v. 2.0. If a copy of the MPL was not distributed 7 | // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | #include 10 | 11 | #if defined(__GNUC__) || (defined(__clang__) && !defined(_MSC_VER)) 12 | 13 | // GCC demangle. This is available also for clang, both with libstdc++ and libc++. 14 | #include 15 | #include 16 | #include 17 | 18 | #endif 19 | 20 | #include 21 | 22 | // NOLINTNEXTLINE(modernize-concat-nested-namespaces) 23 | MPPP_BEGIN_NAMESPACE 24 | namespace detail 25 | { 26 | 27 | std::string demangle_from_typeid(const char *s) 28 | { 29 | #if defined(__GNUC__) || (defined(__clang__) && !defined(_MSC_VER)) 30 | // NOTE: wrap std::free() in a local lambda, so we avoid 31 | // potential ambiguities when taking the address of std::free(). 32 | // See: 33 | // https://stackoverflow.com/questions/27440953/stdunique-ptr-for-c-functions-that-need-free 34 | // NOLINTNEXTLINE(cppcoreguidelines-no-malloc, cppcoreguidelines-owning-memory, hicpp-no-malloc) 35 | auto deleter = [](void *ptr) { std::free(ptr); }; 36 | 37 | // NOTE: abi::__cxa_demangle will return a pointer allocated by std::malloc, which we will delete via std::free(). 38 | std::unique_ptr res{::abi::__cxa_demangle(s, nullptr, nullptr, nullptr), deleter}; 39 | 40 | // NOTE: return the original string if demangling fails. 41 | return res ? std::string(res.get()) : std::string(s); 42 | #else 43 | // If no demangling is available, just return the mangled name. 44 | // NOTE: MSVC already returns the demangled name from typeid. 45 | return std::string(s); 46 | #endif 47 | } 48 | 49 | } // namespace detail 50 | 51 | MPPP_END_NAMESPACE 52 | -------------------------------------------------------------------------------- /test/catch_main.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016-2023 Francesco Biscani (bluescarni@gmail.com) 2 | // 3 | // This file is part of the mp++ library. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla 6 | // Public License v. 2.0. If a copy of the MPL was not distributed 7 | // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | // Minimal main file to reduce catch compile times: 10 | // https://github.com/catchorg/Catch2/blob/master/docs/slow-compiles.md 11 | 12 | #define CATCH_CONFIG_MAIN 13 | 14 | // NOTE: the unicode MSVC builds lead to catch 15 | // defining a wmain() function rather than the usual 16 | // main, and this leads to undefined references 17 | // in the appveyor builds. Luckily, there is 18 | // this definition one can set to use the good 19 | // ole main() instead. 20 | #define DO_NOT_USE_WMAIN 21 | 22 | #include "catch.hpp" 23 | -------------------------------------------------------------------------------- /test/complex128_arith.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016-2023 Francesco Biscani (bluescarni@gmail.com) 2 | // 3 | // This file is part of the mp++ library. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla 6 | // Public License v. 2.0. If a copy of the MPL was not distributed 7 | // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #include "catch.hpp" 16 | 17 | // NOLINTNEXTLINE(google-build-using-namespace) 18 | using namespace mppp; 19 | 20 | #if MPPP_CPLUSPLUS >= 201402L 21 | 22 | constexpr auto test_constexpr_conj(complex128 c) 23 | { 24 | return c.conj(); 25 | } 26 | 27 | #endif 28 | 29 | TEST_CASE("abs") 30 | { 31 | complex128 c{3, 4}; 32 | REQUIRE(std::is_same::value); 33 | REQUIRE(c.abs().m_value == 5); 34 | REQUIRE(std::is_same::value); 35 | REQUIRE(abs(complex128{3, 4}) == 5); 36 | } 37 | 38 | TEST_CASE("arg") 39 | { 40 | complex128 c{1, 0}; 41 | REQUIRE(std::is_same::value); 42 | REQUIRE(c.arg().m_value == 0); 43 | REQUIRE(std::is_same::value); 44 | REQUIRE(arg(complex128{1, 0}).m_value == 0); 45 | } 46 | 47 | TEST_CASE("conj") 48 | { 49 | constexpr auto cnj1 = conj(complex128{1, 3}); 50 | REQUIRE(std::is_same::value); 51 | REQUIRE(cnj1.m_value == cplex128{1, -3}); 52 | REQUIRE(std::is_same::value); 53 | 54 | complex128 c{3, -3}; 55 | c.conj(); 56 | REQUIRE(c == complex128{3, 3}); 57 | REQUIRE(std::is_same::value); 58 | 59 | // NOTE: it looks like on ICC there might 60 | // be a codegen issue that discards the sign 61 | // of a negative zero in certain circumstances. 62 | #if !defined(__INTEL_COMPILER) 63 | c = complex128{1, 0}; 64 | REQUIRE(!c.imag().signbit()); 65 | c.conj(); 66 | REQUIRE(c.imag().signbit()); 67 | #endif 68 | 69 | #if MPPP_CPLUSPLUS >= 201402L && !defined(__INTEL_COMPILER) 70 | constexpr auto cnj2 = test_constexpr_conj(complex128{0, 3}); 71 | REQUIRE(cnj2 == complex128{0, -3}); 72 | #endif 73 | } 74 | 75 | TEST_CASE("proj") 76 | { 77 | complex128 c{42, -43}; 78 | REQUIRE(std::is_same::value); 79 | REQUIRE(c.proj().m_value == cplex128{42, -43}); 80 | REQUIRE(std::is_same::value); 81 | REQUIRE(proj(complex128{1, 2}).m_value == cplex128{1, 2}); 82 | 83 | REQUIRE(proj(complex128{real128_inf(), 123}).m_value == cplex128{real128_inf().m_value, 0}); 84 | REQUIRE(!proj(complex128{real128_inf(), 123}).imag().signbit()); 85 | REQUIRE(proj(complex128{real128_inf(), -123}).m_value == cplex128{real128_inf().m_value, 0}); 86 | REQUIRE(proj(complex128{real128_inf(), -123}).imag().signbit()); 87 | } 88 | -------------------------------------------------------------------------------- /test/complex128_hyper.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016-2023 Francesco Biscani (bluescarni@gmail.com) 2 | // 3 | // This file is part of the mp++ library. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla 6 | // Public License v. 2.0. If a copy of the MPL was not distributed 7 | // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | #include 10 | 11 | #include 12 | 13 | #include "catch.hpp" 14 | 15 | // NOLINTNEXTLINE(google-build-using-namespace) 16 | using namespace mppp; 17 | 18 | TEST_CASE("sinh") 19 | { 20 | const complex128 cmp{"(-6.54812004091100164776681101883532441,-7.61923172032141020848713573680431168)"}; 21 | 22 | complex128 c{3, 4}; 23 | REQUIRE(std::is_same::value); 24 | c.sinh(); 25 | REQUIRE(abs(complex128{c.m_value - cmp.m_value}) < 1E-32); 26 | REQUIRE(std::is_same::value); 27 | REQUIRE(abs(complex128{sinh(complex128{3, 4}).m_value - cmp.m_value}) < 1E-32); 28 | } 29 | 30 | TEST_CASE("cosh") 31 | { 32 | const complex128 cmp{"(-6.58066304055115643256074412653880334,-7.5815527427465443537163452865384257)"}; 33 | 34 | complex128 c{3, 4}; 35 | REQUIRE(std::is_same::value); 36 | c.cosh(); 37 | REQUIRE(abs(complex128{c.m_value - cmp.m_value}) < 1E-32); 38 | REQUIRE(std::is_same::value); 39 | REQUIRE(abs(complex128{cosh(complex128{3, 4}).m_value - cmp.m_value}) < 1E-32); 40 | } 41 | 42 | TEST_CASE("tanh") 43 | { 44 | const complex128 cmp{"(1.00070953606723293932958547240417269,0.00490825806749606025907878692993276652)"}; 45 | 46 | complex128 c{3, 4}; 47 | REQUIRE(std::is_same::value); 48 | c.tanh(); 49 | REQUIRE(abs(complex128{c.m_value - cmp.m_value}) < 1E-32); 50 | REQUIRE(std::is_same::value); 51 | REQUIRE(abs(complex128{tanh(complex128{3, 4}).m_value - cmp.m_value}) < 1E-32); 52 | } 53 | 54 | TEST_CASE("asinh") 55 | { 56 | const complex128 cmp{"(2.29991404087926964995578963066317545,0.91761685335147865575986274867017455)"}; 57 | 58 | complex128 c{3, 4}; 59 | REQUIRE(std::is_same::value); 60 | c.asinh(); 61 | REQUIRE(abs(complex128{c.m_value - cmp.m_value}) < 1E-32); 62 | REQUIRE(std::is_same::value); 63 | REQUIRE(abs(complex128{asinh(complex128{3, 4}).m_value - cmp.m_value}) < 1E-32); 64 | } 65 | 66 | TEST_CASE("acosh") 67 | { 68 | const complex128 cmp{"(2.30550903124347694204183593813343083,0.936812461155719902912524576575608903)"}; 69 | 70 | complex128 c{3, 4}; 71 | REQUIRE(std::is_same::value); 72 | c.acosh(); 73 | REQUIRE(abs(complex128{c.m_value - cmp.m_value}) < 1E-32); 74 | REQUIRE(std::is_same::value); 75 | REQUIRE(abs(complex128{acosh(complex128{3, 4}).m_value - cmp.m_value}) < 1E-32); 76 | } 77 | 78 | TEST_CASE("atanh") 79 | { 80 | const complex128 cmp{"(0.117500907311433888412734257787085516,1.40992104959657552253061938446042078)"}; 81 | 82 | complex128 c{3, 4}; 83 | REQUIRE(std::is_same::value); 84 | c.atanh(); 85 | REQUIRE(abs(complex128{c.m_value - cmp.m_value}) < 1E-32); 86 | REQUIRE(std::is_same::value); 87 | REQUIRE(abs(complex128{atanh(complex128{3, 4}).m_value - cmp.m_value}) < 1E-32); 88 | } 89 | -------------------------------------------------------------------------------- /test/complex128_literal.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016-2023 Francesco Biscani (bluescarni@gmail.com) 2 | // 3 | // This file is part of the mp++ library. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla 6 | // Public License v. 2.0. If a copy of the MPL was not distributed 7 | // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | #include 10 | 11 | #include "catch.hpp" 12 | 13 | // NOLINTNEXTLINE(google-build-using-namespace) 14 | using namespace mppp; 15 | 16 | TEST_CASE("literal") 17 | { 18 | REQUIRE(1.1_icq == complex128{0, real128{"1.1"}}); 19 | REQUIRE(1.1_rq + 1.1_icq == complex128{real128{"1.1"}, real128{"1.1"}}); 20 | } 21 | -------------------------------------------------------------------------------- /test/complex128_logexp.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016-2023 Francesco Biscani (bluescarni@gmail.com) 2 | // 3 | // This file is part of the mp++ library. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla 6 | // Public License v. 2.0. If a copy of the MPL was not distributed 7 | // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | #include 10 | 11 | #include 12 | 13 | #include "catch.hpp" 14 | 15 | // NOLINTNEXTLINE(google-build-using-namespace) 16 | using namespace mppp; 17 | 18 | TEST_CASE("exp") 19 | { 20 | const complex128 cmp{"(-13.1287830814621580803275551453741285,-15.2007844630679545622034810233427382)"}; 21 | 22 | complex128 c{3, 4}; 23 | REQUIRE(std::is_same::value); 24 | c.exp(); 25 | REQUIRE(abs(complex128{c.m_value - cmp.m_value}) < 1E-32); 26 | REQUIRE(std::is_same::value); 27 | REQUIRE(abs(complex128{exp(complex128{3, 4}).m_value - cmp.m_value}) < 1E-32); 28 | } 29 | 30 | TEST_CASE("log") 31 | { 32 | const complex128 cmp{"(1.6094379124341003746007593332261876,0.927295218001612232428512462922428794)"}; 33 | 34 | complex128 c{3, 4}; 35 | REQUIRE(std::is_same::value); 36 | c.log(); 37 | REQUIRE(abs(complex128{c.m_value - cmp.m_value}) < 1E-32); 38 | REQUIRE(std::is_same::value); 39 | REQUIRE(abs(complex128{log(complex128{3, 4}).m_value - cmp.m_value}) < 1E-32); 40 | } 41 | 42 | TEST_CASE("log10") 43 | { 44 | const complex128 cmp{"(0.698970004336018804786261105275506932,0.402719196273373142077900460387457914)"}; 45 | 46 | complex128 c{3, 4}; 47 | REQUIRE(std::is_same::value); 48 | c.log10(); 49 | REQUIRE(abs(complex128{c.m_value - cmp.m_value}) < 1E-32); 50 | REQUIRE(std::is_same::value); 51 | REQUIRE(abs(complex128{log10(complex128{3, 4}).m_value - cmp.m_value}) < 1E-32); 52 | } 53 | -------------------------------------------------------------------------------- /test/complex128_roots.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016-2023 Francesco Biscani (bluescarni@gmail.com) 2 | // 3 | // This file is part of the mp++ library. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla 6 | // Public License v. 2.0. If a copy of the MPL was not distributed 7 | // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | #include 10 | 11 | #include 12 | 13 | #include "catch.hpp" 14 | 15 | // NOLINTNEXTLINE(google-build-using-namespace) 16 | using namespace mppp; 17 | 18 | TEST_CASE("sqrt") 19 | { 20 | const complex128 cmp{"(2,1)"}; 21 | 22 | complex128 c{3, 4}; 23 | REQUIRE(std::is_same::value); 24 | c.sqrt(); 25 | REQUIRE(abs(complex128{c.m_value - cmp.m_value}) < 1E-32); 26 | REQUIRE(std::is_same::value); 27 | REQUIRE(abs(complex128{sqrt(complex128{3, 4}).m_value - cmp.m_value}) < 1E-32); 28 | } 29 | -------------------------------------------------------------------------------- /test/complex128_trig.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016-2023 Francesco Biscani (bluescarni@gmail.com) 2 | // 3 | // This file is part of the mp++ library. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla 6 | // Public License v. 2.0. If a copy of the MPL was not distributed 7 | // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | #include 10 | 11 | #include 12 | 13 | #include "catch.hpp" 14 | 15 | // NOLINTNEXTLINE(google-build-using-namespace) 16 | using namespace mppp; 17 | 18 | TEST_CASE("sin") 19 | { 20 | const complex128 cmp{"(3.85373803791937732161752894046373053,-27.0168132580039344880975437549921532)"}; 21 | 22 | complex128 c{3, 4}; 23 | REQUIRE(std::is_same::value); 24 | c.sin(); 25 | REQUIRE(abs(complex128{c.m_value - cmp.m_value}) < 1E-32); 26 | REQUIRE(std::is_same::value); 27 | REQUIRE(abs(complex128{sin(complex128{3, 4}).m_value - cmp.m_value}) < 1E-32); 28 | } 29 | 30 | TEST_CASE("cos") 31 | { 32 | const complex128 cmp{"(-27.0349456030742246476948026682709123,-3.85115333481177753656333712305312452)"}; 33 | 34 | complex128 c{3, 4}; 35 | REQUIRE(std::is_same::value); 36 | c.cos(); 37 | REQUIRE(abs(complex128{c.m_value - cmp.m_value}) < 1E-32); 38 | REQUIRE(std::is_same::value); 39 | REQUIRE(abs(complex128{cos(complex128{3, 4}).m_value - cmp.m_value}) < 1E-32); 40 | } 41 | 42 | TEST_CASE("tan") 43 | { 44 | const complex128 cmp{"(-0.000187346204629478426224255637728218093,0.999355987381473141391649630320133042)"}; 45 | 46 | complex128 c{3, 4}; 47 | REQUIRE(std::is_same::value); 48 | c.tan(); 49 | REQUIRE(abs(complex128{c.m_value - cmp.m_value}) < 1E-32); 50 | REQUIRE(std::is_same::value); 51 | REQUIRE(abs(complex128{tan(complex128{3, 4}).m_value - cmp.m_value}) < 1E-32); 52 | } 53 | 54 | TEST_CASE("asin") 55 | { 56 | const complex128 cmp{"(0.633983865639176716318797115064142495,2.30550903124347694204183593813343083)"}; 57 | 58 | complex128 c{3, 4}; 59 | REQUIRE(std::is_same::value); 60 | c.asin(); 61 | REQUIRE(abs(complex128{c.m_value - cmp.m_value}) < 1E-32); 62 | REQUIRE(std::is_same::value); 63 | REQUIRE(abs(complex128{asin(complex128{3, 4}).m_value - cmp.m_value}) < 1E-32); 64 | } 65 | 66 | TEST_CASE("acos") 67 | { 68 | const complex128 cmp{"(0.936812461155719902912524576575608903,-2.30550903124347694204183593813343083)"}; 69 | 70 | complex128 c{3, 4}; 71 | REQUIRE(std::is_same::value); 72 | c.acos(); 73 | REQUIRE(abs(complex128{c.m_value - cmp.m_value}) < 1E-32); 74 | REQUIRE(std::is_same::value); 75 | REQUIRE(abs(complex128{acos(complex128{3, 4}).m_value - cmp.m_value}) < 1E-32); 76 | } 77 | 78 | TEST_CASE("atan") 79 | { 80 | const complex128 cmp{"(1.44830699523146454214528045103411354,0.158997191679999174364761036007018789)"}; 81 | 82 | complex128 c{3, 4}; 83 | REQUIRE(std::is_same::value); 84 | c.atan(); 85 | REQUIRE(abs(complex128{c.m_value - cmp.m_value}) < 1E-32); 86 | REQUIRE(std::is_same::value); 87 | REQUIRE(abs(complex128{atan(complex128{3, 4}).m_value - cmp.m_value}) < 1E-32); 88 | } 89 | -------------------------------------------------------------------------------- /test/complex_literals.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016-2023 Francesco Biscani (bluescarni@gmail.com) 2 | // 3 | // This file is part of the mp++ library. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla 6 | // Public License v. 2.0. If a copy of the MPL was not distributed 7 | // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | #include 10 | #include 11 | 12 | #include "catch.hpp" 13 | 14 | // NOLINTNEXTLINE(google-build-using-namespace) 15 | using namespace mppp; 16 | 17 | TEST_CASE("literals test") 18 | { 19 | REQUIRE(0_icr128 == complex{0, 0, complex_prec_t(128)}); 20 | REQUIRE(123_icr128 == complex{0, 123, complex_prec_t(128)}); 21 | REQUIRE((123_icr128).get_prec() == 128); 22 | REQUIRE(-123_icr128 == complex{0, -123, complex_prec_t(128)}); 23 | REQUIRE((-123_icr128).get_prec() == 128); 24 | 25 | #if MPPP_CPLUSPLUS >= 201703L 26 | // Hex literals are supported as well. 27 | REQUIRE(0x123.p-7_icr128 == complex{"(0,0x123.p-7)", 16, complex_prec_t(128)}); 28 | REQUIRE(-0X123.p-7_icr128 == -complex{"(0,0x123.p-7)", 16, complex_prec_t(128)}); 29 | #endif 30 | 31 | REQUIRE(0_icr256 == complex{0, 0, complex_prec_t(128)}); 32 | REQUIRE(123_icr256 == complex{0, 123, complex_prec_t(256)}); 33 | REQUIRE((123_icr256).get_prec() == 256); 34 | REQUIRE(-123_icr256 == complex{0, -123, complex_prec_t(256)}); 35 | REQUIRE((-123_icr256).get_prec() == 256); 36 | 37 | #if MPPP_CPLUSPLUS >= 201703L 38 | // Hex literals are supported as well. 39 | REQUIRE(0x123.p-7_icr256 == complex{"(0,0x123.p-7)", 16, complex_prec_t(256)}); 40 | REQUIRE(-0X123.p-7_icr256 == -complex{"(0,0x123.p-7)", 16, complex_prec_t(256)}); 41 | #endif 42 | 43 | REQUIRE(0_icr512 == complex{0, 0, complex_prec_t(128)}); 44 | REQUIRE(123_icr512 == complex{0, 123, complex_prec_t(512)}); 45 | REQUIRE((123_icr512).get_prec() == 512); 46 | REQUIRE(-123_icr512 == complex{0, -123, complex_prec_t(512)}); 47 | REQUIRE((-123_icr512).get_prec() == 512); 48 | 49 | #if MPPP_CPLUSPLUS >= 201703L 50 | // Hex literals are supported as well. 51 | REQUIRE(0x123.p-7_icr512 == complex{"(0,0x123.p-7)", 16, complex_prec_t(512)}); 52 | REQUIRE(-0X123.p-7_icr512 == -complex{"(0,0x123.p-7)", 16, complex_prec_t(512)}); 53 | #endif 54 | 55 | REQUIRE(0_icr1024 == complex{0, 0, complex_prec_t(128)}); 56 | REQUIRE(123_icr1024 == complex{0, 123, complex_prec_t(1024)}); 57 | REQUIRE((123_icr1024).get_prec() == 1024); 58 | REQUIRE(-123_icr1024 == complex{0, -123, complex_prec_t(1024)}); 59 | REQUIRE((-123_icr1024).get_prec() == 1024); 60 | 61 | #if MPPP_CPLUSPLUS >= 201703L 62 | // Hex literals are supported as well. 63 | REQUIRE(0x123.p-7_icr1024 == complex{"(0,0x123.p-7)", 16, complex_prec_t(1024)}); 64 | REQUIRE(-0X123.p-7_icr1024 == -complex{"(0,0x123.p-7)", 16, complex_prec_t(1024)}); 65 | #endif 66 | } 67 | -------------------------------------------------------------------------------- /test/complex_rootofunity.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016-2023 Francesco Biscani (bluescarni@gmail.com) 2 | // 3 | // This file is part of the mp++ library. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla 6 | // Public License v. 2.0. If a copy of the MPL was not distributed 7 | // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | #include 10 | 11 | #include 12 | 13 | #include "catch.hpp" 14 | 15 | // NOLINTNEXTLINE(google-build-using-namespace) 16 | using namespace mppp; 17 | 18 | TEST_CASE("rootofunity") 19 | { 20 | complex c{1, 2, complex_prec_t(128)}; 21 | REQUIRE(std::is_same::value); 22 | REQUIRE(&set_rootofunity(c, 10, 8) == &c); 23 | REQUIRE(abs(mppp::pow(c, 10) - 1) < mppp::pow(2_r128, -126)); 24 | } 25 | -------------------------------------------------------------------------------- /test/global_header.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016-2023 Francesco Biscani (bluescarni@gmail.com) 2 | // 3 | // This file is part of the mp++ library. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla 6 | // Public License v. 2.0. If a copy of the MPL was not distributed 7 | // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | #include 10 | 11 | #include "catch.hpp" 12 | 13 | // NOLINTNEXTLINE(google-build-using-namespace) 14 | using namespace mppp; 15 | 16 | TEST_CASE("global_test") 17 | { 18 | auto n = 123_z1; 19 | REQUIRE(n == 123); 20 | 21 | auto q = 123_q1; 22 | REQUIRE(q == 123); 23 | 24 | #if defined(MPPP_WITH_QUADMATH) 25 | auto rq = 123_rq; 26 | REQUIRE(rq == 123); 27 | 28 | auto cq = 123_rq + 321_icq; 29 | REQUIRE(cq == complex128{123, 321}); 30 | #endif 31 | 32 | #if defined(MPPP_WITH_MPFR) 33 | auto r = 123_r256; 34 | REQUIRE(r == 123); 35 | #endif 36 | 37 | #if defined(MPPP_WITH_MPC) 38 | auto c = complex{123}; 39 | REQUIRE(c == 123); 40 | #endif 41 | } 42 | -------------------------------------------------------------------------------- /test/integer_abs.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016-2023 Francesco Biscani (bluescarni@gmail.com) 2 | // 3 | // This file is part of the mp++ library. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla 6 | // Public License v. 2.0. If a copy of the MPL was not distributed 7 | // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | 17 | #include "catch.hpp" 18 | #include "test_utils.hpp" 19 | 20 | static const int ntries = 1000; 21 | 22 | // NOLINTNEXTLINE(google-build-using-namespace) 23 | using namespace mppp; 24 | // NOLINTNEXTLINE(google-build-using-namespace) 25 | using namespace mppp_test; 26 | 27 | using sizes = std::tuple, std::integral_constant, 28 | std::integral_constant, std::integral_constant, 29 | std::integral_constant>; 30 | 31 | // NOLINTNEXTLINE(cert-err58-cpp, cert-msc32-c, cert-msc51-cpp, cppcoreguidelines-avoid-non-const-global-variables) 32 | static std::mt19937 rng; 33 | 34 | struct abs_tester { 35 | template 36 | inline void operator()(const S &) const 37 | { 38 | using integer = integer; 39 | // Start with all zeroes. 40 | detail::mpz_raii m1, m2; 41 | integer n1, n2; 42 | mpz_abs(&m1.m_mpz, &m2.m_mpz); 43 | REQUIRE(&abs(n1, n2) == &n1); 44 | REQUIRE((lex_cast(n1) == lex_cast(m1))); 45 | REQUIRE(n1.is_static()); 46 | // Test the other variants. 47 | n1.abs(); 48 | REQUIRE((lex_cast(n1) == lex_cast(m1))); 49 | REQUIRE(n1.is_static()); 50 | REQUIRE((lex_cast(abs(n1)) == lex_cast(m1))); 51 | detail::mpz_raii tmp; 52 | std::uniform_int_distribution sdist(0, 1); 53 | // Run a variety of tests with operands with x number of limbs. 54 | auto random_xy = [&](unsigned x) { 55 | for (int i = 0; i < ntries; ++i) { 56 | // NOLINTNEXTLINE(misc-redundant-expression) 57 | if (sdist(rng) && sdist(rng) && sdist(rng)) { 58 | // Reset rop every once in a while. 59 | n1 = integer{}; 60 | } 61 | random_integer(tmp, x, rng); 62 | mpz_set(&m2.m_mpz, &tmp.m_mpz); 63 | n2 = integer(detail::mpz_to_str(&tmp.m_mpz)); 64 | if (sdist(rng)) { 65 | mpz_neg(&m2.m_mpz, &m2.m_mpz); 66 | n2.neg(); 67 | } 68 | if (n2.is_static() && sdist(rng)) { 69 | // Promote sometimes, if possible. 70 | n2.promote(); 71 | } 72 | mpz_abs(&m1.m_mpz, &m2.m_mpz); 73 | abs(n1, n2); 74 | REQUIRE((lex_cast(n1) == lex_cast(m1))); 75 | REQUIRE((lex_cast(n1) == lex_cast(abs(n2)))); 76 | n2.abs(); 77 | REQUIRE((lex_cast(n1) == lex_cast(n2))); 78 | } 79 | }; 80 | 81 | random_xy(0); 82 | random_xy(1); 83 | random_xy(2); 84 | random_xy(3); 85 | random_xy(4); 86 | } 87 | }; 88 | 89 | TEST_CASE("abs") 90 | { 91 | tuple_for_each(sizes{}, abs_tester{}); 92 | } 93 | -------------------------------------------------------------------------------- /test/integer_even_odd.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016-2023 Francesco Biscani (bluescarni@gmail.com) 2 | // 3 | // This file is part of the mp++ library. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla 6 | // Public License v. 2.0. If a copy of the MPL was not distributed 7 | // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | 16 | #include 17 | 18 | #include "catch.hpp" 19 | #include "test_utils.hpp" 20 | 21 | static const int ntries = 1000; 22 | 23 | // NOLINTNEXTLINE(google-build-using-namespace) 24 | using namespace mppp; 25 | // NOLINTNEXTLINE(google-build-using-namespace) 26 | using namespace mppp_test; 27 | 28 | using sizes = std::tuple, std::integral_constant, 29 | std::integral_constant, std::integral_constant, 30 | std::integral_constant>; 31 | 32 | // NOLINTNEXTLINE(cert-err58-cpp, cert-msc32-c, cert-msc51-cpp, cppcoreguidelines-avoid-non-const-global-variables) 33 | static std::mt19937 rng; 34 | 35 | struct even_odd_tester { 36 | template 37 | inline void operator()(const S &) const 38 | { 39 | using integer = integer; 40 | // Start with all zeroes. 41 | detail::mpz_raii m1; 42 | integer n1; 43 | REQUIRE(even_p(n1)); 44 | REQUIRE(n1.even_p()); 45 | REQUIRE(!odd_p(n1)); 46 | REQUIRE(!n1.odd_p()); 47 | // Simple tests. 48 | n1 = integer{1}; 49 | REQUIRE(!even_p(n1)); 50 | REQUIRE(!n1.even_p()); 51 | REQUIRE(odd_p(n1)); 52 | REQUIRE(n1.odd_p()); 53 | n1 = integer{-1}; 54 | REQUIRE(!even_p(n1)); 55 | REQUIRE(!n1.even_p()); 56 | REQUIRE(odd_p(n1)); 57 | REQUIRE(n1.odd_p()); 58 | n1 = integer{3}; 59 | REQUIRE(!even_p(n1)); 60 | REQUIRE(!n1.even_p()); 61 | REQUIRE(odd_p(n1)); 62 | REQUIRE(n1.odd_p()); 63 | n1 = integer{-3}; 64 | REQUIRE(!even_p(n1)); 65 | REQUIRE(!n1.even_p()); 66 | REQUIRE(odd_p(n1)); 67 | REQUIRE(n1.odd_p()); 68 | n1 = integer{4}; 69 | REQUIRE(even_p(n1)); 70 | REQUIRE(n1.even_p()); 71 | REQUIRE(!odd_p(n1)); 72 | REQUIRE(!n1.odd_p()); 73 | n1 = integer{-4}; 74 | REQUIRE(even_p(n1)); 75 | REQUIRE(n1.even_p()); 76 | REQUIRE(!odd_p(n1)); 77 | REQUIRE(!n1.odd_p()); 78 | detail::mpz_raii tmp; 79 | std::uniform_int_distribution sdist(0, 1); 80 | // Random tests with x number of limbs. 81 | auto random_xy = [&](unsigned x) { 82 | for (int i = 0; i < ntries; ++i) { 83 | random_integer(tmp, x, rng); 84 | mpz_set(&m1.m_mpz, &tmp.m_mpz); 85 | n1 = integer(detail::mpz_to_str(&tmp.m_mpz)); 86 | if (sdist(rng)) { 87 | mpz_neg(&m1.m_mpz, &m1.m_mpz); 88 | n1.neg(); 89 | } 90 | if (n1.is_static() && sdist(rng)) { 91 | // Promote sometimes, if possible. 92 | n1.promote(); 93 | } 94 | REQUIRE((even_p(n1) == mpz_even_p(&m1.m_mpz))); 95 | REQUIRE((n1.even_p() == mpz_even_p(&m1.m_mpz))); 96 | REQUIRE((odd_p(n1) == mpz_odd_p(&m1.m_mpz))); 97 | REQUIRE((n1.odd_p() == mpz_odd_p(&m1.m_mpz))); 98 | } 99 | }; 100 | 101 | random_xy(0); 102 | random_xy(1); 103 | random_xy(2); 104 | random_xy(3); 105 | random_xy(4); 106 | } 107 | }; 108 | 109 | TEST_CASE("even_odd") 110 | { 111 | tuple_for_each(sizes{}, even_odd_tester{}); 112 | } 113 | -------------------------------------------------------------------------------- /test/integer_fac.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016-2023 Francesco Biscani (bluescarni@gmail.com) 2 | // 3 | // This file is part of the mp++ library. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla 6 | // Public License v. 2.0. If a copy of the MPL was not distributed 7 | // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | 18 | #include 19 | 20 | #include "catch.hpp" 21 | #include "test_utils.hpp" 22 | 23 | static const int ntries = 1000; 24 | 25 | // NOLINTNEXTLINE(google-build-using-namespace) 26 | using namespace mppp; 27 | // NOLINTNEXTLINE(google-build-using-namespace) 28 | using namespace mppp_test; 29 | 30 | using sizes = std::tuple, std::integral_constant, 31 | std::integral_constant, std::integral_constant, 32 | std::integral_constant>; 33 | 34 | // NOLINTNEXTLINE(cert-err58-cpp, cert-msc32-c, cert-msc51-cpp, cppcoreguidelines-avoid-non-const-global-variables) 35 | static std::mt19937 rng; 36 | 37 | struct fac_tester { 38 | template 39 | inline void operator()(const S &) const 40 | { 41 | using integer = integer; 42 | // Start with all zeroes. 43 | detail::mpz_raii m1; 44 | integer n1; 45 | mpz_fac_ui(&m1.m_mpz, 0); 46 | fac_ui(n1, 0); 47 | REQUIRE((lex_cast(n1) == lex_cast(m1))); 48 | REQUIRE(n1.is_static()); 49 | // Try one. 50 | mpz_fac_ui(&m1.m_mpz, 1); 51 | REQUIRE(&fac_ui(n1, 1) == &n1); 52 | REQUIRE((lex_cast(n1) == lex_cast(m1))); 53 | REQUIRE(n1.is_static()); 54 | // Try two. 55 | mpz_fac_ui(&m1.m_mpz, 2); 56 | fac_ui(n1, 2); 57 | REQUIRE((lex_cast(n1) == lex_cast(m1))); 58 | REQUIRE(n1.is_static()); 59 | // Try 4. 60 | mpz_fac_ui(&m1.m_mpz, 4); 61 | fac_ui(n1, 4); 62 | REQUIRE((lex_cast(n1) == lex_cast(m1))); 63 | REQUIRE(n1.is_static()); 64 | // Try 10. 65 | mpz_fac_ui(&m1.m_mpz, 10); 66 | fac_ui(n1, 10); 67 | REQUIRE((lex_cast(n1) == lex_cast(m1))); 68 | REQUIRE(n1.is_static()); 69 | // Try the limit. 70 | mpz_fac_ui(&m1.m_mpz, 1000000ul); 71 | fac_ui(n1, 1000000ul); 72 | REQUIRE((lex_cast(n1) == lex_cast(m1))); 73 | // Error testing. 74 | REQUIRE_THROWS_PREDICATE(fac_ui(n1, 1000001ul), std::invalid_argument, [](const std::invalid_argument &ex) { 75 | return std::string(ex.what()) 76 | == "The value 1000001 is too large to be used as input for the factorial " 77 | "function (the maximum allowed value is 1000000)"; 78 | }); 79 | detail::mpz_raii tmp; 80 | std::uniform_int_distribution sdist(0, 1); 81 | std::uniform_int_distribution udist(0u, 100u); 82 | for (int i = 0; i < ntries; ++i) { 83 | // NOLINTNEXTLINE(misc-redundant-expression) 84 | if (sdist(rng) && sdist(rng) && sdist(rng)) { 85 | // Reset rop every once in a while. 86 | n1 = integer{}; 87 | } 88 | if (n1.is_static() && sdist(rng)) { 89 | // Promote sometimes, if possible. 90 | n1.promote(); 91 | } 92 | const auto x = udist(rng); 93 | mpz_fac_ui(&m1.m_mpz, x); 94 | fac_ui(n1, x); 95 | REQUIRE((lex_cast(n1) == lex_cast(m1))); 96 | } 97 | } 98 | }; 99 | 100 | TEST_CASE("fac") 101 | { 102 | tuple_for_each(sizes{}, fac_tester{}); 103 | } 104 | -------------------------------------------------------------------------------- /test/integer_get_mpz_t.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016-2023 Francesco Biscani (bluescarni@gmail.com) 2 | // 3 | // This file is part of the mp++ library. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla 6 | // Public License v. 2.0. If a copy of the MPL was not distributed 7 | // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | #include 16 | 17 | #include "catch.hpp" 18 | #include "test_utils.hpp" 19 | 20 | // NOLINTNEXTLINE(google-build-using-namespace) 21 | using namespace mppp; 22 | // NOLINTNEXTLINE(google-build-using-namespace) 23 | using namespace mppp_test; 24 | 25 | using sizes = std::tuple, std::integral_constant, 26 | std::integral_constant, std::integral_constant, 27 | std::integral_constant>; 28 | 29 | struct get_mpz_t_tester { 30 | template 31 | inline void operator()(const S &) const 32 | { 33 | using integer = integer; 34 | integer n; 35 | auto ptr = n.get_mpz_t(); 36 | REQUIRE(n.is_dynamic()); 37 | REQUIRE((mpz_sgn(ptr) == 0)); 38 | auto view = n.get_mpz_view(); 39 | REQUIRE((mpz_sgn(view.get()) == 0)); 40 | REQUIRE(view.get() == ptr); 41 | n = 12; 42 | REQUIRE(n.is_static()); 43 | ptr = n.get_mpz_t(); 44 | REQUIRE(n.is_dynamic()); 45 | REQUIRE((mpz_sgn(ptr) == 1)); 46 | REQUIRE((mpz_cmp_ui(ptr, 12) == 0)); 47 | auto view2 = n.get_mpz_view(); 48 | REQUIRE((mpz_sgn(view2.get()) == 1)); 49 | REQUIRE(view2.get() == ptr); 50 | ptr = n.get_mpz_t(); 51 | REQUIRE(n.is_dynamic()); 52 | REQUIRE((mpz_sgn(ptr) == 1)); 53 | REQUIRE((mpz_cmp_ui(ptr, 12) == 0)); 54 | auto view2a = n.get_mpz_view(); 55 | REQUIRE((mpz_sgn(view2a.get()) == 1)); 56 | REQUIRE(view2a.get() == ptr); 57 | n = -23; 58 | REQUIRE(n.is_static()); 59 | ptr = n.get_mpz_t(); 60 | REQUIRE(n.is_dynamic()); 61 | REQUIRE((mpz_sgn(ptr) == -1)); 62 | REQUIRE((mpz_cmp_si(ptr, -23) == 0)); 63 | auto view3 = n.get_mpz_view(); 64 | REQUIRE((mpz_sgn(view3.get()) == -1)); 65 | REQUIRE(view3.get() == ptr); 66 | ptr = n.get_mpz_t(); 67 | REQUIRE(n.is_dynamic()); 68 | REQUIRE((mpz_sgn(ptr) == -1)); 69 | REQUIRE((mpz_cmp_si(ptr, -23) == 0)); 70 | auto view3a = n.get_mpz_view(); 71 | REQUIRE((mpz_sgn(view3a.get()) == -1)); 72 | REQUIRE(view3a.get() == ptr); 73 | } 74 | }; 75 | 76 | TEST_CASE("get_mpz_t") 77 | { 78 | tuple_for_each(sizes{}, get_mpz_t_tester{}); 79 | } 80 | -------------------------------------------------------------------------------- /test/integer_hash.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016-2023 Francesco Biscani (bluescarni@gmail.com) 2 | // 3 | // This file is part of the mp++ library. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla 6 | // Public License v. 2.0. If a copy of the MPL was not distributed 7 | // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | 17 | #include 18 | 19 | #include "catch.hpp" 20 | #include "test_utils.hpp" 21 | 22 | static const int ntries = 1000; 23 | 24 | // NOLINTNEXTLINE(google-build-using-namespace) 25 | using namespace mppp; 26 | // NOLINTNEXTLINE(google-build-using-namespace) 27 | using namespace mppp_test; 28 | 29 | using sizes = std::tuple, std::integral_constant, 30 | std::integral_constant, std::integral_constant, 31 | std::integral_constant>; 32 | 33 | // NOLINTNEXTLINE(cert-err58-cpp, cert-msc32-c, cert-msc51-cpp, cppcoreguidelines-avoid-non-const-global-variables) 34 | static std::mt19937 rng; 35 | 36 | struct hash_tester { 37 | template 38 | inline void operator()(const S &) const 39 | { 40 | using integer = integer; 41 | const std::hash hasher{}; 42 | auto n1 = integer{12}, n2 = n1; 43 | REQUIRE(n2.is_static()); 44 | n1.promote(); 45 | REQUIRE(n1.is_dynamic()); 46 | REQUIRE((hash(n1) == hash(n2))); 47 | REQUIRE((hasher(n1) == hash(n2))); 48 | n1 = integer{-12}; 49 | n2 = n1; 50 | REQUIRE(n2.is_static()); 51 | n1.promote(); 52 | REQUIRE(n1.is_dynamic()); 53 | REQUIRE((hash(n1) == hash(n2))); 54 | REQUIRE((hash(n1) == hasher(n2))); 55 | detail::mpz_raii tmp; 56 | std::uniform_int_distribution sdist(0, 1); 57 | // Run a variety of tests with operands with x number of limbs. 58 | // 59 | // NOTE: capture n1/n2 by value because there seems to be 60 | // a strict aliasing bug in GCC, perhaps related to the union 61 | // with common initial sequence used to implement integer. 62 | // Essentially, what seems to happen is that the compiler ignores 63 | // the negation of n1 via n1.neg(), and the subsequent assignment 64 | // n2 = n1 will result in n1 and n2 having the same absolute 65 | // value but different sign. It seems like the "if (sdist(rng)) {" 66 | // is skipped altogether - adding a print statement in it is enough 67 | // to avoid the issue. Compiling with -fno-strict-aliasing also seems 68 | // to hide the bug, as well as capturing only n2 by reference. 69 | auto random_xy = [&, n1, n2](unsigned x) mutable { 70 | for (int i = 0; i < ntries; ++i) { 71 | random_integer(tmp, x, rng); 72 | n1 = integer(detail::mpz_to_str(&tmp.m_mpz)); 73 | if (sdist(rng)) { 74 | // std::cout << "Negated!\n"; 75 | n1.neg(); 76 | } 77 | n2 = n1; 78 | if (n2.is_static()) { 79 | n1.promote(); 80 | } 81 | REQUIRE((hash(n1) == hash(n2))); 82 | REQUIRE((hasher(n1) == hash(n2))); 83 | } 84 | }; 85 | 86 | random_xy(0); 87 | random_xy(1); 88 | random_xy(2); 89 | random_xy(3); 90 | random_xy(4); 91 | } 92 | }; 93 | 94 | TEST_CASE("hash") 95 | { 96 | tuple_for_each(sizes{}, hash_tester{}); 97 | } 98 | -------------------------------------------------------------------------------- /test/integer_is_zero_one.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016-2023 Francesco Biscani (bluescarni@gmail.com) 2 | // 3 | // This file is part of the mp++ library. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla 6 | // Public License v. 2.0. If a copy of the MPL was not distributed 7 | // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | #include "catch.hpp" 16 | #include "test_utils.hpp" 17 | 18 | // NOLINTNEXTLINE(google-build-using-namespace) 19 | using namespace mppp; 20 | // NOLINTNEXTLINE(google-build-using-namespace) 21 | using namespace mppp_test; 22 | 23 | using sizes = std::tuple, std::integral_constant, 24 | std::integral_constant, std::integral_constant, 25 | std::integral_constant>; 26 | 27 | struct is_zero_one_tester { 28 | template 29 | inline void operator()(const S &) const 30 | { 31 | using integer = integer; 32 | integer n; 33 | REQUIRE(n.is_zero()); 34 | REQUIRE(is_zero(n)); 35 | REQUIRE(!n.is_one()); 36 | REQUIRE(!is_one(n)); 37 | REQUIRE(!n.is_negative_one()); 38 | REQUIRE(!is_negative_one(n)); 39 | n.promote(); 40 | REQUIRE(n.is_zero()); 41 | REQUIRE(is_zero(n)); 42 | REQUIRE(!n.is_one()); 43 | REQUIRE(!is_one(n)); 44 | REQUIRE(!n.is_negative_one()); 45 | REQUIRE(!is_negative_one(n)); 46 | n = 1; 47 | REQUIRE(n.is_static()); 48 | REQUIRE(!n.is_zero()); 49 | REQUIRE(!is_zero(n)); 50 | REQUIRE(n.is_one()); 51 | REQUIRE(is_one(n)); 52 | REQUIRE(!n.is_negative_one()); 53 | REQUIRE(!is_negative_one(n)); 54 | n.promote(); 55 | REQUIRE(!n.is_zero()); 56 | REQUIRE(!is_zero(n)); 57 | REQUIRE(n.is_one()); 58 | REQUIRE(is_one(n)); 59 | REQUIRE(!n.is_negative_one()); 60 | REQUIRE(!is_negative_one(n)); 61 | n = -1; 62 | REQUIRE(n.is_static()); 63 | REQUIRE(!n.is_zero()); 64 | REQUIRE(!is_zero(n)); 65 | REQUIRE(!n.is_one()); 66 | REQUIRE(!is_one(n)); 67 | REQUIRE(n.is_negative_one()); 68 | REQUIRE(is_negative_one(n)); 69 | n.promote(); 70 | REQUIRE(!n.is_zero()); 71 | REQUIRE(!is_zero(n)); 72 | REQUIRE(!n.is_one()); 73 | REQUIRE(!is_one(n)); 74 | REQUIRE(n.is_negative_one()); 75 | REQUIRE(is_negative_one(n)); 76 | n = 12; 77 | REQUIRE(n.is_static()); 78 | REQUIRE(!n.is_zero()); 79 | REQUIRE(!is_zero(n)); 80 | REQUIRE(!n.is_one()); 81 | REQUIRE(!is_one(n)); 82 | REQUIRE(!n.is_negative_one()); 83 | REQUIRE(!is_negative_one(n)); 84 | n.promote(); 85 | REQUIRE(!n.is_zero()); 86 | REQUIRE(!is_zero(n)); 87 | REQUIRE(!n.is_one()); 88 | REQUIRE(!is_one(n)); 89 | REQUIRE(!n.is_negative_one()); 90 | REQUIRE(!is_negative_one(n)); 91 | n = -12; 92 | REQUIRE(n.is_static()); 93 | REQUIRE(!n.is_zero()); 94 | REQUIRE(!is_zero(n)); 95 | REQUIRE(!n.is_one()); 96 | REQUIRE(!is_one(n)); 97 | REQUIRE(!n.is_negative_one()); 98 | REQUIRE(!is_negative_one(n)); 99 | n.promote(); 100 | REQUIRE(!n.is_zero()); 101 | REQUIRE(!is_zero(n)); 102 | REQUIRE(!n.is_one()); 103 | REQUIRE(!is_one(n)); 104 | REQUIRE(!n.is_negative_one()); 105 | REQUIRE(!is_negative_one(n)); 106 | } 107 | }; 108 | 109 | TEST_CASE("is_zero_one") 110 | { 111 | tuple_for_each(sizes{}, is_zero_one_tester{}); 112 | } 113 | -------------------------------------------------------------------------------- /test/integer_limb_size_nbits.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016-2023 Francesco Biscani (bluescarni@gmail.com) 2 | // 3 | // This file is part of the mp++ library. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla 6 | // Public License v. 2.0. If a copy of the MPL was not distributed 7 | // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | #include 10 | #include 11 | 12 | #include "catch.hpp" 13 | 14 | // NOLINTNEXTLINE(google-build-using-namespace) 15 | using namespace mppp; 16 | 17 | TEST_CASE("limb_size_nbits") 18 | { 19 | REQUIRE(detail::limb_size_nbits(1) == 1u); 20 | REQUIRE(detail::limb_size_nbits(2) == 2u); 21 | REQUIRE(detail::limb_size_nbits(3) == 2u); 22 | REQUIRE(detail::limb_size_nbits(4) == 3u); 23 | REQUIRE(detail::limb_size_nbits(::mp_limb_t(1) << (GMP_NUMB_BITS - 1)) == GMP_NUMB_BITS); 24 | REQUIRE(detail::limb_size_nbits(::mp_limb_t(1) << (GMP_NUMB_BITS - 2)) == GMP_NUMB_BITS - 1); 25 | REQUIRE(detail::limb_size_nbits((::mp_limb_t(1) << (GMP_NUMB_BITS - 1)) + 1) == GMP_NUMB_BITS); 26 | REQUIRE(detail::limb_size_nbits(::mp_limb_t(1) << (GMP_NUMB_BITS - 2)) == GMP_NUMB_BITS - 1); 27 | REQUIRE(detail::limb_size_nbits((::mp_limb_t(1) << (GMP_NUMB_BITS - 2)) + 1) == GMP_NUMB_BITS - 1); 28 | // Test the GMP implementation, which we do not cover in the CI. 29 | ::mp_limb_t l = 1; 30 | REQUIRE(static_cast(mpn_sizeinbase(&l, 1, 2)) == 1u); 31 | l = 2; 32 | REQUIRE(static_cast(mpn_sizeinbase(&l, 1, 2)) == 2u); 33 | l = 3; 34 | REQUIRE(static_cast(mpn_sizeinbase(&l, 1, 2)) == 2u); 35 | l = 4; 36 | REQUIRE(static_cast(mpn_sizeinbase(&l, 1, 2)) == 3u); 37 | l = ::mp_limb_t(1) << (GMP_NUMB_BITS - 1); 38 | REQUIRE(static_cast(mpn_sizeinbase(&l, 1, 2)) == GMP_NUMB_BITS); 39 | l += 1; 40 | REQUIRE(static_cast(mpn_sizeinbase(&l, 1, 2)) == GMP_NUMB_BITS); 41 | l = ::mp_limb_t(1) << (GMP_NUMB_BITS - 2); 42 | REQUIRE(static_cast(mpn_sizeinbase(&l, 1, 2)) == GMP_NUMB_BITS - 1); 43 | l += 1; 44 | REQUIRE(static_cast(mpn_sizeinbase(&l, 1, 2)) == GMP_NUMB_BITS - 1); 45 | } 46 | -------------------------------------------------------------------------------- /test/integer_neg.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016-2023 Francesco Biscani (bluescarni@gmail.com) 2 | // 3 | // This file is part of the mp++ library. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla 6 | // Public License v. 2.0. If a copy of the MPL was not distributed 7 | // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | 16 | #include 17 | 18 | #include "catch.hpp" 19 | #include "test_utils.hpp" 20 | 21 | static const int ntries = 1000; 22 | 23 | // NOLINTNEXTLINE(google-build-using-namespace) 24 | using namespace mppp; 25 | // NOLINTNEXTLINE(google-build-using-namespace) 26 | using namespace mppp_test; 27 | 28 | using sizes = std::tuple, std::integral_constant, 29 | std::integral_constant, std::integral_constant, 30 | std::integral_constant>; 31 | 32 | // NOLINTNEXTLINE(cert-err58-cpp, cert-msc32-c, cert-msc51-cpp, cppcoreguidelines-avoid-non-const-global-variables) 33 | static std::mt19937 rng; 34 | 35 | struct neg_tester { 36 | template 37 | inline void operator()(const S &) const 38 | { 39 | using integer = integer; 40 | // Start with all zeroes. 41 | detail::mpz_raii m1, m2; 42 | integer n1, n2; 43 | mpz_neg(&m1.m_mpz, &m2.m_mpz); 44 | REQUIRE(&neg(n1, n2) == &n1); 45 | REQUIRE((lex_cast(n1) == lex_cast(m1))); 46 | REQUIRE(n1.is_static()); 47 | // Test the other variants. 48 | n1.neg(); 49 | REQUIRE((lex_cast(n1) == lex_cast(m1))); 50 | REQUIRE(n1.is_static()); 51 | REQUIRE((lex_cast(neg(n1)) == lex_cast(m1))); 52 | detail::mpz_raii tmp; 53 | std::uniform_int_distribution sdist(0, 1); 54 | // Run a variety of tests with operands with x number of limbs. 55 | auto random_xy = [&](unsigned x) { 56 | for (int i = 0; i < ntries; ++i) { 57 | // NOLINTNEXTLINE(misc-redundant-expression) 58 | if (sdist(rng) && sdist(rng) && sdist(rng)) { 59 | // Reset rop every once in a while. 60 | n1 = integer{}; 61 | } 62 | random_integer(tmp, x, rng); 63 | mpz_set(&m2.m_mpz, &tmp.m_mpz); 64 | n2 = integer(detail::mpz_to_str(&tmp.m_mpz)); 65 | if (sdist(rng)) { 66 | mpz_neg(&m2.m_mpz, &m2.m_mpz); 67 | n2.neg(); 68 | } 69 | if (n2.is_static() && sdist(rng)) { 70 | // Promote sometimes, if possible. 71 | n2.promote(); 72 | } 73 | mpz_neg(&m1.m_mpz, &m2.m_mpz); 74 | neg(n1, n2); 75 | REQUIRE((lex_cast(n1) == lex_cast(m1))); 76 | REQUIRE((lex_cast(n1) == lex_cast(neg(n2)))); 77 | n2.neg(); 78 | REQUIRE((lex_cast(n1) == lex_cast(n2))); 79 | } 80 | }; 81 | 82 | random_xy(0); 83 | random_xy(1); 84 | random_xy(2); 85 | random_xy(3); 86 | random_xy(4); 87 | } 88 | }; 89 | 90 | TEST_CASE("neg") 91 | { 92 | tuple_for_each(sizes{}, neg_tester{}); 93 | } 94 | -------------------------------------------------------------------------------- /test/integer_nextprime.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016-2023 Francesco Biscani (bluescarni@gmail.com) 2 | // 3 | // This file is part of the mp++ library. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla 6 | // Public License v. 2.0. If a copy of the MPL was not distributed 7 | // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | 16 | #include 17 | 18 | #include "catch.hpp" 19 | #include "test_utils.hpp" 20 | 21 | static const int ntries = 1000; 22 | 23 | // NOLINTNEXTLINE(google-build-using-namespace) 24 | using namespace mppp; 25 | // NOLINTNEXTLINE(google-build-using-namespace) 26 | using namespace mppp_test; 27 | 28 | using sizes = std::tuple, std::integral_constant, 29 | std::integral_constant, std::integral_constant, 30 | std::integral_constant>; 31 | 32 | // NOLINTNEXTLINE(cert-err58-cpp, cert-msc32-c, cert-msc51-cpp, cppcoreguidelines-avoid-non-const-global-variables) 33 | static std::mt19937 rng; 34 | 35 | struct nextprime_tester { 36 | template 37 | inline void operator()(const S &) const 38 | { 39 | using integer = integer; 40 | // Start with all zeroes. 41 | detail::mpz_raii m1, m2; 42 | integer n1, n2; 43 | mpz_nextprime(&m1.m_mpz, &m2.m_mpz); 44 | REQUIRE(&nextprime(n1, n2) == &n1); 45 | REQUIRE((lex_cast(n1) == lex_cast(m1))); 46 | REQUIRE(n1.is_static()); 47 | // Test the other variants. 48 | n1.nextprime(); 49 | mpz_nextprime(&m1.m_mpz, &m1.m_mpz); 50 | REQUIRE((lex_cast(n1) == lex_cast(m1))); 51 | REQUIRE(n1.is_static()); 52 | mpz_nextprime(&m1.m_mpz, &m1.m_mpz); 53 | REQUIRE((lex_cast(nextprime(n1)) == lex_cast(m1))); 54 | detail::mpz_raii tmp; 55 | std::uniform_int_distribution sdist(0, 1); 56 | // Run a variety of tests with operands with x number of limbs. 57 | auto random_xy = [&](unsigned x) { 58 | for (int i = 0; i < ntries; ++i) { 59 | // NOLINTNEXTLINE(misc-redundant-expression) 60 | if (sdist(rng) && sdist(rng) && sdist(rng)) { 61 | // Reset rop every once in a while. 62 | n1 = integer{}; 63 | } 64 | random_integer(tmp, x, rng); 65 | mpz_set(&m2.m_mpz, &tmp.m_mpz); 66 | n2 = integer(detail::mpz_to_str(&tmp.m_mpz)); 67 | if (sdist(rng)) { 68 | mpz_neg(&m2.m_mpz, &m2.m_mpz); 69 | n2.neg(); 70 | } 71 | if (n2.is_static() && sdist(rng)) { 72 | // Promote sometimes, if possible. 73 | n2.promote(); 74 | } 75 | mpz_nextprime(&m1.m_mpz, &m2.m_mpz); 76 | nextprime(n1, n2); 77 | REQUIRE((lex_cast(n1) == lex_cast(m1))); 78 | REQUIRE((lex_cast(n1) == lex_cast(nextprime(n2)))); 79 | n2.nextprime(); 80 | REQUIRE((lex_cast(n1) == lex_cast(n2))); 81 | } 82 | }; 83 | 84 | random_xy(0); 85 | random_xy(1); 86 | random_xy(2); 87 | random_xy(3); 88 | random_xy(4); 89 | } 90 | }; 91 | 92 | TEST_CASE("nextprime") 93 | { 94 | tuple_for_each(sizes{}, nextprime_tester{}); 95 | } 96 | -------------------------------------------------------------------------------- /test/integer_probab_prime_p.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016-2023 Francesco Biscani (bluescarni@gmail.com) 2 | // 3 | // This file is part of the mp++ library. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla 6 | // Public License v. 2.0. If a copy of the MPL was not distributed 7 | // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | 17 | #include 18 | 19 | #include "catch.hpp" 20 | #include "test_utils.hpp" 21 | 22 | // NOLINTNEXTLINE(google-build-using-namespace) 23 | using namespace mppp; 24 | // NOLINTNEXTLINE(google-build-using-namespace) 25 | using namespace mppp_test; 26 | 27 | using sizes = std::tuple, std::integral_constant, 28 | std::integral_constant, std::integral_constant, 29 | std::integral_constant>; 30 | 31 | struct probab_prime_p_tester { 32 | template 33 | inline void operator()(const S &) const 34 | { 35 | using integer = integer; 36 | detail::mpz_raii m1; 37 | integer n1; 38 | REQUIRE((probab_prime_p(n1) == mpz_probab_prime_p(&m1.m_mpz, 25))); 39 | REQUIRE((n1.probab_prime_p() == mpz_probab_prime_p(&m1.m_mpz, 25))); 40 | mpz_set_ui(&m1.m_mpz, 1u); 41 | n1 = integer(1); 42 | REQUIRE((probab_prime_p(n1, 12) == mpz_probab_prime_p(&m1.m_mpz, 25))); 43 | REQUIRE((n1.probab_prime_p(12) == mpz_probab_prime_p(&m1.m_mpz, 25))); 44 | mpz_set_ui(&m1.m_mpz, 123u); 45 | n1 = integer(123); 46 | REQUIRE((probab_prime_p(n1) == mpz_probab_prime_p(&m1.m_mpz, 25))); 47 | REQUIRE((n1.probab_prime_p() == mpz_probab_prime_p(&m1.m_mpz, 25))); 48 | // Couple of sanity checks. 49 | REQUIRE((probab_prime_p(integer{17}) != 0)); 50 | REQUIRE((probab_prime_p(integer{49979687ll}) != 0)); 51 | REQUIRE((probab_prime_p(integer{128}) == 0)); 52 | // Test errors. 53 | REQUIRE_THROWS_PREDICATE(probab_prime_p(n1, 0), std::invalid_argument, [](const std::invalid_argument &ex) { 54 | return std::string(ex.what()) 55 | == "The number of primality tests must be at least 1, but a value of " 56 | "0 was provided instead"; 57 | }); 58 | REQUIRE_THROWS_PREDICATE(n1.probab_prime_p(-1), std::invalid_argument, [](const std::invalid_argument &ex) { 59 | return std::string(ex.what()) 60 | == "The number of primality tests must be at least 1, but a value of " 61 | "-1 was provided instead"; 62 | }); 63 | n1 = integer(-123); 64 | REQUIRE_THROWS_PREDICATE(probab_prime_p(n1), std::invalid_argument, [](const std::invalid_argument &ex) { 65 | return std::string(ex.what()) == "Cannot run primality tests on the negative number -123"; 66 | }); 67 | REQUIRE_THROWS_PREDICATE(n1.probab_prime_p(), std::invalid_argument, [](const std::invalid_argument &ex) { 68 | return std::string(ex.what()) == "Cannot run primality tests on the negative number -123"; 69 | }); 70 | } 71 | }; 72 | 73 | TEST_CASE("probab_prime_p") 74 | { 75 | tuple_for_each(sizes{}, probab_prime_p_tester{}); 76 | } 77 | -------------------------------------------------------------------------------- /test/pybind11/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Setup the list of Python components we need to locate. 2 | set(_REQUIRED_PYTHON_COMPONENTS Interpreter Development.Module) 3 | 4 | # NOTE: strictly speaking, we should need only the Interpreter and Development.Module 5 | # components. However, in certain setups (e.g., skbuild), it looks 6 | # like if we specify only Development.Module CMake is unable to correctly locate 7 | # the Python installation. Hence, as a workaround, if the following line fails 8 | # and Python3 is *not* found, we try again, this time with the full Development 9 | # component (rather than only Development.Module). This seems to work around the 10 | # issue, for now at least. 11 | find_package(Python3 QUIET COMPONENTS ${_REQUIRED_PYTHON_COMPONENTS}) 12 | 13 | if(NOT Python3_FOUND) 14 | list(POP_BACK _REQUIRED_PYTHON_COMPONENTS) 15 | list(APPEND _REQUIRED_PYTHON_COMPONENTS Development) 16 | endif() 17 | 18 | find_package(Python3 QUIET REQUIRED COMPONENTS ${_REQUIRED_PYTHON_COMPONENTS}) 19 | 20 | message(STATUS "Python3 interpreter: ${Python3_EXECUTABLE}") 21 | message(STATUS "Python3 installation directory: ${Python3_SITEARCH}") 22 | unset(_REQUIRED_PYTHON_COMPONENTS) 23 | 24 | # Find pybind11. 25 | find_package(pybind11 REQUIRED CONFIG) 26 | 27 | # NOTE: this is very similar to the function for creating C++ tests. 28 | function(ADD_MPPP_PYBIND11_TESTCASE arg1) 29 | if(MPPP_TEST_NSPLIT) 30 | math(EXPR __MPPP_TEST_NUM "(${_MPPP_TEST_NUM} + 1) % ${MPPP_TEST_NSPLIT}") 31 | set(_MPPP_TEST_NUM ${__MPPP_TEST_NUM} PARENT_SCOPE) 32 | endif() 33 | if(MPPP_TEST_NSPLIT AND "${MPPP_TEST_SPLIT_NUM}" STREQUAL "${_MPPP_TEST_NUM}") 34 | return() 35 | endif() 36 | Python3_add_library(${arg1} MODULE WITH_SOABI ${arg1}.cpp) 37 | target_link_libraries(${arg1} PRIVATE mp++ "${pybind11_LIBRARIES}") 38 | target_include_directories(${arg1} SYSTEM PRIVATE "${pybind11_INCLUDE_DIR}" "${Python3_INCLUDE_DIRS}") 39 | target_compile_definitions(${arg1} PRIVATE "${pybind11_DEFINITIONS}") 40 | target_compile_options(${arg1} PRIVATE 41 | "$<$:${MPPP_CXX_FLAGS_DEBUG}>" 42 | "$<$:${MPPP_CXX_FLAGS_RELEASE}>" 43 | "$<$:${MPPP_CXX_FLAGS_RELEASE}>" 44 | "$<$:${MPPP_CXX_FLAGS_RELEASE}>" 45 | ) 46 | set_target_properties(${arg1} PROPERTIES CXX_VISIBILITY_PRESET hidden) 47 | set_target_properties(${arg1} PROPERTIES VISIBILITY_INLINES_HIDDEN TRUE) 48 | target_compile_features(${arg1} PRIVATE cxx_std_11) 49 | set_property(TARGET ${arg1} PROPERTY CXX_EXTENSIONS NO) 50 | # Copy over the Python test runner. 51 | # NOTE: need to use file(GENERATE) because in multi-config build systems (e.g., MSVC) we need to copy 52 | # the runner in a directory depending on the config type, and we need to do it at generation time. 53 | # We can fetch the correct directory by reading the TARGET_FILE_DIR property of the python module. 54 | file(GENERATE OUTPUT "$/run_${arg1}.py" INPUT "${CMAKE_CURRENT_SOURCE_DIR}/run_${arg1}.py") 55 | # Add the actual test. 56 | add_test(NAME ${arg1} COMMAND "${Python3_EXECUTABLE}" run_${arg1}.py WORKING_DIRECTORY "$") 57 | endfunction() 58 | 59 | ADD_MPPP_PYBIND11_TESTCASE(pybind11_test_01) 60 | 61 | # Change the split test number in the parent scope. 62 | if(MPPP_TEST_NSPLIT) 63 | set(_MPPP_TEST_NUM ${_MPPP_TEST_NUM} PARENT_SCOPE) 64 | endif() 65 | -------------------------------------------------------------------------------- /test/rational_hash.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016-2023 Francesco Biscani (bluescarni@gmail.com) 2 | // 3 | // This file is part of the mp++ library. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla 6 | // Public License v. 2.0. If a copy of the MPL was not distributed 7 | // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | 17 | #include 18 | 19 | #include "catch.hpp" 20 | #include "test_utils.hpp" 21 | 22 | static const int ntries = 1000; 23 | 24 | // NOLINTNEXTLINE(google-build-using-namespace) 25 | using namespace mppp; 26 | // NOLINTNEXTLINE(google-build-using-namespace) 27 | using namespace mppp_test; 28 | 29 | using sizes = std::tuple, std::integral_constant, 30 | std::integral_constant, std::integral_constant, 31 | std::integral_constant>; 32 | 33 | // NOLINTNEXTLINE(cert-err58-cpp, cert-msc32-c, cert-msc51-cpp, cppcoreguidelines-avoid-non-const-global-variables) 34 | static std::mt19937 rng; 35 | 36 | struct hash_tester { 37 | template 38 | inline void operator()(const S &) const 39 | { 40 | using rational = rational; 41 | const std::hash hasher{}; 42 | rational n1; 43 | const auto orig_h = hash(n1); 44 | REQUIRE((hash(n1) == hash(n1.get_num()) + hash(n1.get_den()))); 45 | REQUIRE((hasher(n1) == hash(n1))); 46 | n1._get_num().promote(); 47 | REQUIRE((hash(n1) == orig_h)); 48 | REQUIRE((hasher(n1) == orig_h)); 49 | n1._get_den().promote(); 50 | REQUIRE((hash(n1) == orig_h)); 51 | REQUIRE((hasher(n1) == orig_h)); 52 | n1._get_num().demote(); 53 | REQUIRE((hash(n1) == orig_h)); 54 | REQUIRE((hasher(n1) == orig_h)); 55 | detail::mpq_raii tmp; 56 | detail::mpz_raii num, den; 57 | std::uniform_int_distribution sdist(0, 1); 58 | // Run a variety of tests with operands with x number of limbs. 59 | auto random_xy = [&](unsigned x) { 60 | for (int i = 0; i < ntries; ++i) { 61 | // NOLINTNEXTLINE(misc-redundant-expression) 62 | if (sdist(rng) && sdist(rng) && sdist(rng)) { 63 | // Reset rop every once in a while. 64 | n1 = rational{}; 65 | } 66 | random_integer(num, x, rng); 67 | random_integer(den, x, rng); 68 | mpz_set(mpq_numref(&tmp.m_mpq), &num.m_mpz); 69 | mpz_set(mpq_denref(&tmp.m_mpq), &den.m_mpz); 70 | if (mpz_sgn(mpq_denref(&tmp.m_mpq)) == 0) { 71 | mpz_set_ui(mpq_denref(&tmp.m_mpq), 1u); 72 | } 73 | mpq_canonicalize(&tmp.m_mpq); 74 | n1 = &tmp.m_mpq; 75 | REQUIRE((hash(n1) == hash(n1.get_num()) + hash(n1.get_den()))); 76 | REQUIRE((hasher(n1) == hash(n1))); 77 | } 78 | }; 79 | 80 | random_xy(0); 81 | random_xy(1); 82 | random_xy(2); 83 | random_xy(3); 84 | random_xy(4); 85 | } 86 | }; 87 | 88 | TEST_CASE("hash") 89 | { 90 | tuple_for_each(sizes{}, hash_tester{}); 91 | } 92 | -------------------------------------------------------------------------------- /test/rational_literals.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016-2023 Francesco Biscani (bluescarni@gmail.com) 2 | // 3 | // This file is part of the mp++ library. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla 6 | // Public License v. 2.0. If a copy of the MPL was not distributed 7 | // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | #include 10 | 11 | #include 12 | #include 13 | 14 | #include "catch.hpp" 15 | 16 | // NOLINTNEXTLINE(google-build-using-namespace) 17 | using namespace mppp; 18 | 19 | // Just a few simple tests, as the rational 20 | // literal is built on top of the integer 21 | // literal. 22 | TEST_CASE("rational_literals_tests") 23 | { 24 | REQUIRE(std::is_same, decltype(123_q1)>::value); 25 | REQUIRE(123_q1 == 123); 26 | REQUIRE(-456_q1 == -456); 27 | #if MPPP_CPLUSPLUS >= 201402L 28 | REQUIRE(-0b1_q1 == -1); 29 | #endif 30 | REQUIRE(07_q1 == 7); 31 | REQUIRE(-0xf_q1 == -15); 32 | REQUIRE(4_q1 / -6 == -rational<1>{2, 3}); 33 | 34 | REQUIRE(std::is_same, decltype(123_q2)>::value); 35 | REQUIRE(123_q2 == 123); 36 | REQUIRE(-456_q2 == -456); 37 | #if MPPP_CPLUSPLUS >= 201402L 38 | REQUIRE(-0b1_q2 == -1); 39 | #endif 40 | REQUIRE(07_q2 == 7); 41 | REQUIRE(-0xf_q2 == -15); 42 | REQUIRE(4_q2 / -6 == -rational<2>{2, 3}); 43 | 44 | REQUIRE(std::is_same, decltype(123_q3)>::value); 45 | REQUIRE(123_q3 == 123); 46 | REQUIRE(-456_q3 == -456); 47 | #if MPPP_CPLUSPLUS >= 201402L 48 | REQUIRE(-0b1_q3 == -1); 49 | #endif 50 | REQUIRE(07_q3 == 7); 51 | REQUIRE(-0xf_q3 == -15); 52 | REQUIRE(4_q3 / -6 == -rational<3>{2, 3}); 53 | } 54 | -------------------------------------------------------------------------------- /test/rational_neg.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016-2023 Francesco Biscani (bluescarni@gmail.com) 2 | // 3 | // This file is part of the mp++ library. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla 6 | // Public License v. 2.0. If a copy of the MPL was not distributed 7 | // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | 16 | #include 17 | 18 | #include "catch.hpp" 19 | #include "test_utils.hpp" 20 | 21 | static const int ntries = 1000; 22 | 23 | // NOLINTNEXTLINE(google-build-using-namespace) 24 | using namespace mppp; 25 | // NOLINTNEXTLINE(google-build-using-namespace) 26 | using namespace mppp_test; 27 | 28 | using sizes = std::tuple, std::integral_constant, 29 | std::integral_constant, std::integral_constant, 30 | std::integral_constant>; 31 | 32 | // NOLINTNEXTLINE(cert-err58-cpp, cert-msc32-c, cert-msc51-cpp, cppcoreguidelines-avoid-non-const-global-variables) 33 | static std::mt19937 rng; 34 | 35 | struct neg_tester { 36 | template 37 | inline void operator()(const S &) const 38 | { 39 | using rational = rational; 40 | // Start with all zeroes. 41 | detail::mpq_raii m1, m2; 42 | rational n1, n2; 43 | mpq_neg(&m1.m_mpq, &m2.m_mpq); 44 | REQUIRE(&neg(n1, n2) == &n1); 45 | REQUIRE((lex_cast(n1) == lex_cast(m1))); 46 | // Test the other variants. 47 | n1.neg(); 48 | REQUIRE((lex_cast(n1) == lex_cast(m1))); 49 | REQUIRE((lex_cast(neg(n1)) == lex_cast(m1))); 50 | detail::mpq_raii tmp; 51 | std::uniform_int_distribution sdist(0, 1); 52 | // Run a variety of tests with operands with x number of limbs. 53 | auto random_xy = [&](unsigned x) { 54 | for (int i = 0; i < ntries; ++i) { 55 | // NOLINTNEXTLINE(misc-redundant-expression) 56 | if (sdist(rng) && sdist(rng) && sdist(rng)) { 57 | // Reset rop every once in a while. 58 | n1 = rational{}; 59 | } 60 | random_rational(tmp, x, rng); 61 | mpq_set(&m2.m_mpq, &tmp.m_mpq); 62 | n2 = rational(&tmp.m_mpq); 63 | if (sdist(rng)) { 64 | mpq_neg(&m2.m_mpq, &m2.m_mpq); 65 | n2.neg(); 66 | } 67 | if (n2.get_num().is_static() && sdist(rng)) { 68 | // Promote sometimes, if possible. 69 | n2._get_num().promote(); 70 | } 71 | if (n2.get_den().is_static() && sdist(rng)) { 72 | // Promote sometimes, if possible. 73 | n2._get_den().promote(); 74 | } 75 | mpq_neg(&m1.m_mpq, &m2.m_mpq); 76 | neg(n1, n2); 77 | REQUIRE((lex_cast(n1) == lex_cast(m1))); 78 | REQUIRE((lex_cast(n1) == lex_cast(neg(n2)))); 79 | n2.neg(); 80 | REQUIRE((lex_cast(n1) == lex_cast(n2))); 81 | } 82 | }; 83 | 84 | random_xy(0); 85 | random_xy(1); 86 | random_xy(2); 87 | random_xy(3); 88 | random_xy(4); 89 | } 90 | }; 91 | 92 | TEST_CASE("neg") 93 | { 94 | tuple_for_each(sizes{}, neg_tester{}); 95 | } 96 | -------------------------------------------------------------------------------- /test/real128_bessel.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016-2023 Francesco Biscani (bluescarni@gmail.com) 2 | // 3 | // This file is part of the mp++ library. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla 6 | // Public License v. 2.0. If a copy of the MPL was not distributed 7 | // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | #include 10 | 11 | #include "catch.hpp" 12 | 13 | // NOLINTNEXTLINE(google-build-using-namespace) 14 | using namespace mppp; 15 | 16 | TEST_CASE("real128 j0") 17 | { 18 | REQUIRE(j0(real128{}) == 1); 19 | real128 x; 20 | REQUIRE(x.j0() == 1); 21 | REQUIRE(abs(j0(real128{1}) - 0.765197686557966551449717526102663221_rq) < 1E-34); 22 | } 23 | 24 | TEST_CASE("real128 j1") 25 | { 26 | REQUIRE(j1(real128{}) == 0); 27 | real128 x; 28 | REQUIRE(x.j1() == 0); 29 | REQUIRE(abs(j1(real128{1}) - 0.440050585744933515959682203718914913_rq) < 1E-34); 30 | } 31 | 32 | TEST_CASE("real128 jn") 33 | { 34 | REQUIRE(abs(jn(7, real128{1}) - 0.00000150232581743680821221863346804840184_rq) < 1E-34); 35 | } 36 | 37 | TEST_CASE("real128 y0") 38 | { 39 | REQUIRE(y0(real128{}) == real128{"-inf"}); 40 | real128 x; 41 | REQUIRE(x.y0() == real128{"-inf"}); 42 | REQUIRE(abs(y0(real128{1}) - 0.0882569642156769579829267660235151621_rq) < 1E-34); 43 | } 44 | 45 | TEST_CASE("real128 y1") 46 | { 47 | REQUIRE(y1(real128{}) == real128{"-inf"}); 48 | real128 x; 49 | REQUIRE(x.y1() == real128{"-inf"}); 50 | REQUIRE(abs(y1(real128{1}) - -0.78121282130028871654715000004796479_rq) < 1E-34); 51 | } 52 | 53 | TEST_CASE("real128 yn") 54 | { 55 | REQUIRE(abs(yn(7, real128{1}) - -30588.9570521239888408800675925647278_rq) < 1E-34); 56 | } 57 | -------------------------------------------------------------------------------- /test/real128_constants.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016-2023 Francesco Biscani (bluescarni@gmail.com) 2 | // 3 | // This file is part of the mp++ library. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla 6 | // Public License v. 2.0. If a copy of the MPL was not distributed 7 | // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | #include 10 | 11 | #include 12 | 13 | #include "catch.hpp" 14 | 15 | // NOLINTNEXTLINE(google-build-using-namespace) 16 | using namespace mppp; 17 | 18 | TEST_CASE("real128 constants") 19 | { 20 | constexpr auto sig_digits = real128_sig_digits(); 21 | REQUIRE(sig_digits == 113u); 22 | REQUIRE(real128_sig_digits() == 113u); 23 | constexpr auto pi = real128_pi(); 24 | REQUIRE((pi.m_value == real128{"3.14159265358979323846264338327950280"}.m_value)); 25 | constexpr auto e = real128_e(); 26 | REQUIRE((e.m_value == real128{"2.71828182845904523536028747135266231e+00"}.m_value)); 27 | constexpr auto sqrt2 = real128_sqrt2(); 28 | REQUIRE((sqrt2.m_value == real128{"1.41421356237309504880168872420969798"}.m_value)); 29 | constexpr auto inf = real128_inf(); 30 | REQUIRE((inf.m_value == real128{"inf"}.m_value)); 31 | constexpr auto minf = -real128_inf(); 32 | REQUIRE((minf.m_value == real128{"-inf"}.m_value)); 33 | constexpr auto nan = real128_nan(); 34 | REQUIRE(nan.isnan()); 35 | constexpr auto mnan = -real128_nan(); 36 | REQUIRE(mnan.isnan()); 37 | constexpr auto max = real128_max(); 38 | REQUIRE(max == real128{"1.18973149535723176508575932662800702e+4932"}); 39 | REQUIRE(get<0>(max.get_ieee()) == 0u); 40 | REQUIRE(get<1>(max.get_ieee()) == 32766ul); 41 | REQUIRE(get<2>(max.get_ieee()) == 281474976710655ull); 42 | REQUIRE(get<3>(max.get_ieee()) == 18446744073709551615ull); 43 | constexpr auto min = real128_min(); 44 | REQUIRE(min == real128{"3.36210314311209350626267781732175260e-4932"}); 45 | REQUIRE(get<0>(min.get_ieee()) == 0u); 46 | REQUIRE(get<1>(min.get_ieee()) == 1u); 47 | REQUIRE(get<2>(min.get_ieee()) == 0u); 48 | REQUIRE(get<3>(min.get_ieee()) == 0u); 49 | constexpr auto eps = real128_epsilon(); 50 | REQUIRE(eps == real128{"1.92592994438723585305597794258492732e-34"}); 51 | REQUIRE(get<0>(eps.get_ieee()) == 0u); 52 | REQUIRE(get<1>(eps.get_ieee()) == 16271u); 53 | REQUIRE(get<2>(eps.get_ieee()) == 0u); 54 | REQUIRE(get<3>(eps.get_ieee()) == 0u); 55 | constexpr auto dmin = real128_denorm_min(); 56 | REQUIRE(dmin == real128{"6.47517511943802511092443895822764655e-4966"}); 57 | REQUIRE(get<0>(dmin.get_ieee()) == 0u); 58 | REQUIRE(get<1>(dmin.get_ieee()) == 0u); 59 | REQUIRE(get<2>(dmin.get_ieee()) == 0u); 60 | REQUIRE(get<3>(dmin.get_ieee()) == 1u); 61 | #if MPPP_CPLUSPLUS >= 201703L 62 | REQUIRE(sig_digits_128 == 113u); 63 | REQUIRE((pi_128.m_value == real128_pi().m_value)); 64 | REQUIRE((e_128.m_value == real128_e().m_value)); 65 | REQUIRE((sqrt2_128.m_value == real128_sqrt2().m_value)); 66 | REQUIRE((inf_128.m_value == real128_inf().m_value)); 67 | REQUIRE(nan_128.isnan()); 68 | REQUIRE((max_128.m_value == real128_max().m_value)); 69 | REQUIRE((min_128.m_value == real128_min().m_value)); 70 | REQUIRE((epsilon_128.m_value == real128_epsilon().m_value)); 71 | REQUIRE((denorm_min_128.m_value == real128_denorm_min().m_value)); 72 | #endif 73 | } 74 | -------------------------------------------------------------------------------- /test/real128_fdim.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016-2023 Francesco Biscani (bluescarni@gmail.com) 2 | // 3 | // This file is part of the mp++ library. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla 6 | // Public License v. 2.0. If a copy of the MPL was not distributed 7 | // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #include "catch.hpp" 14 | 15 | // NOLINTNEXTLINE(google-build-using-namespace) 16 | using namespace mppp; 17 | 18 | TEST_CASE("real128 fdim") 19 | { 20 | REQUIRE(fdim(-1_rq, -1_rq) == 0); 21 | REQUIRE(fdim(1_rq, -1_rq) == 2); 22 | REQUIRE(fdim(-1_rq, 1_rq) == 0); 23 | REQUIRE(fdim(1_rq, 1_rq) == 0); 24 | 25 | // Couple of small tests with non-real128 args. 26 | REQUIRE(fdim(-1_rq, -1) == 0); 27 | REQUIRE(fdim(1., -1_rq) == 2); 28 | REQUIRE(fdim(-1_rq, 1_z1) == 0); 29 | REQUIRE(fdim(1_q1, 1_rq) == 0); 30 | } 31 | -------------------------------------------------------------------------------- /test/real128_fmax_fmin.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016-2023 Francesco Biscani (bluescarni@gmail.com) 2 | // 3 | // This file is part of the mp++ library. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla 6 | // Public License v. 2.0. If a copy of the MPL was not distributed 7 | // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #include "catch.hpp" 14 | 15 | // NOLINTNEXTLINE(google-build-using-namespace) 16 | using namespace mppp; 17 | 18 | TEST_CASE("real128 fmax") 19 | { 20 | REQUIRE(fmax(-1_rq, -1_rq) == -1); 21 | REQUIRE(fmax(1_rq, -1_rq) == 1); 22 | REQUIRE(fmax(-1_rq, 1_rq) == 1); 23 | REQUIRE(fmax(1_rq, 1_rq) == 1); 24 | 25 | // Couple of small tests with non-real128 args. 26 | REQUIRE(fmax(-1_rq, -1) == -1); 27 | REQUIRE(fmax(1., -1_rq) == 1); 28 | REQUIRE(fmax(-1_rq, 1_z1) == 1); 29 | REQUIRE(fmax(1_q1, 1_rq) == 1); 30 | } 31 | 32 | TEST_CASE("real128 fmin") 33 | { 34 | REQUIRE(fmin(-1_rq, -1_rq) == -1); 35 | REQUIRE(fmin(1_rq, -1_rq) == -1); 36 | REQUIRE(fmin(-1_rq, 1_rq) == -1); 37 | REQUIRE(fmin(1_rq, 1_rq) == 1); 38 | 39 | // Couple of small tests with non-real128 args. 40 | REQUIRE(fmin(-1_rq, -1) == -1); 41 | REQUIRE(fmin(1., -1_rq) == -1); 42 | REQUIRE(fmin(-1_rq, 1_z1) == -1); 43 | REQUIRE(fmin(1_q1, 1_rq) == 1); 44 | } 45 | -------------------------------------------------------------------------------- /test/real128_fpmanip.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016-2023 Francesco Biscani (bluescarni@gmail.com) 2 | // 3 | // This file is part of the mp++ library. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla 6 | // Public License v. 2.0. If a copy of the MPL was not distributed 7 | // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #include "catch.hpp" 14 | 15 | // NOLINTNEXTLINE(google-build-using-namespace) 16 | using namespace mppp; 17 | 18 | TEST_CASE("real128 nextafter") 19 | { 20 | REQUIRE(nextafter(real128{0}, real128{1}) > 0); 21 | REQUIRE(nextafter(real128{0}, real128{-1}) < 0); 22 | REQUIRE(nextafter(real128{0}, real128{0}) == 0); 23 | REQUIRE(nextafter(real128{1}, real128{1}) == 1); 24 | REQUIRE(nextafter(real128{-1}, real128{-1}) == -1); 25 | REQUIRE(isinf(nextafter(real128{"inf"}, real128{"inf"}))); 26 | REQUIRE(isinf(nextafter(real128{"-inf"}, real128{"-inf"}))); 27 | REQUIRE(!isinf(nextafter(real128{"-inf"}, real128{1}))); 28 | } 29 | 30 | TEST_CASE("real128 copysign") 31 | { 32 | REQUIRE(copysign(-1_rq, -1_rq) == -1); 33 | REQUIRE(copysign(1_rq, -1_rq) == -1); 34 | REQUIRE(copysign(-1_rq, 1_rq) == 1); 35 | REQUIRE(copysign(1_rq, 1_rq) == 1); 36 | 37 | // Couple of small tests with non-real128 args. 38 | REQUIRE(copysign(-1_rq, -1) == -1); 39 | REQUIRE(copysign(1., -1_rq) == -1); 40 | REQUIRE(copysign(-1_rq, 1_z1) == 1); 41 | REQUIRE(copysign(1_q1, 1_rq) == 1); 42 | } 43 | -------------------------------------------------------------------------------- /test/real128_hash.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016-2023 Francesco Biscani (bluescarni@gmail.com) 2 | // 3 | // This file is part of the mp++ library. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla 6 | // Public License v. 2.0. If a copy of the MPL was not distributed 7 | // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | #include "catch.hpp" 15 | 16 | // NOLINTNEXTLINE(google-build-using-namespace) 17 | using namespace mppp; 18 | 19 | TEST_CASE("real128 hash") 20 | { 21 | REQUIRE(hash(real128{0}) == 0u); 22 | REQUIRE(hash(real128{0.}) == hash(real128{-0.})); 23 | REQUIRE(hash(real128{42}) != 0u); 24 | REQUIRE(hash(real128{42}) != std::size_t(-1)); 25 | REQUIRE(hash(real128{-42}) != 0u); 26 | REQUIRE(hash(real128{-42}) == std::hash{}(real128{-42})); 27 | REQUIRE(hash(real128{-42}) != std::size_t(-1)); 28 | REQUIRE(hash(real128{"inf"}) != 0u); 29 | REQUIRE(hash(real128{"inf"}) != std::size_t(-1)); 30 | REQUIRE(hash(real128{"-inf"}) != 0u); 31 | REQUIRE(hash(real128{"-inf"}) != std::size_t(-1)); 32 | REQUIRE(hash(real128{"inf"}) != hash(real128{"-inf"})); 33 | REQUIRE(hash(real128_min()) != 0u); 34 | REQUIRE(hash(real128_min()) != std::size_t(-1)); 35 | REQUIRE(hash(-real128_min()) != 0u); 36 | REQUIRE(hash(-real128_min()) != std::size_t(-1)); 37 | REQUIRE(hash(real128_max()) != 0u); 38 | REQUIRE(hash(real128_max()) != std::size_t(-1)); 39 | REQUIRE(hash(-real128_max()) != 0u); 40 | REQUIRE(hash(-real128_max()) != std::size_t(-1)); 41 | } 42 | -------------------------------------------------------------------------------- /test/real128_hyperbolic.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016-2023 Francesco Biscani (bluescarni@gmail.com) 2 | // 3 | // This file is part of the mp++ library. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla 6 | // Public License v. 2.0. If a copy of the MPL was not distributed 7 | // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | #include 10 | 11 | #include "catch.hpp" 12 | 13 | // NOLINTNEXTLINE(google-build-using-namespace) 14 | using namespace mppp; 15 | 16 | TEST_CASE("real128 sinhcosh") 17 | { 18 | REQUIRE(cosh(real128{}) == 1); 19 | REQUIRE(sinh(real128{}) == 0); 20 | real128 x; 21 | REQUIRE(x.cosh() == 1); 22 | REQUIRE(x.sinh() != 0); 23 | x = 0; 24 | REQUIRE(x.sinh() == 0); 25 | REQUIRE(abs(sinh(real128{"1.234"}) - real128{"1.571908059102337379176699145503416648"}) < 1E-33); 26 | REQUIRE(abs(cosh(real128{"1.234"}) - real128{"1.863033801698422589073643750256062085"}) < 1E-33); 27 | } 28 | 29 | TEST_CASE("real128 tanh") 30 | { 31 | REQUIRE(tanh(real128{}) == 0); 32 | real128 x; 33 | REQUIRE(x.tanh() == 0); 34 | x = 0; 35 | REQUIRE(x.tanh() == 0); 36 | REQUIRE(abs(tanh(real128{"1.234"}) - real128{"0.84373566258933019391702000004355143214"}) < 1E-33); 37 | } 38 | 39 | TEST_CASE("real128 inversefunctions") 40 | { 41 | { 42 | REQUIRE(acosh(real128{1}) == 0.); 43 | real128 x{1}; 44 | REQUIRE(x.acosh() == 0.); 45 | x = 1; 46 | REQUIRE(x.acosh() == 0.); 47 | REQUIRE(abs(acos(cos(real128{"1.234"})) - real128{"1.234"}) < 1E-33); 48 | } 49 | { 50 | REQUIRE(asinh(real128{}) == 0.); 51 | real128 x; 52 | REQUIRE(x.asinh() == 0.); 53 | x = 0; 54 | REQUIRE(x.asinh() == 0.); 55 | REQUIRE(abs(asinh(sinh(real128{"0.234"})) - real128{"0.234"}) < 1E-33); 56 | } 57 | { 58 | REQUIRE(atanh(real128{}) == 0.); 59 | real128 x; 60 | REQUIRE(x.atanh() == 0.); 61 | x = 0; 62 | REQUIRE(x.atanh() == 0.); 63 | REQUIRE(abs(atanh(tanh(real128{"0.234"})) - real128{"0.234"}) < 1E-33); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /test/real128_ieee.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016-2023 Francesco Biscani (bluescarni@gmail.com) 2 | // 3 | // This file is part of the mp++ library. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla 6 | // Public License v. 2.0. If a copy of the MPL was not distributed 7 | // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | #include "catch.hpp" 17 | 18 | // NOLINTNEXTLINE(google-build-using-namespace) 19 | using namespace mppp; 20 | 21 | using int_t = integer<1>; 22 | 23 | TEST_CASE("real128 get_ieee()") 24 | { 25 | // NOTE: not sure why, but we get 26 | // a compiler error with ICC in C++17 27 | // on these tuple operations below. 28 | #if !defined(__INTEL_COMPILER) || MPPP_CPLUSPLUS < 201703L 29 | std::uint_least8_t sign{}; 30 | std::uint_least16_t exp{}; 31 | std::uint_least64_t hi{}; 32 | std::uint_least64_t lo{}; 33 | std::tie(sign, exp, hi, lo) = real128{}.get_ieee(); 34 | REQUIRE(!sign); 35 | REQUIRE(!exp); 36 | REQUIRE(!hi); 37 | REQUIRE(!lo); 38 | std::tie(sign, exp, hi, lo) = real128{-0.}.get_ieee(); 39 | REQUIRE(sign); 40 | REQUIRE(!exp); 41 | REQUIRE(!hi); 42 | REQUIRE(!lo); 43 | std::tie(sign, exp, hi, lo) = real128{42}.get_ieee(); 44 | REQUIRE(!sign); 45 | REQUIRE(exp == 16388ul); 46 | REQUIRE(hi == 10ull << (48 - 5)); 47 | REQUIRE(!lo); 48 | std::tie(sign, exp, hi, lo) = real128{-42}.get_ieee(); 49 | REQUIRE(sign); 50 | REQUIRE(exp == 16388ul); 51 | REQUIRE(hi == 10ull << (48 - 5)); 52 | REQUIRE(!lo); 53 | std::tie(sign, exp, hi, lo) = real128_nan().get_ieee(); 54 | REQUIRE(exp == 32767ul); 55 | REQUIRE((hi || lo)); 56 | std::tie(sign, exp, hi, lo) = real128_inf().get_ieee(); 57 | REQUIRE(!sign); 58 | REQUIRE(exp == 32767ul); 59 | REQUIRE((!hi && !lo)); 60 | std::tie(sign, exp, hi, lo) = (-real128_inf()).get_ieee(); 61 | REQUIRE(sign); 62 | REQUIRE(exp == 32767ul); 63 | REQUIRE((!hi && !lo)); 64 | std::tie(sign, exp, hi, lo) = real128{"1.189731495357231765085759326628007e4932"}.get_ieee(); 65 | REQUIRE(!sign); 66 | REQUIRE(exp == 32766ul); 67 | REQUIRE(hi == std::uint_least64_t(-1) % (1ull << 48)); 68 | REQUIRE(lo == std::uint_least64_t(-1) % (int_t(1) << 64)); 69 | std::tie(sign, exp, hi, lo) = real128{"-1.189731495357231765085759326628007e4932"}.get_ieee(); 70 | REQUIRE(sign); 71 | REQUIRE(exp == 32766ul); 72 | REQUIRE(hi == std::uint_least64_t(-1) % (1ull << 48)); 73 | REQUIRE(lo == std::uint_least64_t(-1) % (int_t(1) << 64)); 74 | std::tie(sign, exp, hi, lo) = real128{"6.47517511943802511092443895822764655e-4966"}.get_ieee(); 75 | REQUIRE(!sign); 76 | REQUIRE(!exp); 77 | REQUIRE(!hi); 78 | REQUIRE(lo == 1u); 79 | std::tie(sign, exp, hi, lo) = real128{"-6.47517511943802511092443895822764655e-4966"}.get_ieee(); 80 | REQUIRE(sign); 81 | REQUIRE(!exp); 82 | REQUIRE(!hi); 83 | REQUIRE(lo == 1u); 84 | #endif 85 | } 86 | -------------------------------------------------------------------------------- /test/real128_literal.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016-2023 Francesco Biscani (bluescarni@gmail.com) 2 | // 3 | // This file is part of the mp++ library. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla 6 | // Public License v. 2.0. If a copy of the MPL was not distributed 7 | // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | #include 15 | 16 | #include "catch.hpp" 17 | #include "test_utils.hpp" 18 | 19 | // NOLINTNEXTLINE(google-build-using-namespace) 20 | using namespace mppp; 21 | 22 | TEST_CASE("real128_literal_tests") 23 | { 24 | REQUIRE(std::is_same::value); 25 | REQUIRE(123_rq == 123); 26 | REQUIRE(-123._rq == -123); 27 | REQUIRE(-.1_rq == -real128{"0.1"}); 28 | REQUIRE(-0.1_rq == -real128{"0.1"}); 29 | REQUIRE(0._rq == -real128{}); 30 | REQUIRE(0_rq == -real128{}); 31 | REQUIRE(-.123e-7_rq == -real128{".123e-7"}); 32 | #if MPPP_CPLUSPLUS >= 201703L 33 | // Hex literals are supported as well. 34 | REQUIRE(0x123.p-7_rq == real128{"0x123.p-7"}); 35 | REQUIRE(-0X123.p-7_rq == -real128{"0x123.p-7"}); 36 | REQUIRE(0x123.P-7_rq == real128{"0x123.p-7"}); 37 | REQUIRE(-0X123.P-7_rq == -real128{"0x123.p-7"}); 38 | REQUIRE(-0X0.123P-7_rq == -real128{"0x0.123p-7"}); 39 | #endif 40 | 41 | // Runtime failures. 42 | real128 r; 43 | #if MPPP_CPLUSPLUS >= 201402L 44 | REQUIRE_THROWS_PREDICATE(r = 0b010010_rq, std::invalid_argument, [](const std::invalid_argument &ia) { 45 | return ia.what() == std::string("A real128 cannot be constructed from binary or octal literals"); 46 | }); 47 | REQUIRE_THROWS_PREDICATE(r = 0B010010_rq, std::invalid_argument, [](const std::invalid_argument &ia) { 48 | return ia.what() == std::string("A real128 cannot be constructed from binary or octal literals"); 49 | }); 50 | #endif 51 | REQUIRE_THROWS_PREDICATE(r = 04552627_rq, std::invalid_argument, [](const std::invalid_argument &ia) { 52 | return ia.what() == std::string("A real128 cannot be constructed from binary or octal literals"); 53 | }); 54 | } 55 | -------------------------------------------------------------------------------- /test/real128_logexp.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016-2023 Francesco Biscani (bluescarni@gmail.com) 2 | // 3 | // This file is part of the mp++ library. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla 6 | // Public License v. 2.0. If a copy of the MPL was not distributed 7 | // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | #include 10 | #include 11 | 12 | #include "catch.hpp" 13 | 14 | // NOLINTNEXTLINE(google-build-using-namespace) 15 | using namespace mppp; 16 | 17 | TEST_CASE("real128 logexp") 18 | { 19 | REQUIRE(exp(real128{}) == 1); 20 | REQUIRE(abs(exp(real128{1}) - real128_e()) < 1E-32); 21 | REQUIRE(abs(exp(real128{-1}) - 1 / real128_e()) < 1E-32); 22 | REQUIRE(abs(exp(real128{2}) - real128_e() * real128_e()) < 1e-32); 23 | real128 x{2}; 24 | x.exp(); 25 | REQUIRE(x == exp(real128{2})); 26 | 27 | REQUIRE(log(real128{}) == -real128_inf()); 28 | REQUIRE(log(real128{1}) == 0); 29 | REQUIRE(log(real128{-1}).isnan()); 30 | REQUIRE(abs(log(real128{2}) - real128{"0.693147180559945309417232121458176575"}) < 1e-32); 31 | x = 2; 32 | x.log(); 33 | REQUIRE(x == log(real128{2})); 34 | 35 | REQUIRE(log10(real128{}) == -real128_inf()); 36 | REQUIRE(log10(real128{1}) == 0); 37 | REQUIRE(log10(real128{-1}).isnan()); 38 | REQUIRE(abs(log10(real128{2}) - real128{"0.30102999566398119521373889472449302"}) < 1e-32); 39 | x = 2; 40 | x.log10(); 41 | REQUIRE(x == log10(real128{2})); 42 | 43 | REQUIRE(log2(real128{}) == -real128_inf()); 44 | REQUIRE(log2(real128{1}) == 0); 45 | REQUIRE(log2(real128{-1}).isnan()); 46 | REQUIRE(abs(log2(real128{2}) - real128{1}) < 1e-32); 47 | x = 2; 48 | x.log2(); 49 | REQUIRE(x == log2(real128{2})); 50 | 51 | #if defined(MPPP_QUADMATH_HAVE_EXP2Q) 52 | // exp2. 53 | REQUIRE(exp2(real128{}) == 1); 54 | REQUIRE(abs(exp2(real128{1}) - 2) < 1E-32); 55 | REQUIRE(abs(exp2(real128{-1}) - 1_rq / 2) < 1E-32); 56 | REQUIRE(abs(exp2(real128{2}) - 2 * 2) < 1e-32); 57 | x = 2; 58 | x.exp2(); 59 | REQUIRE(x == exp2(real128{2})); 60 | #endif 61 | 62 | // expm1. 63 | REQUIRE(expm1(real128{}) == 0); 64 | REQUIRE(abs(expm1(real128{1}) - real128_e() + 1) < 1E-32); 65 | REQUIRE(abs(expm1(real128{-1}) + 1 - 1 / real128_e()) < 1E-32); 66 | REQUIRE(abs(expm1(real128{2}) + 1 - (real128_e() * real128_e())) < 1e-32); 67 | x = 2; 68 | x.expm1(); 69 | REQUIRE(x == expm1(real128{2})); 70 | 71 | // log1p. 72 | REQUIRE(log1p(real128{}) == 0); 73 | REQUIRE(log1p(real128{1}) == log(2_rq)); 74 | REQUIRE(log1p(real128{-2}).isnan()); 75 | REQUIRE(abs(log1p(real128{2}) - 1.09861228866810969139524523692252561_rq) < 1e-32); 76 | x = 2; 77 | x.log1p(); 78 | REQUIRE(x == log1p(real128{2})); 79 | } 80 | -------------------------------------------------------------------------------- /test/real128_miscfunctions.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016-2023 Francesco Biscani (bluescarni@gmail.com) 2 | // 3 | // This file is part of the mp++ library. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla 6 | // Public License v. 2.0. If a copy of the MPL was not distributed 7 | // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | #include 10 | 11 | #include "catch.hpp" 12 | 13 | // NOLINTNEXTLINE(google-build-using-namespace) 14 | using namespace mppp; 15 | 16 | TEST_CASE("real128 erf") 17 | { 18 | REQUIRE(erf(real128{}) == 0); 19 | real128 x; 20 | REQUIRE(x.erf() == 0); 21 | REQUIRE(abs(erf(real128{"1.234"}) - real128{"0.9190394169576684157198123662625681813"}) < 1E-34); 22 | } 23 | 24 | TEST_CASE("real128 erfc") 25 | { 26 | REQUIRE(erfc(real128{}) == 1); 27 | real128 x; 28 | REQUIRE(x.erfc() == 1); 29 | REQUIRE(abs(erfc(real128{4}) - 0.0000000154172579002800188521596734868840499_rq) < 1E-34); 30 | } 31 | 32 | TEST_CASE("real128 lgamma") 33 | { 34 | REQUIRE(lgamma(real128{1}) == 0); 35 | real128 x(1); 36 | REQUIRE(x.lgamma() == 0); 37 | REQUIRE(abs(lgamma(real128{"1.234"}) - real128{"-0.094478407681159572584826666218660204"}) < 1E-34); 38 | } 39 | 40 | TEST_CASE("real128 tgamma") 41 | { 42 | REQUIRE(tgamma(real128{1}) == 1); 43 | real128 x(1); 44 | REQUIRE(x.tgamma() == 1); 45 | REQUIRE(abs(tgamma(real128{"1.234"}) - real128{"0.909847380128661106639623421763461722"}) < 1E-34); 46 | } 47 | -------------------------------------------------------------------------------- /test/real128_pow.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016-2023 Francesco Biscani (bluescarni@gmail.com) 2 | // 3 | // This file is part of the mp++ library. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla 6 | // Public License v. 2.0. If a copy of the MPL was not distributed 7 | // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | #if defined(__clang__) || defined(__GNUC__) 10 | 11 | #pragma GCC diagnostic ignored "-Wconversion" 12 | 13 | #endif 14 | 15 | #include 16 | #include 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #include "catch.hpp" 25 | 26 | // NOLINTNEXTLINE(google-build-using-namespace) 27 | using namespace mppp; 28 | 29 | using int_t = integer<1>; 30 | using rat_t = rational<1>; 31 | 32 | template 33 | using pow_t = decltype(mppp::pow(std::declval(), std::declval())); 34 | 35 | TEST_CASE("real128 pow") 36 | { 37 | REQUIRE((std::is_same::value)); 38 | REQUIRE((std::is_same::value)); 39 | REQUIRE((std::is_same::value)); 40 | REQUIRE((std::is_same::value)); 41 | REQUIRE((std::is_same::value)); 42 | REQUIRE((pow(real128{}, real128{}).m_value == 1.)); 43 | REQUIRE((pow(real128{2}, real128{3}).m_value == 8.)); 44 | REQUIRE((pow(real128{2}, real128{-3}).m_value == real128{".125"}.m_value)); 45 | REQUIRE((pow(real128{}, 0).m_value == 1.)); 46 | REQUIRE((pow(0.f, real128{}).m_value == 1.)); 47 | REQUIRE((pow(real128{2}, 3ll).m_value == 8.)); 48 | REQUIRE((pow(2u, real128{3}).m_value == 8.)); 49 | REQUIRE((pow(real128{2}, static_cast(-3)).m_value == real128{".125"}.m_value)); 50 | REQUIRE((pow(2., real128{-3}).m_value == real128{".125"}.m_value)); 51 | REQUIRE((pow(real128{}, int_t{}).m_value == 1.)); 52 | REQUIRE((pow(int_t{}, real128{}).m_value == 1.)); 53 | REQUIRE((pow(real128{2}, int_t{3}).m_value == 8.)); 54 | REQUIRE((pow(int_t{2}, real128{3}).m_value == 8.)); 55 | REQUIRE((pow(real128{2}, int_t{-3}).m_value == real128{".125"}.m_value)); 56 | REQUIRE((pow(int_t{2}, real128{-3}).m_value == real128{".125"}.m_value)); 57 | REQUIRE((pow(real128{}, rat_t{}).m_value == 1.)); 58 | REQUIRE((pow(rat_t{}, real128{}).m_value == 1.)); 59 | REQUIRE((pow(real128{2}, rat_t{3}).m_value == 8.)); 60 | REQUIRE((pow(rat_t{2}, real128{3}).m_value == 8.)); 61 | REQUIRE((pow(real128{2}, rat_t{-3}).m_value == real128{".125"}.m_value)); 62 | REQUIRE((pow(rat_t{2}, real128{-3}).m_value == real128{".125"}.m_value)); 63 | REQUIRE((abs(pow(real128{2}, rat_t{1, 2}) - real128_sqrt2()).m_value < 1E-30)); 64 | REQUIRE((pow(rat_t{1, 2}, real128{2}).m_value == real128{".25"}.m_value)); 65 | #if defined(MPPP_HAVE_GCC_INT128) 66 | REQUIRE(pow(real128{5}, __int128_t{2}) == 25); 67 | REQUIRE(pow(__int128_t{2}, real128{5}) == 32); 68 | REQUIRE(pow(real128{5}, __uint128_t{2}) == 25); 69 | REQUIRE(pow(__uint128_t{2}, real128{5}) == 32); 70 | #endif 71 | #if defined(MPPP_FLOAT128_WITH_LONG_DOUBLE) 72 | REQUIRE(abs(pow(real128{5}, 3.5l) - 279.508497187473712051146708591409519_rq) < 1E-30); 73 | REQUIRE(abs(pow(3.5l, real128{5}) - 525.21875_rq) < 1E-30); 74 | #else 75 | REQUIRE(!detail::is_detected::value); 76 | REQUIRE(!detail::is_detected::value); 77 | #endif 78 | } 79 | -------------------------------------------------------------------------------- /test/real128_signbit.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016-2023 Francesco Biscani (bluescarni@gmail.com) 2 | // 3 | // This file is part of the mp++ library. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla 6 | // Public License v. 2.0. If a copy of the MPL was not distributed 7 | // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | #include 10 | 11 | #include 12 | 13 | #include "catch.hpp" 14 | 15 | // NOLINTNEXTLINE(google-build-using-namespace) 16 | using namespace mppp; 17 | 18 | TEST_CASE("real128 signbit") 19 | { 20 | real128 r; 21 | REQUIRE(!r.signbit()); 22 | REQUIRE(!signbit(r)); 23 | r = -0.; 24 | REQUIRE(r.signbit()); 25 | REQUIRE(signbit(r)); 26 | r = -1; 27 | REQUIRE(r.signbit()); 28 | REQUIRE(signbit(r)); 29 | r = 1; 30 | REQUIRE(!r.signbit()); 31 | REQUIRE(!signbit(r)); 32 | r = "inf"; 33 | REQUIRE(!r.signbit()); 34 | REQUIRE(!signbit(r)); 35 | r = "-inf"; 36 | REQUIRE(r.signbit()); 37 | REQUIRE(signbit(r)); 38 | r = "nan"; 39 | REQUIRE(!r.signbit()); 40 | REQUIRE(!signbit(r)); 41 | r = ::copysignq(r.m_value, __float128(-1)); 42 | REQUIRE(r.signbit()); 43 | REQUIRE(signbit(r)); 44 | } 45 | -------------------------------------------------------------------------------- /test/real_get_set_z_2exp.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016-2023 Francesco Biscani (bluescarni@gmail.com) 2 | // 3 | // This file is part of the mp++ library. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla 6 | // Public License v. 2.0. If a copy of the MPL was not distributed 7 | // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | #include 10 | 11 | #include 12 | 13 | #include "catch.hpp" 14 | #include "test_utils.hpp" 15 | 16 | // NOLINTNEXTLINE(google-build-using-namespace) 17 | using namespace mppp; 18 | // NOLINTNEXTLINE(google-build-using-namespace) 19 | using namespace mppp_test; 20 | 21 | using int_t = integer<1>; 22 | 23 | TEST_CASE("real set_z_2exp") 24 | { 25 | real r0{45}; 26 | set_z_2exp(r0, int_t{2}, 4); 27 | REQUIRE(r0 == 32); 28 | REQUIRE(r0.get_prec() == detail::real_deduce_precision(45)); 29 | set_z_2exp(r0, int_t{-1}, -1); 30 | REQUIRE(r0 == real{"-.5", 7}); 31 | REQUIRE(r0.get_prec() == detail::real_deduce_precision(45)); 32 | set_z_2exp(r0, int_t{0}, -1); 33 | REQUIRE(r0 == real{}); 34 | REQUIRE(r0.get_prec() == detail::real_deduce_precision(45)); 35 | REQUIRE(!r0.signbit()); 36 | } 37 | 38 | TEST_CASE("real get_z_2exp") 39 | { 40 | real r0{45}; 41 | set_z_2exp(r0, int_t{2}, 4); 42 | int_t n; 43 | auto exp = get_z_2exp(n, r0); 44 | REQUIRE(real{n} * pow(2, real{exp}) == r0); 45 | set_z_2exp(r0, int_t{-2}, -4); 46 | exp = get_z_2exp(n, r0); 47 | REQUIRE(real{n} * pow(2, real{exp}) == r0); 48 | const auto old_n(n); 49 | REQUIRE_THROWS_PREDICATE(get_z_2exp(n, real{"nan", 5}), std::domain_error, [](const std::domain_error &ex) { 50 | return ex.what() == std::string("Cannot extract the significand and the exponent of a non-finite real"); 51 | }); 52 | REQUIRE_THROWS_PREDICATE(get_z_2exp(n, real{"inf", 5}), std::domain_error, [](const std::domain_error &ex) { 53 | return ex.what() == std::string("Cannot extract the significand and the exponent of a non-finite real"); 54 | }); 55 | REQUIRE_THROWS_PREDICATE(get_z_2exp(n, real{"-inf", 5}), std::domain_error, [](const std::domain_error &ex) { 56 | return ex.what() == std::string("Cannot extract the significand and the exponent of a non-finite real"); 57 | }); 58 | REQUIRE(n == old_n); 59 | exp = get_z_2exp(n, real{}); 60 | (void)exp; 61 | REQUIRE(n.is_zero()); 62 | } 63 | 64 | TEST_CASE("real set_ui_si_2exp") 65 | { 66 | real r0{45}; 67 | set_ui_2exp(r0, 2, 4); 68 | REQUIRE(r0 == 32); 69 | REQUIRE(r0.get_prec() == detail::real_deduce_precision(45)); 70 | set_si_2exp(r0, 2, 5); 71 | REQUIRE(r0 == 64); 72 | REQUIRE(r0.get_prec() == detail::real_deduce_precision(45)); 73 | set_si_2exp(r0, -1, -1); 74 | REQUIRE(r0 == real{"-.5", 7}); 75 | REQUIRE(r0.get_prec() == detail::real_deduce_precision(45)); 76 | set_si_2exp(r0, 0, -1); 77 | REQUIRE(r0 == real{}); 78 | REQUIRE(!r0.signbit()); 79 | REQUIRE(r0.get_prec() == detail::real_deduce_precision(45)); 80 | set_ui_2exp(r0, 0, -1); 81 | REQUIRE(r0 == real{}); 82 | REQUIRE(!r0.signbit()); 83 | REQUIRE(r0.get_prec() == detail::real_deduce_precision(45)); 84 | } 85 | -------------------------------------------------------------------------------- /test/real_hash.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016-2023 Francesco Biscani (bluescarni@gmail.com) 2 | // 3 | // This file is part of the mp++ library. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla 6 | // Public License v. 2.0. If a copy of the MPL was not distributed 7 | // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | #include 10 | 11 | #include 12 | 13 | #include "catch.hpp" 14 | 15 | // NOLINTNEXTLINE(google-build-using-namespace) 16 | using namespace mppp; 17 | 18 | // NOLINTNEXTLINE(google-readability-function-size, hicpp-function-size, readability-function-size) 19 | TEST_CASE("real hash") 20 | { 21 | // NaNs. 22 | REQUIRE(hash(real{"nan", 32}) == hash(real{"-nan", 32})); 23 | REQUIRE(hash(real{"nan", 640}) == hash(real{"-nan", 32})); 24 | REQUIRE(hash(real{"nan", 32}) == hash(real{"-nan", 640})); 25 | 26 | // Zeroes. 27 | REQUIRE(hash(real{"0", 32}) == hash(real{"-0", 32})); 28 | REQUIRE(hash(real{"0", 640}) == hash(real{"-0", 32})); 29 | REQUIRE(hash(real{"0", 32}) == hash(real{"-0", 640})); 30 | 31 | // Infinities. 32 | REQUIRE(hash(real{"inf", 32}) == hash(real{"inf", 32})); 33 | REQUIRE(hash(real{"-inf", 640}) == hash(real{"-inf", 640})); 34 | REQUIRE(hash(real{"inf", 32}) != hash(real{"-inf", 32})); 35 | REQUIRE(hash(real{"inf", 32}) == hash(real{"inf", 640})); 36 | REQUIRE(hash(real{"-inf", 640}) == hash(real{"-inf", 32})); 37 | 38 | // Normal numbers. The important thing to check here is that 39 | // trailing zero limbs are ignored in the computation of the hash. 40 | REQUIRE(hash(real{1, 1137}) == hash(real{1, 31})); 41 | real tmp{"-1.1", 113}; 42 | tmp.prec_round(2371); 43 | REQUIRE(hash(tmp) == hash(real{"-1.1", 113})); 44 | REQUIRE(hash(real{1, 64}) == hash(real{1, 65})); 45 | REQUIRE(hash(real{1, 64}) == hash(real{1, 63})); 46 | 47 | // Test also the std::hash specialisation. 48 | REQUIRE(std::hash{}(real{"-1.1", 113}) == hash(real{"-1.1", 113})); 49 | 50 | // A test changing the exponent. 51 | REQUIRE(std::hash{}(real{"-1.1", 113}) != hash(real{"-1.1", 113} * 16 * 16)); 52 | } 53 | -------------------------------------------------------------------------------- /test/real_neg_abs.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016-2023 Francesco Biscani (bluescarni@gmail.com) 2 | // 3 | // This file is part of the mp++ library. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla 6 | // Public License v. 2.0. If a copy of the MPL was not distributed 7 | // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | #include 10 | 11 | #include 12 | 13 | #include "catch.hpp" 14 | 15 | // NOLINTNEXTLINE(google-build-using-namespace) 16 | using namespace mppp; 17 | 18 | TEST_CASE("real neg") 19 | { 20 | real r0; 21 | REQUIRE(!r0.signbit()); 22 | REQUIRE((std::is_same::value)); 23 | r0.neg(); 24 | REQUIRE(r0.signbit()); 25 | r0 = -1; 26 | REQUIRE(r0.neg() == real{1}); 27 | REQUIRE(neg(real{-42}) == real{42}); 28 | r0 = 53; 29 | REQUIRE(neg(r0) == real{-53}); 30 | neg(r0, real{-53, 8}); 31 | REQUIRE(std::is_same::value); 32 | REQUIRE(r0 == real{53}); 33 | REQUIRE(r0.get_prec() == 8); 34 | real r1{123}; 35 | neg(r0, r1); 36 | REQUIRE(r0 == real{-123}); 37 | REQUIRE(r0.get_prec() == detail::nl_digits() + 1); 38 | } 39 | 40 | TEST_CASE("real abs") 41 | { 42 | real r0{"-0", 50}; 43 | REQUIRE(r0.signbit()); 44 | REQUIRE((std::is_same::value)); 45 | r0.abs(); 46 | REQUIRE(!r0.signbit()); 47 | r0 = -1; 48 | REQUIRE(r0.abs() == real{1}); 49 | REQUIRE(abs(real{-42}) == real{42}); 50 | REQUIRE(fabs(real{-42}) == real{42}); 51 | r0 = -53; 52 | REQUIRE(abs(r0) == real{53}); 53 | REQUIRE(fabs(r0) == real{53}); 54 | abs(r0, real{-53, 8}); 55 | REQUIRE(std::is_same::value); 56 | REQUIRE(r0 == real{53}); 57 | REQUIRE(r0.get_prec() == 8); 58 | fabs(r0, real{-53, 8}); 59 | REQUIRE(std::is_same::value); 60 | REQUIRE(r0 == real{53}); 61 | REQUIRE(r0.get_prec() == 8); 62 | real r1{-123}; 63 | abs(r0, r1); 64 | REQUIRE(r0 == real{123}); 65 | REQUIRE(r0.get_prec() == detail::nl_digits() + 1); 66 | r1 = real{-123}; 67 | fabs(r0, r1); 68 | REQUIRE(r0 == real{123}); 69 | REQUIRE(r0.get_prec() == detail::nl_digits() + 1); 70 | } 71 | -------------------------------------------------------------------------------- /test/real_nextafter.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016-2023 Francesco Biscani (bluescarni@gmail.com) 2 | // 3 | // This file is part of the mp++ library. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla 6 | // Public License v. 2.0. If a copy of the MPL was not distributed 7 | // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | #include "catch.hpp" 15 | 16 | // NOLINTNEXTLINE(google-build-using-namespace) 17 | using namespace mppp; 18 | 19 | // NOLINTNEXTLINE(google-readability-function-size, hicpp-function-size, readability-function-size) 20 | TEST_CASE("real nextafter ternary") 21 | { 22 | real rop; 23 | real x{1.1}; 24 | nextafter(rop, x, real{0}); 25 | REQUIRE(rop.get_prec() == x.get_prec()); 26 | REQUIRE(rop == std::nextafter(1.1, 0.)); 27 | 28 | // Check that the precision of y does not have any influence. 29 | rop = real{}; 30 | REQUIRE(&rop == &nextafter(rop, x, real{0, 512})); 31 | REQUIRE(rop.get_prec() == x.get_prec()); 32 | REQUIRE(rop == std::nextafter(1.1, 0.)); 33 | 34 | // Check with y overlapping x. 35 | rop = real{}; 36 | nextafter(rop, x, x); 37 | REQUIRE(rop.get_prec() == x.get_prec()); 38 | REQUIRE(rop == x); 39 | 40 | // Try moving in x. 41 | rop = real{}; 42 | auto x2 = x; 43 | nextafter(rop, std::move(x2), x); 44 | REQUIRE(rop.get_prec() == x.get_prec()); 45 | REQUIRE(rop == x); 46 | REQUIRE(x2 == real{}); 47 | REQUIRE(x2.get_prec() == real{}.get_prec()); 48 | 49 | // Identical arguments. 50 | rop = real{}; 51 | nextafter(rop, x, x); 52 | REQUIRE(rop.get_prec() == x.get_prec()); 53 | REQUIRE(rop == x); 54 | 55 | // Identical arguments, first one moved in. 56 | rop = real{}; 57 | x2 = x; 58 | nextafter(rop, std::move(x), x); 59 | REQUIRE(rop.get_prec() == x2.get_prec()); 60 | REQUIRE(rop == x2); 61 | REQUIRE(x == real{}); 62 | REQUIRE(x.get_prec() == real{}.get_prec()); 63 | 64 | rop = real{}; 65 | x = real{1.1}; 66 | 67 | // NaN testing. 68 | nextafter(rop, real{"nan", 23}, x); 69 | REQUIRE(isnan(rop)); 70 | REQUIRE(rop.get_prec() == 23); 71 | 72 | rop = real{}; 73 | nextafter(rop, x, real{"nan", 23}); 74 | REQUIRE(isnan(rop)); 75 | REQUIRE(rop.get_prec() == x.get_prec()); 76 | } 77 | 78 | // NOLINTNEXTLINE(google-readability-function-size, hicpp-function-size, readability-function-size) 79 | TEST_CASE("real nextafter binary") 80 | { 81 | real x{1.1}; 82 | auto rop = nextafter(x, real{0}); 83 | REQUIRE(rop.get_prec() == x.get_prec()); 84 | REQUIRE(rop == std::nextafter(1.1, 0.)); 85 | 86 | // Check that the precision of y does not have any influence. 87 | rop = nextafter(x, real{0, 512}); 88 | REQUIRE(rop.get_prec() == x.get_prec()); 89 | REQUIRE(rop == std::nextafter(1.1, 0.)); 90 | 91 | // Check with y overlapping x. 92 | rop = nextafter(x, x); 93 | REQUIRE(rop.get_prec() == x.get_prec()); 94 | REQUIRE(rop == x); 95 | 96 | // Try moving in x. 97 | auto x2 = x; 98 | rop = nextafter(std::move(x2), x); 99 | REQUIRE(rop.get_prec() == x.get_prec()); 100 | REQUIRE(rop == x); 101 | REQUIRE(!x2.is_valid()); 102 | 103 | // Identical arguments. 104 | rop = nextafter(x, x); 105 | REQUIRE(rop.get_prec() == x.get_prec()); 106 | REQUIRE(rop == x); 107 | 108 | // Identical arguments, first one moved in. 109 | x2 = x; 110 | rop = nextafter(std::move(x), x); 111 | REQUIRE(rop.get_prec() == x2.get_prec()); 112 | REQUIRE(rop == x2); 113 | REQUIRE(!x.is_valid()); 114 | 115 | x = real{1.1}; 116 | 117 | // NaN testing. 118 | rop = nextafter(real{"nan", 23}, x); 119 | REQUIRE(isnan(rop)); 120 | REQUIRE(rop.get_prec() == 23); 121 | 122 | rop = nextafter(x, real{"nan", 23}); 123 | REQUIRE(isnan(rop)); 124 | REQUIRE(rop.get_prec() == x.get_prec()); 125 | } 126 | -------------------------------------------------------------------------------- /test/type_name.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2016-2023 Francesco Biscani (bluescarni@gmail.com) 2 | // 3 | // This file is part of the mp++ library. 4 | // 5 | // This Source Code Form is subject to the terms of the Mozilla 6 | // Public License v. 2.0. If a copy of the MPL was not distributed 7 | // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include "catch.hpp" 20 | 21 | // NOLINTNEXTLINE(google-build-using-namespace) 22 | using namespace mppp; 23 | 24 | TEST_CASE("type_name") 25 | { 26 | std::cout << type_name() << '\n'; 27 | std::cout << type_name() << '\n'; 28 | std::cout << type_name() << '\n'; 29 | std::cout << type_name() << '\n'; 30 | std::cout << type_name() << '\n'; 31 | std::cout << type_name() << '\n'; 32 | std::cout << type_name>>() << '\n'; 33 | std::cout << type_name>() << '\n'; 34 | std::cout << type_name>() << '\n'; 35 | std::cout << type_name &>() << '\n'; 36 | std::cout << type_name const>() << '\n'; 37 | std::cout << type_name const &>() << '\n'; 38 | std::cout << type_name *>() << '\n'; 39 | std::cout << type_name *>() << '\n'; 40 | std::cout << type_name *const>() << '\n'; 41 | std::cout << type_name *const &>() << '\n'; 42 | std::cout << type_name() << '\n'; 43 | std::cout << type_name() << '\n'; 44 | std::cout << type_name() << '\n'; 45 | std::cout << type_name() << '\n'; 46 | #if defined(MPPP_HAVE_GCC_INT128) 47 | std::cout << type_name<__int128_t>() << '\n'; 48 | std::cout << type_name<__int128_t *>() << '\n'; 49 | std::cout << type_name<__int128_t const *>() << '\n'; 50 | std::cout << type_name<__int128_t const *const>() << '\n'; 51 | std::cout << type_name<__uint128_t>() << '\n'; 52 | std::cout << type_name<__uint128_t *>() << '\n'; 53 | std::cout << type_name<__uint128_t const *>() << '\n'; 54 | std::cout << type_name<__uint128_t const *const>() << '\n'; 55 | std::cout << type_name() << '\n'; 56 | std::cout << type_name() << '\n'; 57 | std::cout << type_name<__int128_t &>() << '\n'; 58 | std::cout << type_name<__uint128_t &>() << '\n'; 59 | std::cout << type_name<__int128_t &&>() << '\n'; 60 | std::cout << type_name<__uint128_t &&>() << '\n'; 61 | std::cout << type_name() << '\n'; 62 | std::cout << type_name() << '\n'; 63 | std::cout << type_name<__int128_t[3]>() << '\n'; 64 | std::cout << type_name<__int128_t(&)[3]>() << '\n'; 65 | std::cout << type_name>() << '\n'; 66 | #endif 67 | 68 | // Couple of multithreaded tests. 69 | auto t_func = []() -> std::string { 70 | std::string tmp; 71 | for (auto i = 0; i < 100; ++i) { 72 | tmp += type_name>>(); 73 | } 74 | return tmp; 75 | }; 76 | 77 | std::thread t1(t_func); 78 | std::thread t2(t_func); 79 | std::thread t3(t_func); 80 | std::thread t4(t_func); 81 | std::thread t5(t_func); 82 | std::thread t6(t_func); 83 | 84 | t1.join(); 85 | t2.join(); 86 | t3.join(); 87 | t4.join(); 88 | t5.join(); 89 | t6.join(); 90 | } 91 | -------------------------------------------------------------------------------- /tools/appveyor-download.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | rem initiate the retry number 3 | set retryNumber=0 4 | set maxRetries=6 5 | set time=0 6 | 7 | :DOWNLOAD 8 | timeout %time% > NUL 9 | set /a time=2*%time%+1 10 | appveyor DownloadFile %* 11 | 12 | rem problem? 13 | IF NOT ERRORLEVEL 1 GOTO :EOF 14 | @echo Oops, appveyor download exited with code %ERRORLEVEL% - let us try again! 15 | set /a retryNumber=%retryNumber%+1 16 | IF %reTryNumber% LSS %maxRetries% (GOTO :DOWNLOAD) 17 | @echo Sorry, we tried downloading the package for %maxRetries% times and all attempts were unsuccessful! 18 | EXIT /B 1 19 | -------------------------------------------------------------------------------- /tools/circleci_conda_arm64.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Echo each command 4 | set -x 5 | 6 | # Exit on error. 7 | set -e 8 | 9 | # Core deps. 10 | sudo apt-get install wget 11 | 12 | # Install conda+deps. 13 | wget https://github.com/conda-forge/miniforge/releases/latest/download/Miniforge3-Linux-aarch64.sh -O mambaforge.sh 14 | export deps_dir=$HOME/local 15 | export PATH="$HOME/mambaforge/bin:$PATH" 16 | bash mambaforge.sh -b -p $HOME/mambaforge 17 | mamba create -y -p $deps_dir c-compiler cxx-compiler ninja cmake gmp mpfr libflint mpc fmt libboost-devel 18 | source activate $deps_dir 19 | 20 | # Create the build dir and cd into it. 21 | mkdir build 22 | cd build 23 | 24 | unset CFLAGS 25 | unset CXXFLAGS 26 | 27 | # GCC build. 28 | cmake ../ -G Ninja \ 29 | -DCMAKE_PREFIX_PATH=$deps_dir \ 30 | -DCMAKE_CXX_STANDARD=20 \ 31 | -DCMAKE_BUILD_TYPE=Debug \ 32 | -DMPPP_BUILD_TESTS=yes \ 33 | -DMPPP_WITH_BOOST_S11N=yes \ 34 | -DMPPP_WITH_FMT=yes \ 35 | -DMPPP_WITH_MPFR=yes \ 36 | -DMPPP_WITH_MPC=yes \ 37 | -DMPPP_WITH_FLINT=yes \ 38 | -DMPPP_ENABLE_IPO=yes 39 | 40 | ninja -v -j4 41 | # Run the tests. 42 | ctest -V -j4 43 | 44 | set +e 45 | set +x 46 | -------------------------------------------------------------------------------- /tools/circleci_conda_coverage.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Echo each command 4 | set -x 5 | 6 | # Exit on error. 7 | set -e 8 | 9 | # Core deps. 10 | sudo apt-get install wget curl 11 | 12 | # Install conda+deps. 13 | wget https://github.com/conda-forge/miniforge/releases/latest/download/Miniforge3-Linux-x86_64.sh -O mambaforge.sh 14 | export deps_dir=$HOME/local 15 | export PATH="$HOME/mambaforge/bin:$PATH" 16 | bash mambaforge.sh -b -p $HOME/mambaforge 17 | mamba create -y -p $deps_dir c-compiler cxx-compiler ninja cmake gmp mpfr libflint mpc fmt libboost-devel lcov 18 | source activate $deps_dir 19 | 20 | # Create the build dir and cd into it. 21 | mkdir build 22 | cd build 23 | 24 | unset CFLAGS 25 | unset CXXFLAGS 26 | 27 | # GCC build. 28 | cmake ../ -G Ninja \ 29 | -DCMAKE_PREFIX_PATH=$deps_dir \ 30 | -DCMAKE_CXX_STANDARD=17 \ 31 | -DCMAKE_BUILD_TYPE=Debug \ 32 | -DMPPP_BUILD_TESTS=yes \ 33 | -DMPPP_WITH_MPFR=yes \ 34 | -DMPPP_WITH_MPC=yes \ 35 | -DMPPP_WITH_FLINT=yes \ 36 | -DMPPP_WITH_QUADMATH=yes \ 37 | -DMPPP_WITH_BOOST_S11N=yes \ 38 | -DCMAKE_CXX_FLAGS="--coverage" 39 | 40 | ninja -v -j4 41 | # Run the tests. 42 | ctest -V -j4 43 | 44 | # Create lcov report 45 | lcov --capture --directory . --output-file coverage.info 46 | 47 | # Upload coverage data. 48 | curl -Os https://uploader.codecov.io/latest/linux/codecov 49 | chmod +x codecov 50 | ./codecov -f coverage.info -g --gx $deps_dir/bin/gcov 51 | 52 | set +e 53 | set +x 54 | -------------------------------------------------------------------------------- /tools/circleci_conda_docs.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Echo each command 4 | set -x 5 | 6 | # Exit on error. 7 | set -e 8 | 9 | # Core deps. 10 | sudo apt-get install wget 11 | 12 | # Install conda+deps. 13 | wget https://github.com/conda-forge/miniforge/releases/latest/download/Miniforge3-Linux-x86_64.sh -O mambaforge.sh 14 | export deps_dir=$HOME/local 15 | export PATH="$HOME/mambaforge/bin:$PATH" 16 | bash mambaforge.sh -b -p $HOME/mambaforge 17 | mamba create -y -p $deps_dir c-compiler cxx-compiler ninja cmake gmp mpfr libflint mpc fmt \ 18 | libboost-devel 'sphinx=7.*' 'sphinx-book-theme=1.*' myst-nb xeus-cling 19 | source activate $deps_dir 20 | 21 | # Create the build dir and cd into it. 22 | mkdir build 23 | cd build 24 | 25 | unset CFLAGS 26 | unset CXXFLAGS 27 | 28 | # Build and install 29 | cmake ../ -G Ninja \ 30 | -DCMAKE_PREFIX_PATH=$deps_dir \ 31 | -DCMAKE_INSTALL_PREFIX=$deps_dir \ 32 | -DCMAKE_CXX_STANDARD=17 \ 33 | -DCMAKE_BUILD_TYPE=Debug \ 34 | -DMPPP_WITH_BOOST_S11N=yes \ 35 | -DMPPP_WITH_FMT=yes \ 36 | -DMPPP_WITH_MPFR=yes \ 37 | -DMPPP_WITH_MPC=yes \ 38 | -DMPPP_WITH_FLINT=yes \ 39 | -DMPPP_WITH_QUADMATH=yes 40 | 41 | ninja -v -j4 install 42 | 43 | # Build the docs. 44 | cd ../doc 45 | make html linkcheck 46 | 47 | if [[ ! -z "${CI_PULL_REQUEST}" ]]; then 48 | echo "Testing a pull request, the generated documentation will not be uploaded."; 49 | exit 0; 50 | fi 51 | 52 | if [[ "${CIRCLE_BRANCH}" != "master" ]]; then 53 | echo "Branch is not master, the generated documentation will not be uploaded."; 54 | exit 0; 55 | fi 56 | 57 | # Check out the gh_pages branch in a separate dir. 58 | cd ../ 59 | git config --global push.default simple 60 | git config --global user.name "CircleCI" 61 | git config --global user.email "bluescarni@gmail.com" 62 | set +x 63 | git clone "https://${GH_TOKEN}@github.com/bluescarni/mppp.git" mppp_gh_pages -q 64 | set -x 65 | cd mppp_gh_pages 66 | git checkout -b gh-pages --track origin/gh-pages; 67 | git rm -fr *; 68 | mv ../doc/_build/html/* .; 69 | git add *; 70 | # We assume here that a failure in commit means that there's nothing 71 | # to commit. 72 | git commit -m "Update Sphinx documentation, commit ${CIRCLE_SHA1} [skip ci]." || exit 0 73 | PUSH_COUNTER=0 74 | until git push -q 75 | do 76 | git pull -q 77 | PUSH_COUNTER=$((PUSH_COUNTER + 1)) 78 | if [ "$PUSH_COUNTER" -gt 3 ]; then 79 | echo "Push failed, aborting."; 80 | exit 1; 81 | fi 82 | done 83 | 84 | set +e 85 | set +x 86 | -------------------------------------------------------------------------------- /tools/circleci_conda_release.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Echo each command 4 | set -x 5 | 6 | # Exit on error. 7 | set -e 8 | 9 | # Core deps. 10 | sudo apt-get install wget 11 | 12 | # Install conda+deps. 13 | wget https://github.com/conda-forge/miniforge/releases/latest/download/Miniforge3-Linux-x86_64.sh -O mambaforge.sh 14 | export deps_dir=$HOME/local 15 | export PATH="$HOME/mambaforge/bin:$PATH" 16 | bash mambaforge.sh -b -p $HOME/mambaforge 17 | mamba create -y -p $deps_dir c-compiler cxx-compiler ninja cmake gmp mpfr libflint mpc fmt libboost-devel 18 | source activate $deps_dir 19 | 20 | # Create the build dir and cd into it. 21 | mkdir build 22 | cd build 23 | 24 | # GCC build. 25 | cmake ../ -G Ninja \ 26 | -DCMAKE_PREFIX_PATH=$deps_dir \ 27 | -DCMAKE_CXX_STANDARD=17 \ 28 | -DCMAKE_BUILD_TYPE=Release \ 29 | -DMPPP_BUILD_TESTS=yes \ 30 | -DMPPP_WITH_BOOST_S11N=yes \ 31 | -DMPPP_WITH_FMT=yes \ 32 | -DMPPP_WITH_MPFR=yes \ 33 | -DMPPP_WITH_MPC=yes \ 34 | -DMPPP_WITH_FLINT=yes \ 35 | -DMPPP_WITH_QUADMATH=yes \ 36 | -DMPPP_ENABLE_IPO=yes \ 37 | 38 | ninja -v -j4 39 | # Run the tests. 40 | ctest -V -j4 41 | 42 | set +e 43 | set +x 44 | -------------------------------------------------------------------------------- /tools/circleci_focal_clang9_debuggmp_unstable.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Echo each command 4 | set -x 5 | 6 | # Exit on error. 7 | set -e 8 | 9 | # Core deps. 10 | sudo apt-get install build-essential cmake mercurial autoconf bison texinfo clang 11 | 12 | # Create the build dir and cd into it. 13 | mkdir build 14 | cd build 15 | 16 | # Download and compile locally the latest GMP in debug mode. 17 | hg clone https://gmplib.org/repo/gmp/ gmp_unstable 18 | cd gmp_unstable 19 | ./.bootstrap 20 | CC=clang CXX=clang++ ./configure --enable-shared --disable-static --enable-assert --enable-alloca=debug --disable-assembly CFLAGS="-g -fsanitize=address" --prefix=/home/circleci/.local 21 | make -j2 22 | make install 23 | 24 | # Compile mppp and run the tests. 25 | cd .. 26 | CC=clang CXX=clang++ cmake ../ -DCMAKE_BUILD_TYPE=Debug -DMPPP_WITH_QUADMATH=yes -DMPPP_BUILD_TESTS=yes -DCMAKE_CXX_FLAGS="-fsanitize=address" -DCMAKE_PREFIX_PATH=/home/circleci/.local -DMPPP_QUADMATH_INCLUDE_DIR=/usr/lib/gcc/x86_64-linux-gnu/9/include/ -DMPPP_QUADMATH_LIBRARY=/usr/lib/gcc/x86_64-linux-gnu/9/libquadmath.so -DMPPP_ENABLE_IPO=yes 27 | make -j2 VERBOSE=1 28 | ctest -V 29 | 30 | set +e 31 | set +x 32 | -------------------------------------------------------------------------------- /tools/circleci_focal_clang9_msan.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Echo each command 4 | set -x 5 | 6 | # Exit on error. 7 | set -e 8 | 9 | # Core deps. 10 | sudo apt-get update 11 | sudo apt-get install build-essential cmake wget clang ninja-build 12 | 13 | # Create the build dir and cd into it. 14 | mkdir build 15 | cd build 16 | MPPP_BUILD_DIR=`pwd` 17 | 18 | # libc++ setup. See: 19 | # https://github.com/google/sanitizers/wiki/MemorySanitizerLibcxxHowTo 20 | git clone --depth=1 https://github.com/llvm/llvm-project 21 | cd llvm-project 22 | mkdir build 23 | cd build 24 | LLVM_BUILD_DIR=`pwd` 25 | cmake -GNinja ../llvm \ 26 | -DCMAKE_BUILD_TYPE=Release \ 27 | -DLLVM_ENABLE_PROJECTS="libcxx;libcxxabi" \ 28 | -DCMAKE_C_COMPILER=clang \ 29 | -DCMAKE_CXX_COMPILER=clang++ \ 30 | -DLLVM_USE_SANITIZER=MemoryWithOrigins 31 | cmake --build . -- cxx cxxabi 32 | cd .. 33 | find . -iname "cxxabi.h" 34 | # Back to the MPPP build dir. 35 | cd $MPPP_BUILD_DIR 36 | 37 | # Download and compile locally GMP in debug mode. 38 | GMP_VERSION="6.2.1" 39 | wget https://gmplib.org/download/gmp/gmp-${GMP_VERSION}.tar.bz2 -O gmp.tar.bz2 40 | tar xjvf gmp.tar.bz2 41 | cd gmp-${GMP_VERSION} 42 | CC=clang CXX=clang++ ./configure --enable-shared --disable-static --enable-assert --enable-alloca=debug --disable-assembly CFLAGS="-g -fsanitize=memory" --prefix=/home/circleci/.local 43 | make -j2 44 | make install 45 | 46 | # Compile mppp and run the tests. 47 | cd .. 48 | MPPP_MSAN_FLAGS="-fsanitize=memory -stdlib=libc++ -nostdinc++ -isystem ${LLVM_BUILD_DIR}/include/c++/v1/include/c++/v1/ -isystem ${LLVM_BUILD_DIR}/include/c++/v1 -L${LLVM_BUILD_DIR}/lib -Wl,-rpath,${LLVM_BUILD_DIR}/lib -Wno-unused-command-line-argument" 49 | CC=clang CXX=clang++ cmake ../ -DCMAKE_BUILD_TYPE=Debug -DMPPP_BUILD_TESTS=yes -DCMAKE_CXX_FLAGS="${MPPP_MSAN_FLAGS}" -DCMAKE_C_FLAGS="${MPPP_MSAN_FLAGS}" -DCMAKE_PREFIX_PATH=/home/circleci/.local -DCMAKE_CXX_STANDARD=17 -DMPPP_TEST_NSPLIT=${TEST_NSPLIT} -DMPPP_TEST_SPLIT_NUM=${SPLIT_TEST_NUM} 50 | make -j2 VERBOSE=1 51 | ctest -j4 -V 52 | 53 | set +e 54 | set +x 55 | -------------------------------------------------------------------------------- /tools/gha_conda_asan.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Echo each command 4 | set -x 5 | 6 | # Exit on error. 7 | set -e 8 | 9 | # Core deps. 10 | sudo apt-get install wget 11 | 12 | # Install conda+deps. 13 | wget https://github.com/conda-forge/miniforge/releases/latest/download/Miniforge3-Linux-x86_64.sh -O miniforge.sh 14 | export deps_dir=$HOME/local 15 | export PATH="$HOME/miniforge/bin:$PATH" 16 | bash miniforge.sh -b -p $HOME/miniforge 17 | mamba create -y -p $deps_dir c-compiler cxx-compiler ninja cmake gmp mpfr libflint mpc fmt libboost-devel 18 | source activate $deps_dir 19 | 20 | # Create the build dir and cd into it. 21 | mkdir build 22 | cd build 23 | 24 | unset CFLAGS 25 | unset CXXFLAGS 26 | 27 | cmake ../ -G Ninja \ 28 | -DCMAKE_PREFIX_PATH=$deps_dir \ 29 | -DCMAKE_CXX_STANDARD=20 \ 30 | -DCMAKE_BUILD_TYPE=Debug \ 31 | -DMPPP_BUILD_TESTS=yes \ 32 | -DMPPP_WITH_BOOST_S11N=yes \ 33 | -DMPPP_WITH_FMT=yes \ 34 | -DMPPP_WITH_MPFR=yes \ 35 | -DMPPP_WITH_MPC=yes \ 36 | -DMPPP_WITH_FLINT=yes \ 37 | -DMPPP_WITH_QUADMATH=yes \ 38 | -DCMAKE_CXX_FLAGS="-fsanitize=address" \ 39 | -DMPPP_ENABLE_IPO=yes 40 | 41 | ninja -v 42 | ctest -V -j2 43 | 44 | set +e 45 | set +x 46 | -------------------------------------------------------------------------------- /tools/gha_conda_tsan.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Echo each command 4 | set -x 5 | 6 | # Exit on error. 7 | set -e 8 | 9 | # Core deps. 10 | sudo apt-get install wget 11 | 12 | # Install conda+deps. 13 | wget https://github.com/conda-forge/miniforge/releases/latest/download/Miniforge3-Linux-x86_64.sh -O miniforge.sh 14 | export deps_dir=$HOME/local 15 | export PATH="$HOME/miniforge/bin:$PATH" 16 | bash miniforge.sh -b -p $HOME/miniforge 17 | mamba create -y -p $deps_dir c-compiler cxx-compiler ninja cmake gmp mpfr libflint mpc fmt libboost-devel 18 | source activate $deps_dir 19 | 20 | # Create the build dir and cd into it. 21 | mkdir build 22 | cd build 23 | 24 | unset CFLAGS 25 | unset CXXFLAGS 26 | 27 | cmake ../ -G Ninja \ 28 | -DCMAKE_PREFIX_PATH=$deps_dir \ 29 | -DCMAKE_CXX_STANDARD=17 \ 30 | -DCMAKE_BUILD_TYPE=Debug \ 31 | -DMPPP_BUILD_TESTS=yes \ 32 | -DMPPP_WITH_BOOST_S11N=yes \ 33 | -DMPPP_WITH_FMT=yes \ 34 | -DMPPP_WITH_MPFR=yes \ 35 | -DMPPP_WITH_MPC=yes \ 36 | -DMPPP_WITH_FLINT=yes \ 37 | -DMPPP_WITH_QUADMATH=yes \ 38 | -DCMAKE_CXX_FLAGS="-fsanitize=thread" \ 39 | -DMPPP_ENABLE_IPO=yes 40 | 41 | ninja -v 42 | ctest -V -j2 43 | 44 | set +e 45 | set +x 46 | -------------------------------------------------------------------------------- /tools/gha_conda_ubsan.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Echo each command 4 | set -x 5 | 6 | # Exit on error. 7 | set -e 8 | 9 | # Core deps. 10 | sudo apt-get install wget 11 | 12 | # Install conda+deps. 13 | wget https://github.com/conda-forge/miniforge/releases/latest/download/Miniforge3-Linux-x86_64.sh -O miniforge.sh 14 | export deps_dir=$HOME/local 15 | export PATH="$HOME/miniforge/bin:$PATH" 16 | bash miniforge.sh -b -p $HOME/miniforge 17 | mamba create -y -p $deps_dir c-compiler cxx-compiler ninja cmake gmp mpfr libflint mpc fmt libboost-devel 18 | source activate $deps_dir 19 | 20 | # Create the build dir and cd into it. 21 | mkdir build 22 | cd build 23 | 24 | unset CFLAGS 25 | unset CXXFLAGS 26 | 27 | cmake ../ -G Ninja \ 28 | -DCMAKE_PREFIX_PATH=$deps_dir \ 29 | -DCMAKE_CXX_STANDARD=17 \ 30 | -DCMAKE_BUILD_TYPE=Debug \ 31 | -DMPPP_BUILD_TESTS=yes \ 32 | -DMPPP_WITH_BOOST_S11N=yes \ 33 | -DMPPP_WITH_FMT=yes \ 34 | -DMPPP_WITH_MPFR=yes \ 35 | -DMPPP_WITH_MPC=yes \ 36 | -DMPPP_WITH_FLINT=yes \ 37 | -DMPPP_WITH_QUADMATH=yes \ 38 | -DCMAKE_CXX_FLAGS="-fsanitize=undefined" \ 39 | -DMPPP_ENABLE_IPO=yes 40 | 41 | ninja -v 42 | ctest -V -j2 43 | 44 | set +e 45 | set +x 46 | 47 | -------------------------------------------------------------------------------- /tools/gha_debuggmp.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Echo each command 4 | set -x 5 | 6 | # Exit on error. 7 | set -e 8 | 9 | # Core deps. 10 | sudo apt-get install wget 11 | 12 | # Install conda+deps. 13 | wget https://github.com/conda-forge/miniforge/releases/latest/download/Miniforge3-Linux-x86_64.sh -O miniforge.sh 14 | export deps_dir=$HOME/local 15 | export PATH="$HOME/miniforge/bin:$PATH" 16 | bash miniforge.sh -b -p $HOME/miniforge 17 | mamba create -y -p $deps_dir c-compiler cxx-compiler ninja cmake make 18 | source activate $deps_dir 19 | 20 | # Create the build dir and cd into it. 21 | mkdir build 22 | cd build 23 | 24 | unset CFLAGS 25 | unset CXXFLAGS 26 | 27 | # Download and compile locally GMP in debug mode. 28 | GMP_VERSION="6.3.0" 29 | wget https://github.com/esa/manylinux_x86_64_with_deps/raw/master/gmp-${GMP_VERSION}.tar.bz2 -O gmp.tar.bz2 30 | tar xjvf gmp.tar.bz2 31 | cd gmp-${GMP_VERSION} 32 | ./configure --enable-shared --disable-static --enable-assert --enable-alloca=debug --disable-assembly CFLAGS="-g -fsanitize=address" --prefix=$CONDA_PREFIX 33 | make -j2 34 | make install 35 | 36 | # Compile mppp and run the tests. 37 | cd .. 38 | cmake ../ -G Ninja \ 39 | -DCMAKE_BUILD_TYPE=Debug \ 40 | -DMPPP_WITH_QUADMATH=yes \ 41 | -DMPPP_BUILD_TESTS=yes \ 42 | -DCMAKE_CXX_FLAGS="-fsanitize=address" \ 43 | -DCMAKE_PREFIX_PATH=$CONDA_PREFIX \ 44 | -DMPPP_ENABLE_IPO=yes 45 | 46 | ninja -v 47 | ctest -V -j2 48 | 49 | set +e 50 | set +x 51 | -------------------------------------------------------------------------------- /tools/gha_osx.sh: -------------------------------------------------------------------------------- 1 | 2 | #!/usr/bin/env bash 3 | 4 | # Echo each command 5 | set -x 6 | 7 | # Exit on error. 8 | set -e 9 | 10 | # Install conda+deps. 11 | wget https://github.com/conda-forge/miniforge/releases/latest/download/Miniforge3-MacOSX-x86_64.sh -O miniforge.sh 12 | export deps_dir=$HOME/local 13 | export PATH="$HOME/miniforge/bin:$PATH" 14 | bash miniforge.sh -b -p $HOME/miniforge 15 | mamba create -y -p $deps_dir c-compiler cxx-compiler ninja cmake gmp mpfr libflint mpc fmt libboost-devel 16 | source activate $deps_dir 17 | 18 | # Create the build dir and cd into it. 19 | mkdir build 20 | cd build 21 | 22 | unset CFLAGS 23 | unset CXXFLAGS 24 | 25 | cmake ../ -G Ninja \ 26 | -DCMAKE_PREFIX_PATH=$deps_dir \ 27 | -DCMAKE_CXX_STANDARD=20 \ 28 | -DCMAKE_BUILD_TYPE=Debug \ 29 | -DMPPP_BUILD_TESTS=yes \ 30 | -DMPPP_WITH_BOOST_S11N=yes \ 31 | -DMPPP_WITH_FMT=yes \ 32 | -DMPPP_WITH_MPFR=yes \ 33 | -DMPPP_WITH_FLINT=yes \ 34 | -DMPPP_WITH_MPC=yes \ 35 | -DMPPP_ENABLE_IPO=yes 36 | 37 | ninja -v 38 | ctest -V -j2 39 | 40 | set +e 41 | set +x 42 | -------------------------------------------------------------------------------- /tools/sample_project/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # mp++ requires at least CMake 3.12. 2 | cmake_minimum_required(VERSION 3.12.0) 3 | 4 | # The name of our project. 5 | project(sample_project) 6 | 7 | # Look for an installation of mp++ in the system. 8 | find_package(mp++ REQUIRED) 9 | 10 | # Create an executable, and link it to the mp++::mp++ imported target. 11 | # This ensures that, in the compilation of 'main', mp++'s include 12 | # dirs are added to the include path of the compiler and that mp++'s 13 | # dependencies (e.g., GMP) are transitively linked to 'main'. 14 | add_executable(main main.cpp) 15 | target_link_libraries(main mp++::mp++) 16 | -------------------------------------------------------------------------------- /tools/sample_project/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using int_t = mppp::integer<1>; 5 | 6 | int main() 7 | { 8 | int_t n{42}; 9 | std::cout << n << '\n'; 10 | } 11 | -------------------------------------------------------------------------------- /tools/travis_ubuntu_ppc64.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Echo each command 4 | set -x 5 | 6 | # Exit on error. 7 | set -e 8 | 9 | 10 | # Install conda+deps. 11 | curl -L -o miniconda.sh https://github.com/conda-forge/miniforge/releases/latest/download/Mambaforge-Linux-ppc64le.sh 12 | export deps_dir=$HOME/local 13 | export PATH="$HOME/miniconda/bin:$PATH" 14 | bash miniconda.sh -b -p $HOME/miniconda 15 | conda create -y -q -p $deps_dir cmake gmp mpfr libflint python=3.8 pybind11 mpc boost-cpp c-compiler cxx-compiler make fmt 16 | source activate $deps_dir 17 | 18 | # Create the build dir and cd into it. 19 | mkdir build 20 | cd build 21 | 22 | # GCC build. 23 | cmake ../ -DCMAKE_PREFIX_PATH=$deps_dir -DCMAKE_CXX_STANDARD=17 -DCMAKE_BUILD_TYPE=Debug -DMPPP_BUILD_TESTS=YES -DMPPP_WITH_BOOST_S11N=yes -DMPPP_WITH_FMT=yes -DMPPP_WITH_QUADMATH=yes -DMPPP_WITH_MPFR=yes -DMPPP_WITH_MPC=yes -DMPPP_WITH_FLINT=yes -DMPPP_TEST_PYBIND11=yes -DPYBIND11_PYTHON_VERSION=3.8 24 | make -j1 VERBOSE=1 25 | # Run the tests. 26 | ctest -V -j2 27 | 28 | set +e 29 | set +x 30 | --------------------------------------------------------------------------------