├── .clang-tidy ├── .github └── workflows │ ├── coverage.yml │ └── test.yml ├── CITATION.cff ├── CMakeLists.txt ├── LICENSE ├── README.md ├── examples ├── example.F90 ├── example.c └── example.cpp ├── src ├── CMakeLists.txt ├── c │ ├── CMakeLists.txt │ ├── Cl2.c │ ├── Cl2.h │ ├── Cl3.c │ ├── Cl3.h │ ├── Cl4.c │ ├── Cl4.h │ ├── Cl5.c │ ├── Cl5.h │ ├── Cl6.c │ ├── Cl6.h │ ├── Li2.c │ ├── Li2.h │ ├── Li3.c │ ├── Li3.h │ ├── Li4.c │ ├── Li4.h │ ├── Li5.c │ ├── Li5.h │ ├── Li6.c │ ├── Li6.h │ ├── log.c │ └── log.h ├── cpp │ ├── CMakeLists.txt │ ├── Cl.cpp │ ├── Cl.hpp │ ├── Cl1.cpp │ ├── Cl1.hpp │ ├── Cl2.cpp │ ├── Cl2.hpp │ ├── Cl3.cpp │ ├── Cl3.hpp │ ├── Cl4.cpp │ ├── Cl4.hpp │ ├── Cl5.cpp │ ├── Cl5.hpp │ ├── Cl6.cpp │ ├── Cl6.hpp │ ├── Li.cpp │ ├── Li.hpp │ ├── Li2.cpp │ ├── Li2.hpp │ ├── Li3.cpp │ ├── Li3.hpp │ ├── Li4.cpp │ ├── Li4.hpp │ ├── Li5.cpp │ ├── Li5.hpp │ ├── Li6.cpp │ ├── Li6.hpp │ ├── Sl.cpp │ ├── Sl.hpp │ ├── eta.cpp │ ├── eta.hpp │ ├── factorial.cpp │ ├── factorial.hpp │ ├── harmonic.cpp │ ├── harmonic.hpp │ ├── horner.hpp │ ├── log.hpp │ ├── zeta.cpp │ └── zeta.hpp ├── fortran │ ├── CMakeLists.txt │ ├── Cl2.f90 │ ├── Cl2.fh │ ├── Cl3.f90 │ ├── Cl3.fh │ ├── Cl4.f90 │ ├── Cl4.fh │ ├── Cl5.f90 │ ├── Cl5.fh │ ├── Cl6.f90 │ ├── Cl6.fh │ ├── Li2.f90 │ ├── Li2.fh │ ├── Li3.f90 │ ├── Li3.fh │ ├── Li4.f90 │ ├── Li4.fh │ ├── Li5.f90 │ ├── Li5.fh │ ├── Li6.f90 │ ├── Li6.fh │ └── log.f90 └── version.h └── test ├── CMakeLists.txt ├── alt ├── CMakeLists.txt ├── README.md ├── algorithm_327 │ ├── CMakeLists.txt │ └── algorithm_327.c ├── algorithm_490 │ ├── CMakeLists.txt │ └── algorithm_490.c ├── alt.c ├── alt.h ├── babar │ ├── CMakeLists.txt │ └── babar.c ├── bernoulli │ ├── CMakeLists.txt │ └── bernoulli.c ├── cephes │ ├── CMakeLists.txt │ └── cephes.c ├── feynhiggs │ ├── CMakeLists.txt │ └── feynhiggs.c ├── fortran77 │ └── Li2.f ├── hassani │ ├── CMakeLists.txt │ └── hassani.c ├── hdecay │ ├── CMakeLists.txt │ └── hdecay.c ├── hollik │ ├── CMakeLists.txt │ └── hollik.c ├── koelbig │ ├── CMakeLists.txt │ └── koelbig.c ├── morris │ ├── CMakeLists.txt │ └── morris.c ├── pade │ ├── CMakeLists.txt │ └── pade.c ├── sherpa │ ├── CMakeLists.txt │ └── sherpa.c ├── spheno │ ├── CMakeLists.txt │ └── spheno.c ├── tsil │ ├── CMakeLists.txt │ ├── dilog.c │ ├── trilog.c │ ├── tsil.h │ └── tsil_cpp.h └── wu │ ├── CMakeLists.txt │ └── wu.c ├── bench.hpp ├── bench_Cl.cpp ├── bench_Li.cpp ├── bench_Sl.cpp ├── c_wrappers.c ├── c_wrappers.h ├── data ├── Cl1.txt ├── Cl10.txt ├── Cl1000.txt ├── Cl1000000.txt ├── Cl1001.txt ├── Cl11.txt ├── Cl12.txt ├── Cl13.txt ├── Cl14.txt ├── Cl15.txt ├── Cl16.txt ├── Cl2.txt ├── Cl3.txt ├── Cl4.txt ├── Cl5.txt ├── Cl6.txt ├── Cl7.txt ├── Cl8.txt ├── Cl9.txt ├── Li-1.txt ├── Li-10.txt ├── Li-100.txt ├── Li-2.txt ├── Li-3.txt ├── Li-4.txt ├── Li-5.txt ├── Li-6.txt ├── Li-7.txt ├── Li-8.txt ├── Li-9.txt ├── Li0.txt ├── Li1.txt ├── Li100.txt ├── Li2.txt ├── Li3.txt ├── Li4.txt ├── Li5.txt ├── Li6.txt ├── Sl1.txt ├── Sl10.txt ├── Sl1000.txt ├── Sl1001.txt ├── Sl11.txt ├── Sl12.txt ├── Sl13.txt ├── Sl14.txt ├── Sl15.txt ├── Sl16.txt ├── Sl17.txt ├── Sl18.txt ├── Sl19.txt ├── Sl2.txt ├── Sl20.txt ├── Sl21.txt ├── Sl22.txt ├── Sl23.txt ├── Sl24.txt ├── Sl25.txt ├── Sl26.txt ├── Sl27.txt ├── Sl28.txt ├── Sl29.txt ├── Sl3.txt ├── Sl30.txt ├── Sl31.txt ├── Sl4.txt ├── Sl5.txt ├── Sl6.txt ├── Sl7.txt ├── Sl8.txt └── Sl9.txt ├── doctest.h ├── fortran_wrappers.f90 ├── fortran_wrappers.h ├── generate_data_Cl.m ├── generate_data_Li.m ├── math ├── clausenBernoulli.m ├── clausenCheby.m ├── clausenMinimaxApprox.m ├── clausenWu.m ├── dilogCheby.m ├── dilogMinimaxApprox.m ├── dilogRelations.m ├── dilogRemezApprox.m ├── polylog.m ├── tetralogMinimaxApprox.m └── trilogMinimaxApprox.m ├── read_data.hpp ├── stopwatch.hpp ├── test.hpp ├── test_Cl.cpp ├── test_Cl1.cpp ├── test_Cl2.cpp ├── test_Cl3.cpp ├── test_Cl4.cpp ├── test_Cl5.cpp ├── test_Cl6.cpp ├── test_Li.cpp ├── test_Li2.cpp ├── test_Li3.cpp ├── test_Li4.cpp ├── test_Li5.cpp ├── test_Li6.cpp ├── test_Sl.cpp ├── test_eta.cpp ├── test_example.cpp ├── test_factorial.cpp ├── test_harmonic.cpp ├── test_log.cpp ├── test_version.cpp └── test_zeta.cpp /.clang-tidy: -------------------------------------------------------------------------------- 1 | Checks: > 2 | *, 3 | -*-avoid-c-arrays, 4 | -*-magic-numbers, 5 | -cppcoreguidelines-pro-bounds-constant-array-index, 6 | -google-explicit-constructor, 7 | -fuchsia-default-arguments-calls, 8 | -fuchsia-default-arguments-declarations, 9 | -fuchsia-overloaded-operator, 10 | -hicpp-explicit-conversions, 11 | -llvmlibc-*, 12 | -modernize-use-trailing-return-type, 13 | -readability-isolate-declaration, 14 | -------------------------------------------------------------------------------- /.github/workflows/coverage.yml: -------------------------------------------------------------------------------- 1 | name: coverage 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | coverage: 7 | name: Coverage 8 | runs-on: ubuntu-latest 9 | env: 10 | BUILD_TYPE: Release 11 | CC: gcc 12 | CFLAGS: --coverage 13 | CXX: g++ 14 | CXXFLAGS: --coverage 15 | FC: gfortran 16 | FCFLAGS: --coverage 17 | steps: 18 | - name: checkout 19 | uses: actions/checkout@v1 20 | - name: install dependencies 21 | run: sudo apt-get install lcov 22 | - name: cmake 23 | run: cmake . -DCMAKE_POLICY_DEFAULT_CMP0091=NEW -DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} 24 | - name: cmake build 25 | run: cmake --build . --config ${{ env.BUILD_TYPE }} 26 | - name: ctest 27 | run: ctest -T Test -T Coverage -C ${{ env.BUILD_TYPE }} 28 | env: 29 | CTEST_OUTPUT_ON_FAILURE: 1 30 | - name: Lcov 31 | run: lcov --directory . --capture --exclude '/usr/*' --exclude '*/test/*' --output-file=coverage.lcov 32 | - name: Coveralls 33 | uses: coverallsapp/github-action@v2 34 | with: 35 | file: coverage.lcov 36 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: test 2 | 3 | on: 4 | push: 5 | pull_request: 6 | 7 | jobs: 8 | test: 9 | 10 | runs-on: ${{ matrix.os }} 11 | 12 | strategy: 13 | matrix: 14 | os: [ubuntu-latest, macOS-latest] 15 | cxxflags: ["", "-Ofast -ffast-math"] 16 | 17 | steps: 18 | - uses: actions/checkout@v1 19 | - name: cmake 20 | run: cmake . 21 | env: 22 | CXXFLAGS: ${{ matrix.cxxflags }} 23 | - name: cmake build 24 | run: cmake --build . 25 | - name: ctest 26 | run: ctest 27 | env: 28 | CTEST_OUTPUT_ON_FAILURE: 1 29 | - name: cmake install 30 | run: cmake --install . --prefix $PWD/install 31 | -------------------------------------------------------------------------------- /CITATION.cff: -------------------------------------------------------------------------------- 1 | cff-version: 1.2.0 2 | message: "If you use this software, please cite it as below." 3 | authors: 4 | - family-names: "Voigt" 5 | given-names: "Alexander" 6 | orcid: "https://orcid.org/0000-0001-8963-6512" 7 | title: "Polylogarithm" 8 | version: 7.0.0 9 | date-released: 2024-03-15 10 | url: "https://github.com/Expander/polylogarithm" 11 | license: MIT 12 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | project(polylogarithm CXX C) 3 | 4 | if(NOT CMAKE_BUILD_TYPE) 5 | set(CMAKE_BUILD_TYPE Release) 6 | endif() 7 | 8 | set(CMAKE_CXX_STANDARD 11) 9 | set(CMAKE_CXX_STANDARD_REQUIRED YES) 10 | set(CMAKE_CXX_EXTENSIONS OFF) 11 | 12 | set(CMAKE_C_STANDARD 11) 13 | set(CMAKE_C_STANDARD_REQUIRED YES) 14 | set(CMAKE_C_EXTENSIONS OFF) 15 | 16 | include(GNUInstallDirs) 17 | include(CheckLanguage) 18 | check_language(Fortran) 19 | 20 | if(CMAKE_Fortran_COMPILER) 21 | enable_language(Fortran) 22 | set(CMAKE_Fortran_STANDARD 90) 23 | set(CMAKE_Fortran_STANDARD_REQUIRED YES) 24 | set(CMAKE_Fortran_EXTENSIONS OFF) 25 | add_compile_definitions(ENABLE_FORTRAN=1) 26 | else() 27 | message(STATUS "No Fortran support") 28 | endif() 29 | 30 | enable_testing() 31 | add_subdirectory(src) 32 | add_subdirectory(test) 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Alexander Voigt 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Polylogarithm 2 | ============= 3 | 4 | [![Build Status](https://github.com/Expander/polylogarithm/workflows/test/badge.svg)](https://github.com/Expander/polylogarithm/actions) 5 | [![Coverage Status](https://coveralls.io/repos/github/Expander/polylogarithm/badge.svg)](https://coveralls.io/github/Expander/polylogarithm) 6 | 7 | The Polylogarithm package provides C, C++ and Fortran implementations 8 | of various polylogarithms, including the real and complex dilogarithm, 9 | trilogarithm, and (Standard and Glaisher) Clausen functions. The 10 | implementations have been fully tested against the literature and many 11 | other implementations and are highly optimized for fast numerical 12 | evaluation. 13 | 14 | The package has no external dependencies, except for the C/C++/Fortran 15 | standard libraries. The implementations of the individual polylogarithm 16 | functions are distributed among different source code files, so 17 | individual source code files can be easily extracted and incorporated 18 | into existing projects. 19 | 20 | 21 | Example in C++ 22 | -------------- 23 | 24 | ```.cpp 25 | #include "Li.hpp" 26 | #include "Li2.hpp" 27 | #include "Li3.hpp" 28 | #include "Li4.hpp" 29 | #include "Li5.hpp" 30 | #include "Li6.hpp" 31 | #include 32 | 33 | int main() { 34 | using namespace polylogarithm; 35 | 36 | const double x = 1.0; 37 | const std::complex z(1.0, 1.0); 38 | 39 | // real polylogarithms for real arguments 40 | std::cout 41 | << "Li_2(" << x << ") = " << Li2(x) << '\n' 42 | << "Li_3(" << x << ") = " << Li3(x) << '\n' 43 | << "Li_4(" << x << ") = " << Li4(x) << '\n'; 44 | 45 | // complex polylogarithms for complex arguments 46 | std::cout 47 | << "Li_2(" << z << ") = " << Li2(z) << '\n' 48 | << "Li_3(" << z << ") = " << Li3(z) << '\n' 49 | << "Li_4(" << z << ") = " << Li4(z) << '\n' 50 | << "Li_5(" << z << ") = " << Li5(z) << '\n' 51 | << "Li_6(" << z << ") = " << Li6(z) << '\n' 52 | << "Li_10(" << z << ") = " << Li(10,z) << '\n'; 53 | } 54 | ``` 55 | 56 | Output: 57 | 58 | ``` 59 | Li_2(1) = 1.64493 60 | Li_3(1) = 1.20206 61 | Li_4(1) = 1.08232 62 | Li_2((1,1)) = (0.61685,1.46036) 63 | Li_3((1,1)) = (0.871159,1.26708) 64 | Li_4((1,1)) = (0.959319,1.13804) 65 | Li_5((1,1)) = (0.987467,1.06844) 66 | Li_6((1,1)) = (0.99615,1.03355) 67 | Li_10((1,1)) = (0.999962,1.00199) 68 | ``` 69 | 70 | 71 | Notes 72 | ----- 73 | 74 | The implementation of the real dilogarithm is an adaptation of 75 | [[arXiv:2201.01678](https://arxiv.org/abs/2201.01678)]. 76 | 77 | The implementation of the complex dilogarithm is inspired by the 78 | implementation in [SPheno](https://spheno.hepforge.org/). 79 | 80 | The implementation of the real trilogarithm is an adaptation of 81 | [[arXiv:2308.11619](https://arxiv.org/abs/2308.11619)]. 82 | 83 | The implementation of the general n-th order complex polylogarithm an 84 | adaptation of [[arXiv:2010.09860](https://arxiv.org/abs/2010.09860)]. 85 | 86 | 87 | Copying 88 | ------- 89 | 90 | Polylogarithm is licenced under the MIT License. 91 | -------------------------------------------------------------------------------- /examples/example.F90: -------------------------------------------------------------------------------- 1 | ! Compile as: 2 | ! 3 | ! gfortran example.F90 -I/include /lib/libpolylogarithm_fortran.a 4 | 5 | program example 6 | implicit none 7 | 8 | #include "polylogarithm/Cl2.fh" 9 | #include "polylogarithm/Cl3.fh" 10 | #include "polylogarithm/Cl4.fh" 11 | #include "polylogarithm/Cl5.fh" 12 | #include "polylogarithm/Cl6.fh" 13 | #include "polylogarithm/Li2.fh" 14 | #include "polylogarithm/Li3.fh" 15 | #include "polylogarithm/Li4.fh" 16 | #include "polylogarithm/Li5.fh" 17 | #include "polylogarithm/Li6.fh" 18 | 19 | double precision :: x 20 | double complex :: z 21 | 22 | x = 1.1D0 23 | z = dcmplx(1.1D0, 1.1D0) 24 | 25 | print *, 'dcl2(', x, ') = ', dcl2(x) 26 | print *, 'dcl3(', x, ') = ', dcl3(x) 27 | print *, 'dcl4(', x, ') = ', dcl4(x) 28 | print *, 'dcl5(', x, ') = ', dcl5(x) 29 | print *, 'dcl6(', x, ') = ', dcl6(x) 30 | print *, 'dli2(', x, ') = ', dli2(x) 31 | print *, 'dli3(', x, ') = ', dli3(x) 32 | print *, 'dli4(', x, ') = ', dli4(x) 33 | print *, 'cdli2(', z, ') = ', cdli2(z) 34 | print *, 'cdli3(', z, ') = ', cdli3(z) 35 | print *, 'cdli4(', z, ') = ', cdli4(z) 36 | print *, 'cdli5(', z, ') = ', cdli5(z) 37 | print *, 'cdli6(', z, ') = ', cdli6(z) 38 | 39 | end program example 40 | -------------------------------------------------------------------------------- /examples/example.c: -------------------------------------------------------------------------------- 1 | /* 2 | Compile as follows: 3 | 4 | gcc example.c -I/include /lib/libpolylogarithm_c.a -lm 5 | */ 6 | 7 | #include 8 | #include 9 | #include "polylogarithm/Cl2.h" 10 | #include "polylogarithm/Cl3.h" 11 | #include "polylogarithm/Cl4.h" 12 | #include "polylogarithm/Cl5.h" 13 | #include "polylogarithm/Cl6.h" 14 | #include "polylogarithm/Li2.h" 15 | #include "polylogarithm/Li3.h" 16 | #include "polylogarithm/Li4.h" 17 | #include "polylogarithm/Li5.h" 18 | #include "polylogarithm/Li6.h" 19 | 20 | int main() { 21 | const double x = 1.1; 22 | printf("cl2(%g) = %g\n", x, cl2(x)); 23 | printf("cl3(%g) = %g\n", x, cl3(x)); 24 | printf("cl4(%g) = %g\n", x, cl4(x)); 25 | printf("cl5(%g) = %g\n", x, cl5(x)); 26 | printf("cl6(%g) = %g\n", x, cl6(x)); 27 | printf("li2(%g) = %g\n", x, li2(x)); 28 | printf("li3(%g) = %g\n", x, li3(x)); 29 | printf("li4(%g) = %g\n", x, li4(x)); 30 | 31 | const double _Complex z = 1.1 + 1.1*I; 32 | printf("cli2(%g + %gi) = %g + %gi\n", creal(z), cimag(z), creal(cli2(z)), cimag(cli2(z))); 33 | printf("cli3(%g + %gi) = %g + %gi\n", creal(z), cimag(z), creal(cli3(z)), cimag(cli3(z))); 34 | printf("cli4(%g + %gi) = %g + %gi\n", creal(z), cimag(z), creal(cli4(z)), cimag(cli4(z))); 35 | printf("cli5(%g + %gi) = %g + %gi\n", creal(z), cimag(z), creal(cli5(z)), cimag(cli5(z))); 36 | printf("cli6(%g + %gi) = %g + %gi\n", creal(z), cimag(z), creal(cli6(z)), cimag(cli6(z))); 37 | } 38 | -------------------------------------------------------------------------------- /examples/example.cpp: -------------------------------------------------------------------------------- 1 | // Compile as follows: 2 | // 3 | // g++ examples/example.cpp -I/include /lib/libpolylogarithm_cpp.a 4 | 5 | #include 6 | #include 7 | #include "polylogarithm/Cl.hpp" 8 | #include "polylogarithm/Cl1.hpp" 9 | #include "polylogarithm/Cl2.hpp" 10 | #include "polylogarithm/Cl3.hpp" 11 | #include "polylogarithm/Cl4.hpp" 12 | #include "polylogarithm/Cl5.hpp" 13 | #include "polylogarithm/Cl6.hpp" 14 | #include "polylogarithm/Li.hpp" 15 | #include "polylogarithm/Li2.hpp" 16 | #include "polylogarithm/Li3.hpp" 17 | #include "polylogarithm/Li4.hpp" 18 | #include "polylogarithm/Li5.hpp" 19 | #include "polylogarithm/Li6.hpp" 20 | #include "polylogarithm/Sl.hpp" 21 | 22 | int main() { 23 | const double x = 1.1; 24 | std::cout << "Cl1(" << x << ") = " << polylogarithm::Cl1(x) << '\n'; 25 | std::cout << "Cl2(" << x << ") = " << polylogarithm::Cl2(x) << '\n'; 26 | std::cout << "Cl3(" << x << ") = " << polylogarithm::Cl3(x) << '\n'; 27 | std::cout << "Cl4(" << x << ") = " << polylogarithm::Cl4(x) << '\n'; 28 | std::cout << "Cl5(" << x << ") = " << polylogarithm::Cl5(x) << '\n'; 29 | std::cout << "Cl6(" << x << ") = " << polylogarithm::Cl6(x) << '\n'; 30 | std::cout << "Cl(10," << x << ") = " << polylogarithm::Cl(10,x) << '\n'; 31 | std::cout << "Li2(" << x << ") = " << polylogarithm::Li2(x) << '\n'; 32 | std::cout << "Li3(" << x << ") = " << polylogarithm::Li3(x) << '\n'; 33 | std::cout << "Li4(" << x << ") = " << polylogarithm::Li4(x) << '\n'; 34 | std::cout << "Li(10," << x << ") = " << polylogarithm::Li(10,x) << '\n'; 35 | std::cout << "Sl(10," << x << ") = " << polylogarithm::Sl(10,x) << '\n'; 36 | 37 | const std::complex z(1.1, 1.1); 38 | std::cout << "Li2(" << z << ") = " << polylogarithm::Li2(z) << '\n'; 39 | std::cout << "Li3(" << z << ") = " << polylogarithm::Li3(z) << '\n'; 40 | std::cout << "Li4(" << z << ") = " << polylogarithm::Li4(z) << '\n'; 41 | std::cout << "Li5(" << z << ") = " << polylogarithm::Li5(z) << '\n'; 42 | std::cout << "Li6(" << z << ") = " << polylogarithm::Li6(z) << '\n'; 43 | std::cout << "Li(10," << z << ") = " << polylogarithm::Li(10,z) << '\n'; 44 | } 45 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(c) 2 | add_subdirectory(cpp) 3 | add_subdirectory(fortran) 4 | 5 | add_library(polylogarithm INTERFACE) 6 | target_include_directories(polylogarithm 7 | INTERFACE 8 | ${CMAKE_CURRENT_SOURCE_DIR} 9 | ${CMAKE_CURRENT_SOURCE_DIR}/c 10 | ${CMAKE_CURRENT_SOURCE_DIR}/cpp 11 | ${CMAKE_CURRENT_SOURCE_DIR}/fortran 12 | ) 13 | target_link_libraries(polylogarithm 14 | INTERFACE 15 | polylogarithm_c 16 | polylogarithm_cpp 17 | polylogarithm_fortran 18 | ) 19 | set(HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/version.h) 20 | set_target_properties(polylogarithm 21 | PROPERTIES PUBLIC_HEADER "${HEADERS}") 22 | install( 23 | TARGETS 24 | polylogarithm 25 | polylogarithm_c 26 | polylogarithm_cpp 27 | polylogarithm_fortran 28 | PUBLIC_HEADER 29 | DESTINATION 30 | ${CMAKE_INSTALL_INCLUDEDIR}/polylogarithm 31 | ) 32 | -------------------------------------------------------------------------------- /src/c/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(polylogarithm_c 2 | Cl2.c 3 | Cl3.c 4 | Cl4.c 5 | Cl5.c 6 | Cl6.c 7 | Li2.c 8 | Li3.c 9 | Li4.c 10 | Li5.c 11 | Li6.c 12 | log.c 13 | ) 14 | 15 | target_include_directories(polylogarithm_c PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) 16 | set(C_HEADERS 17 | ${CMAKE_CURRENT_SOURCE_DIR}/Cl2.h 18 | ${CMAKE_CURRENT_SOURCE_DIR}/Cl3.h 19 | ${CMAKE_CURRENT_SOURCE_DIR}/Cl4.h 20 | ${CMAKE_CURRENT_SOURCE_DIR}/Cl5.h 21 | ${CMAKE_CURRENT_SOURCE_DIR}/Cl6.h 22 | ${CMAKE_CURRENT_SOURCE_DIR}/Li2.h 23 | ${CMAKE_CURRENT_SOURCE_DIR}/Li3.h 24 | ${CMAKE_CURRENT_SOURCE_DIR}/Li4.h 25 | ${CMAKE_CURRENT_SOURCE_DIR}/Li5.h 26 | ${CMAKE_CURRENT_SOURCE_DIR}/Li6.h 27 | ) 28 | set_target_properties(polylogarithm_c PROPERTIES PUBLIC_HEADER "${C_HEADERS}") 29 | -------------------------------------------------------------------------------- /src/c/Cl2.h: -------------------------------------------------------------------------------- 1 | /* ==================================================================== 2 | * This file is part of Polylogarithm. 3 | * 4 | * Polylogarithm is licenced under the MIT License. 5 | * ==================================================================== */ 6 | 7 | #pragma once 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | /** real Clausen function Cl_2 with double precision */ 14 | double cl2(double); 15 | 16 | /** real Clausen function Cl_2 with long double precision */ 17 | long double cl2l(long double); 18 | 19 | #ifdef __cplusplus 20 | } 21 | #endif 22 | -------------------------------------------------------------------------------- /src/c/Cl3.h: -------------------------------------------------------------------------------- 1 | /* ==================================================================== 2 | * This file is part of Polylogarithm. 3 | * 4 | * Polylogarithm is licenced under the MIT License. 5 | * ==================================================================== */ 6 | 7 | #pragma once 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | /** real Clausen function Cl_3 with double precision */ 14 | double cl3(double); 15 | 16 | /** real Clausen function Cl_3 with long double precision */ 17 | long double cl3l(long double); 18 | 19 | #ifdef __cplusplus 20 | } 21 | #endif 22 | -------------------------------------------------------------------------------- /src/c/Cl4.h: -------------------------------------------------------------------------------- 1 | /* ==================================================================== 2 | * This file is part of Polylogarithm. 3 | * 4 | * Polylogarithm is licenced under the MIT License. 5 | * ==================================================================== */ 6 | 7 | #pragma once 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | /** real Clausen function Cl_4 with double precision */ 14 | double cl4(double); 15 | 16 | /** real Clausen function Cl_4 with long double precision */ 17 | long double cl4l(long double); 18 | 19 | #ifdef __cplusplus 20 | } 21 | #endif 22 | -------------------------------------------------------------------------------- /src/c/Cl5.h: -------------------------------------------------------------------------------- 1 | /* ==================================================================== 2 | * This file is part of Polylogarithm. 3 | * 4 | * Polylogarithm is licenced under the MIT License. 5 | * ==================================================================== */ 6 | 7 | #pragma once 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | /** real Clausen function Cl_5 with double precision */ 14 | double cl5(double); 15 | 16 | /** real Clausen function Cl_5 with long double precision */ 17 | long double cl5l(long double); 18 | 19 | #ifdef __cplusplus 20 | } 21 | #endif 22 | -------------------------------------------------------------------------------- /src/c/Cl6.h: -------------------------------------------------------------------------------- 1 | /* ==================================================================== 2 | * This file is part of Polylogarithm. 3 | * 4 | * Polylogarithm is licenced under the MIT License. 5 | * ==================================================================== */ 6 | 7 | #pragma once 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | /** real Clausen function Cl_6 with double precision */ 14 | double cl6(double); 15 | 16 | /** real Clausen function Cl_6 with long double precision */ 17 | long double cl6l(long double); 18 | 19 | #ifdef __cplusplus 20 | } 21 | #endif 22 | -------------------------------------------------------------------------------- /src/c/Li2.h: -------------------------------------------------------------------------------- 1 | /* ==================================================================== 2 | * This file is part of Polylogarithm. 3 | * 4 | * Polylogarithm is licenced under the MIT License. 5 | * ==================================================================== */ 6 | 7 | #pragma once 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | /** real polylogarithm with n=2 (dilogarithm) with single precision */ 14 | float li2f(float); 15 | 16 | /** real polylogarithm with n=2 (dilogarithm) with double precision */ 17 | double li2(double); 18 | 19 | /** real polylogarithm with n=2 (dilogarithm) with long double precision */ 20 | long double li2l(long double); 21 | 22 | /** complex polylogarithm with n=2 (dilogarithm) with single precision */ 23 | float _Complex cli2f(float _Complex); 24 | 25 | /** complex polylogarithm with n=2 (dilogarithm) with double precision */ 26 | double _Complex cli2(double _Complex); 27 | 28 | /** complex polylogarithm with n=2 (dilogarithm) with long double precision */ 29 | long double _Complex cli2l(long double _Complex); 30 | 31 | #ifdef __cplusplus 32 | } 33 | #endif 34 | -------------------------------------------------------------------------------- /src/c/Li3.h: -------------------------------------------------------------------------------- 1 | /* ==================================================================== 2 | * This file is part of Polylogarithm. 3 | * 4 | * Polylogarithm is licenced under the MIT License. 5 | * ==================================================================== */ 6 | 7 | #pragma once 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | /** real polylogarithm with n=3 (trilogarithm) with double precision */ 14 | double li3(double); 15 | 16 | /** complex polylogarithm with n=3 (trilogarithm) with double precision */ 17 | double _Complex cli3(double _Complex); 18 | 19 | /** complex polylogarithm with n=3 (trilogarithm) with long double precision */ 20 | long double _Complex cli3l(long double _Complex); 21 | 22 | #ifdef __cplusplus 23 | } 24 | #endif 25 | -------------------------------------------------------------------------------- /src/c/Li4.h: -------------------------------------------------------------------------------- 1 | /* ==================================================================== 2 | * This file is part of Polylogarithm. 3 | * 4 | * Polylogarithm is licenced under the MIT License. 5 | * ==================================================================== */ 6 | 7 | #pragma once 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | /** real polylogarithm with n=4 (tetralogarithm) with double precision */ 14 | double li4(double); 15 | 16 | /** complex polylogarithm with n=4 (tetralogarithm) with double precision */ 17 | double _Complex cli4(double _Complex); 18 | 19 | /** complex polylogarithm with n=4 (tetralogarithm) with long double precision */ 20 | long double _Complex cli4l(long double _Complex); 21 | 22 | #ifdef __cplusplus 23 | } 24 | #endif 25 | -------------------------------------------------------------------------------- /src/c/Li5.h: -------------------------------------------------------------------------------- 1 | /* ==================================================================== 2 | * This file is part of Polylogarithm. 3 | * 4 | * Polylogarithm is licenced under the MIT License. 5 | * ==================================================================== */ 6 | 7 | #pragma once 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | /** complex polylogarithm with n=5 with double precision */ 14 | double _Complex cli5(double _Complex); 15 | 16 | /** complex polylogarithm with n=5 with long double precision */ 17 | long double _Complex cli5l(long double _Complex); 18 | 19 | #ifdef __cplusplus 20 | } 21 | #endif 22 | -------------------------------------------------------------------------------- /src/c/Li6.h: -------------------------------------------------------------------------------- 1 | /* ==================================================================== 2 | * This file is part of Polylogarithm. 3 | * 4 | * Polylogarithm is licenced under the MIT License. 5 | * ==================================================================== */ 6 | 7 | #pragma once 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | /** complex polylogarithm with n=4 with double precision */ 14 | double _Complex cli6(double _Complex); 15 | 16 | /** complex polylogarithm with n=4 with long double precision */ 17 | long double _Complex cli6l(long double _Complex); 18 | 19 | #ifdef __cplusplus 20 | } 21 | #endif 22 | -------------------------------------------------------------------------------- /src/c/log.c: -------------------------------------------------------------------------------- 1 | /* ==================================================================== 2 | * This file is part of Polylogarithm. 3 | * 4 | * Polylogarithm is licenced under the MIT License. 5 | * ==================================================================== */ 6 | 7 | #include 8 | #include 9 | 10 | 11 | double _Complex clog1p(double _Complex z) 12 | { 13 | const double _Complex u = 1.0 + z; 14 | const double rz = creal(u); 15 | const double iz = cimag(u); 16 | 17 | if (rz == 1.0 && iz == 0.0) { 18 | return z; 19 | } else if (rz <= 0.0) { 20 | return clog(u); 21 | } 22 | 23 | return clog(u)*(z/(u - 1.0)); 24 | } 25 | 26 | 27 | long double _Complex clog1pl(long double _Complex z) 28 | { 29 | const long double _Complex u = 1.0L + z; 30 | const long double rz = creall(u); 31 | const long double iz = cimagl(u); 32 | 33 | if (rz == 1.0L && iz == 0.0L) { 34 | return z; 35 | } else if (rz <= 0.0L) { 36 | return clogl(u); 37 | } 38 | 39 | return clogl(u)*(z/(u - 1.0L)); 40 | } 41 | 42 | 43 | /** 44 | * returns log(z) for complex z 45 | * @param z complex argument 46 | * @note Points on the branch cut are treated differently from std::log(z): 47 | * Points with Re(z) < 0 and Im(z) == -0.0 are mapped to Im(z) == 0.0 48 | * @return log(z) 49 | */ 50 | double _Complex pos_clog(double _Complex z) 51 | { 52 | const double rz = creal(z); 53 | const double iz = cimag(z); 54 | 55 | if (iz == 0.0 && rz > 0.0) { 56 | return log(rz); 57 | } else if (iz == 0.0) { 58 | return log(-rz) + I*3.1415926535897932; 59 | } 60 | 61 | return clog(z); 62 | } 63 | 64 | 65 | /** 66 | * returns log(z) for complex z 67 | * @param z complex argument 68 | * @note Points on the branch cut are treated differently from std::log(z): 69 | * Points with Re(z) < 0 and Im(z) == -0.0 are mapped to Im(z) == 0.0 70 | * @return log(z) 71 | */ 72 | long double _Complex pos_clogl(long double _Complex z) 73 | { 74 | const long double rz = creall(z); 75 | const long double iz = cimagl(z); 76 | 77 | if (iz == 0.0L && rz > 0.0L) { 78 | return logl(rz); 79 | } else if (iz == 0.0L) { 80 | return logl(-rz) + I*3.14159265358979323846264338327950288L; 81 | } 82 | 83 | return clogl(z); 84 | } 85 | -------------------------------------------------------------------------------- /src/c/log.h: -------------------------------------------------------------------------------- 1 | /* ==================================================================== 2 | * This file is part of Polylogarithm. 3 | * 4 | * Polylogarithm is licenced under the MIT License. 5 | * ==================================================================== */ 6 | 7 | #pragma once 8 | 9 | /** returns clog(1 + z) with double precision */ 10 | double _Complex clog1p(double _Complex z); 11 | 12 | /** returns clog(1 + z) with long double precision */ 13 | long double _Complex clog1pl(long double _Complex z); 14 | 15 | /** returns clog(z) with double precision */ 16 | double _Complex pos_clog(double _Complex z); 17 | 18 | /** returns clog(z) with long double precision */ 19 | long double _Complex pos_clogl(long double _Complex z); 20 | -------------------------------------------------------------------------------- /src/cpp/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(polylogarithm_cpp 2 | Cl.cpp 3 | Cl1.cpp 4 | Cl2.cpp 5 | Cl3.cpp 6 | Cl4.cpp 7 | Cl5.cpp 8 | Cl6.cpp 9 | eta.cpp 10 | factorial.cpp 11 | harmonic.cpp 12 | Li.cpp 13 | Li2.cpp 14 | Li3.cpp 15 | Li4.cpp 16 | Li5.cpp 17 | Li6.cpp 18 | Sl.cpp 19 | zeta.cpp 20 | ) 21 | target_include_directories(polylogarithm_cpp PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) 22 | set(CXX_HEADERS 23 | ${CMAKE_CURRENT_SOURCE_DIR}/Cl.hpp 24 | ${CMAKE_CURRENT_SOURCE_DIR}/Cl1.hpp 25 | ${CMAKE_CURRENT_SOURCE_DIR}/Cl2.hpp 26 | ${CMAKE_CURRENT_SOURCE_DIR}/Cl3.hpp 27 | ${CMAKE_CURRENT_SOURCE_DIR}/Cl4.hpp 28 | ${CMAKE_CURRENT_SOURCE_DIR}/Cl5.hpp 29 | ${CMAKE_CURRENT_SOURCE_DIR}/Cl6.hpp 30 | ${CMAKE_CURRENT_SOURCE_DIR}/Li.hpp 31 | ${CMAKE_CURRENT_SOURCE_DIR}/Li2.hpp 32 | ${CMAKE_CURRENT_SOURCE_DIR}/Li3.hpp 33 | ${CMAKE_CURRENT_SOURCE_DIR}/Li4.hpp 34 | ${CMAKE_CURRENT_SOURCE_DIR}/Li5.hpp 35 | ${CMAKE_CURRENT_SOURCE_DIR}/Li6.hpp 36 | ${CMAKE_CURRENT_SOURCE_DIR}/Sl.hpp 37 | ) 38 | set_target_properties(polylogarithm_cpp PROPERTIES PUBLIC_HEADER "${CXX_HEADERS}") 39 | -------------------------------------------------------------------------------- /src/cpp/Cl.hpp: -------------------------------------------------------------------------------- 1 | // ==================================================================== 2 | // This file is part of Polylogarithm. 3 | // 4 | // Polylogarithm is licenced under the MIT License. 5 | // ==================================================================== 6 | 7 | #pragma once 8 | #include 9 | 10 | namespace polylogarithm { 11 | 12 | /// Standard Clausen function for arbitrary integer n 13 | double Cl(int64_t, double); 14 | 15 | } // namespace polylogarithm 16 | -------------------------------------------------------------------------------- /src/cpp/Cl1.cpp: -------------------------------------------------------------------------------- 1 | // ==================================================================== 2 | // This file is part of Polylogarithm. 3 | // 4 | // Polylogarithm is licenced under the MIT License. 5 | // ==================================================================== 6 | 7 | #include "Cl1.hpp" 8 | #include 9 | #include 10 | 11 | namespace polylogarithm { 12 | 13 | /** 14 | * @brief Clausen function \f$\operatorname{Cl}_1(\theta) = \operatorname{Re}(\operatorname{Li}_1(e^{i\theta}))\f$ 15 | * @param x real angle 16 | * @return \f$\operatorname{Cl}_1(\theta)\f$ 17 | * @author Alexander Voigt 18 | */ 19 | double Cl1(double x) noexcept 20 | { 21 | const double PI = 3.14159265358979324; 22 | const double PI2 = 2*PI; 23 | 24 | if (x < 0) { 25 | x = -x; 26 | } 27 | 28 | if (x >= PI2) { 29 | x = std::fmod(x, PI2); 30 | } 31 | 32 | if (x > PI) { 33 | const double p0 = 6.28125; 34 | const double p1 = 0.0019353071795864769253; 35 | x = (p0 - x) + p1; 36 | } 37 | 38 | if (x == 0) { 39 | return std::numeric_limits::infinity(); 40 | } 41 | 42 | return -std::log(2.0*std::sin(0.5*x)); 43 | } 44 | 45 | } // namespace polylogarithm 46 | -------------------------------------------------------------------------------- /src/cpp/Cl1.hpp: -------------------------------------------------------------------------------- 1 | // ==================================================================== 2 | // This file is part of Polylogarithm. 3 | // 4 | // Polylogarithm is licenced under the MIT License. 5 | // ==================================================================== 6 | 7 | #pragma once 8 | 9 | namespace polylogarithm { 10 | 11 | /// Clausen function with n=1 12 | double Cl1(double) noexcept; 13 | 14 | } // namespace polylogarithm 15 | -------------------------------------------------------------------------------- /src/cpp/Cl2.hpp: -------------------------------------------------------------------------------- 1 | // ==================================================================== 2 | // This file is part of Polylogarithm. 3 | // 4 | // Polylogarithm is licenced under the MIT License. 5 | // ==================================================================== 6 | 7 | #pragma once 8 | 9 | namespace polylogarithm { 10 | 11 | /// Clausen function with n=2 12 | double Cl2(double) noexcept; 13 | 14 | /// Clausen function with n=2 with long double precision 15 | long double Cl2(long double) noexcept; 16 | 17 | } // namespace polylogarithm 18 | -------------------------------------------------------------------------------- /src/cpp/Cl3.hpp: -------------------------------------------------------------------------------- 1 | // ==================================================================== 2 | // This file is part of Polylogarithm. 3 | // 4 | // Polylogarithm is licenced under the MIT License. 5 | // ==================================================================== 6 | 7 | #pragma once 8 | 9 | namespace polylogarithm { 10 | 11 | /// Clausen function with n=3 12 | double Cl3(double) noexcept; 13 | 14 | /// Clausen function with n=3 with long double precision 15 | long double Cl3(long double) noexcept; 16 | 17 | } // namespace polylogarithm 18 | -------------------------------------------------------------------------------- /src/cpp/Cl4.hpp: -------------------------------------------------------------------------------- 1 | // ==================================================================== 2 | // This file is part of Polylogarithm. 3 | // 4 | // Polylogarithm is licenced under the MIT License. 5 | // ==================================================================== 6 | 7 | #pragma once 8 | 9 | namespace polylogarithm { 10 | 11 | /// Clausen function with n=4 12 | double Cl4(double) noexcept; 13 | 14 | /// Clausen function with n=4 with long double precision 15 | long double Cl4(long double) noexcept; 16 | 17 | } // namespace polylogarithm 18 | -------------------------------------------------------------------------------- /src/cpp/Cl5.hpp: -------------------------------------------------------------------------------- 1 | // ==================================================================== 2 | // This file is part of Polylogarithm. 3 | // 4 | // Polylogarithm is licenced under the MIT License. 5 | // ==================================================================== 6 | 7 | #pragma once 8 | 9 | namespace polylogarithm { 10 | 11 | /// Clausen function with n=5 12 | double Cl5(double) noexcept; 13 | 14 | /// Clausen function with n=5 with long double precision 15 | long double Cl5(long double) noexcept; 16 | 17 | } // namespace polylogarithm 18 | -------------------------------------------------------------------------------- /src/cpp/Cl6.hpp: -------------------------------------------------------------------------------- 1 | // ==================================================================== 2 | // This file is part of Polylogarithm. 3 | // 4 | // Polylogarithm is licenced under the MIT License. 5 | // ==================================================================== 6 | 7 | #pragma once 8 | 9 | namespace polylogarithm { 10 | 11 | /// Clausen function with n=6 12 | double Cl6(double) noexcept; 13 | 14 | /// Clausen function with n=6 with long double precision 15 | long double Cl6(long double) noexcept; 16 | 17 | } // namespace polylogarithm 18 | -------------------------------------------------------------------------------- /src/cpp/Li.hpp: -------------------------------------------------------------------------------- 1 | // ==================================================================== 2 | // This file is part of Polylogarithm. 3 | // 4 | // Polylogarithm is licenced under the MIT License. 5 | // ==================================================================== 6 | 7 | #pragma once 8 | #include 9 | #include 10 | 11 | namespace polylogarithm { 12 | 13 | /// complex polylogarithm for arbitrary integer n 14 | std::complex Li(int64_t n, const std::complex&) noexcept; 15 | 16 | } // namespace polylogarithm 17 | -------------------------------------------------------------------------------- /src/cpp/Li2.hpp: -------------------------------------------------------------------------------- 1 | // ==================================================================== 2 | // This file is part of Polylogarithm. 3 | // 4 | // Polylogarithm is licenced under the MIT License. 5 | // ==================================================================== 6 | 7 | #pragma once 8 | #include 9 | 10 | namespace polylogarithm { 11 | 12 | /// real polylogarithm with n=2 (dilogarithm) with single precision 13 | float Li2(float) noexcept; 14 | 15 | /// real polylogarithm with n=2 (dilogarithm) with double precision 16 | double Li2(double) noexcept; 17 | 18 | /// real polylogarithm with n=2 (dilogarithm) with long double precision 19 | long double Li2(long double) noexcept; 20 | 21 | /// complex polylogarithm with n=2 (dilogarithm) with single precision 22 | std::complex Li2(const std::complex&) noexcept; 23 | 24 | /// complex polylogarithm with n=2 (dilogarithm) with double precision 25 | std::complex Li2(const std::complex&) noexcept; 26 | 27 | /// complex polylogarithm with n=2 (dilogarithm) with long double precision 28 | std::complex Li2(const std::complex&) noexcept; 29 | 30 | } // namespace polylogarithm 31 | -------------------------------------------------------------------------------- /src/cpp/Li3.hpp: -------------------------------------------------------------------------------- 1 | // ==================================================================== 2 | // This file is part of Polylogarithm. 3 | // 4 | // Polylogarithm is licenced under the MIT License. 5 | // ==================================================================== 6 | 7 | #pragma once 8 | #include 9 | 10 | namespace polylogarithm { 11 | 12 | /// real polylogarithm with n=3 (trilogarithm) 13 | double Li3(double) noexcept; 14 | 15 | /// complex polylogarithm with n=3 (trilogarithm) 16 | std::complex Li3(const std::complex&) noexcept; 17 | 18 | /// complex polylogarithm with n=3 (trilogarithm) with long double precision 19 | std::complex Li3(const std::complex&) noexcept; 20 | 21 | } // namespace polylogarithm 22 | -------------------------------------------------------------------------------- /src/cpp/Li4.hpp: -------------------------------------------------------------------------------- 1 | // ==================================================================== 2 | // This file is part of Polylogarithm. 3 | // 4 | // Polylogarithm is licenced under the MIT License. 5 | // ==================================================================== 6 | 7 | #pragma once 8 | #include 9 | 10 | namespace polylogarithm { 11 | 12 | /// real polylogarithm with n=4 13 | double Li4(double) noexcept; 14 | 15 | /// complex polylogarithm with n=4 16 | std::complex Li4(const std::complex&) noexcept; 17 | 18 | /// complex polylogarithm with n=4 with long double precision 19 | std::complex Li4(const std::complex&) noexcept; 20 | 21 | } // namespace polylogarithm 22 | -------------------------------------------------------------------------------- /src/cpp/Li5.hpp: -------------------------------------------------------------------------------- 1 | // ==================================================================== 2 | // This file is part of Polylogarithm. 3 | // 4 | // Polylogarithm is licenced under the MIT License. 5 | // ==================================================================== 6 | 7 | #pragma once 8 | #include 9 | 10 | namespace polylogarithm { 11 | 12 | /// complex polylogarithm with n=5 13 | std::complex Li5(const std::complex&) noexcept; 14 | 15 | /// complex polylogarithm with n=5 with long double precision 16 | std::complex Li5(const std::complex&) noexcept; 17 | 18 | } // namespace polylogarithm 19 | -------------------------------------------------------------------------------- /src/cpp/Li6.hpp: -------------------------------------------------------------------------------- 1 | // ==================================================================== 2 | // This file is part of Polylogarithm. 3 | // 4 | // Polylogarithm is licenced under the MIT License. 5 | // ==================================================================== 6 | 7 | #pragma once 8 | #include 9 | 10 | namespace polylogarithm { 11 | 12 | /// complex polylogarithm with n=5 13 | std::complex Li6(const std::complex&) noexcept; 14 | 15 | /// complex polylogarithm with n=5 with long double precision 16 | std::complex Li6(const std::complex&) noexcept; 17 | 18 | } // namespace polylogarithm 19 | -------------------------------------------------------------------------------- /src/cpp/Sl.hpp: -------------------------------------------------------------------------------- 1 | // ==================================================================== 2 | // This file is part of Polylogarithm. 3 | // 4 | // Polylogarithm is licenced under the MIT License. 5 | // ==================================================================== 6 | 7 | #pragma once 8 | #include 9 | 10 | namespace polylogarithm { 11 | 12 | /// Glaisher-Clausen function for arbitrary integer n 13 | double Sl(int64_t, double); 14 | 15 | } // namespace polylogarithm 16 | -------------------------------------------------------------------------------- /src/cpp/eta.cpp: -------------------------------------------------------------------------------- 1 | // ==================================================================== 2 | // This file is part of Polylogarithm. 3 | // 4 | // Polylogarithm is licenced under the MIT License. 5 | // ==================================================================== 6 | 7 | #include "eta.hpp" 8 | #include 9 | 10 | namespace polylogarithm { 11 | 12 | namespace { 13 | 14 | // Table[PolyLog[n,-1], {n,1,54}] 15 | const double NEG_ETA[54] = { 16 | -0.69314718055994531, -0.82246703342411322, -0.90154267736969571, 17 | -0.94703282949724592, -0.97211977044690931, -0.98555109129743510, 18 | -0.99259381992283028, -0.99623300185264790, -0.99809429754160533, 19 | -0.99903950759827157, -0.99951714349806075, -0.99975768514385819, 20 | -0.99987854276326512, -0.99993917034597972, -0.99996955121309924, 21 | -0.99998476421490611, -0.99999237829204101, -0.99999618786961011, 22 | -0.99999809350817168, -0.99999904661158152, -0.99999952325821554, 23 | -0.99999976161323082, -0.99999988080131844, -0.99999994039889239, 24 | -0.99999997019885696, -0.99999998509923200, -0.99999999254955048, 25 | -0.99999999627475340, -0.99999999813736942, -0.99999999906868228, 26 | -0.9999999995343403 , -0.9999999997671699 , -0.9999999998835849 , 27 | -0.9999999999417924 , -0.9999999999708962 , -0.9999999999854481 , 28 | -0.9999999999927240 , -0.9999999999963620 , -0.9999999999981810 , 29 | -0.9999999999990905 , -0.9999999999995453 , -0.9999999999997726 , 30 | -0.9999999999998863 , -0.9999999999999432 , -0.9999999999999716 , 31 | -0.9999999999999858 , -0.9999999999999929 , -0.9999999999999964 , 32 | -0.9999999999999982 , -0.9999999999999991 , -0.9999999999999996 , 33 | -0.9999999999999998 , -0.9999999999999999 , -0.9999999999999999 34 | }; 35 | 36 | // Table[PolyLog[-2n+1,-1], {n,1,109}] 37 | const double NEG_ETA_NEG_N[] = { 38 | -0.25, 0.125 , -0.25 , 1.0625 , 39 | -7.75 , 86.375 , -1365.25 , 40 | 29049.03125 , -800572.75 , 2.7741322625e7 , 41 | -1.18052913025e9 , 6.05239800516875e10 , -3.67941677853775e12 , 42 | 2.6170760990658388e014, -2.1531418140800295e016, 2.0288775575173016e018, 43 | -2.1708009902623771e020, 2.6173826968455815e022, -3.5324148876863878e024, 44 | 5.3042033406864907e026, -8.8138218364311577e028, 1.6128065107490779e031, 45 | -3.2355470001722734e033, 7.0876727476537493e035, -1.6890450341293966e038, 46 | 4.3639690731216831e040, -1.2185998827061261e043, 3.6670584803153006e045, 47 | -1.1859898526302099e048, 4.1120769493584015e050, -1.5249042436787620e053, 48 | 6.0349693196941307e055, -2.5437161764210696e058, 1.1396923802632288e061, 49 | -5.4180861064753979e063, 2.7283654799994374e066, -1.4529750514918543e069, 50 | 8.1705519371067450e071, -4.8445781606678368e074, 3.0246694206649519e077, 51 | -1.9858807961690493e080, 1.3694474620720087e083, -9.9070382984295808e085, 52 | 7.5103780796592646e088, -5.9598418264260881e091, 4.9455988887500020e094, 53 | -4.2873596927020241e097, 3.8791952037716163e100, -3.6600317773156342e103, 54 | 3.5978775704117284e106, -3.6818662617467813e109, 3.9192743066421374e112, 55 | -4.3363921885063858e115, 4.9833162711780838e118, -5.9438653020209606e121, 56 | 7.3533439019770134e124, -9.4293465716973561e127, 1.2525196404154548e131, 57 | -1.7223787163994400e134, 2.4505178680729537e137, -3.6051616659014189e140, 58 | 5.4813803836499771e143, -8.6083892012122616e146, 1.3957139354298160e150, 59 | -2.3350508860591630e153, 4.0291297374794860e156, -7.1669946227411534e159, 60 | 1.3136385964069363e163, -2.4799083462304252e166, 4.8198083696385558e169, 61 | -9.6400031196958281e172, 1.9833611905147644e176, -4.1959717912682865e179, 62 | 9.1243724595750010e182, -2.0386902382464212e186, 4.6786408066350383e189, 63 | -1.1024400389046488e193, 2.6662916424238258e196, -6.6165585014771755e199, 64 | 1.6841726974970032e203, -4.3957474813006951e206, 1.1760766011899571e210, 65 | -3.2245094671360478e213, 9.0570855543185808e216, -2.6054618058433054e220, 66 | 7.6741449421726560e223, -2.3136880427961752e227, 7.1382598572408242e230, 67 | -2.2530900128907084e234, 7.2736404696018159e237, -2.4010608416429639e241, 68 | 8.1026279414941787e244, -2.7945745738098571e248, 9.8485095122481192e251, 69 | -3.5456055356238575e255, 1.3036999220919921e259, -4.8948166866453784e262, 70 | 1.8761736309852136e266, -7.3399918877807488e269, 2.9303136033539038e273, 71 | -1.1935494277949469e277, 4.9589310621971370e280, -2.1012240064879845e284, 72 | 9.0784179834777353e287, -3.9987113012775244e291, 1.7952380922182709e295, 73 | -8.2136799002055846e298, 3.8290431596908477e302, -1.8184610414701105e306 74 | }; 75 | 76 | constexpr bool is_even(int64_t n) noexcept { return n % 2 == 0; } 77 | 78 | } // anonymous namespace 79 | 80 | /// negative Dirichlet eta function 81 | double neg_eta(int64_t n) noexcept 82 | { 83 | if (n < 0) { 84 | if (is_even(n)) { 85 | return 0.0; 86 | } else if (-(1 + n)/2 < static_cast(sizeof(NEG_ETA_NEG_N)/sizeof(NEG_ETA_NEG_N[0]))) { 87 | return NEG_ETA_NEG_N[-(1 + n)/2]; 88 | } else if (is_even((1 - n)/2)) { 89 | return std::numeric_limits::infinity(); 90 | } else { 91 | return -std::numeric_limits::infinity(); 92 | } 93 | } else if (n == 0) { 94 | return -0.5; 95 | } else if (n <= static_cast(sizeof(NEG_ETA)/sizeof(NEG_ETA[0]))) { 96 | return NEG_ETA[n - 1]; 97 | } else { 98 | return -1.0; 99 | } 100 | } 101 | 102 | } // namespace polylogarithm 103 | -------------------------------------------------------------------------------- /src/cpp/eta.hpp: -------------------------------------------------------------------------------- 1 | // ==================================================================== 2 | // This file is part of Polylogarithm. 3 | // 4 | // Polylogarithm is licenced under the MIT License. 5 | // ==================================================================== 6 | 7 | #pragma once 8 | #include 9 | 10 | namespace polylogarithm { 11 | 12 | /// negative Dirichlet eta function for arbitrary integer n 13 | double neg_eta(int64_t) noexcept; 14 | 15 | } // namespace polylogarithm 16 | -------------------------------------------------------------------------------- /src/cpp/factorial.cpp: -------------------------------------------------------------------------------- 1 | // ==================================================================== 2 | // This file is part of Polylogarithm. 3 | // 4 | // Polylogarithm is licenced under the MIT License. 5 | // ==================================================================== 6 | 7 | #include "factorial.hpp" 8 | #include 9 | 10 | namespace polylogarithm { 11 | 12 | namespace { 13 | 14 | // 1/n! for integer n = 0, 1, 2, ... 15 | const double INVERSE_FACTORIALS[178] = { 16 | 1.0, 1.0, 0.5 , 1.6666666666666667e-001, 4.1666666666666667e-002, 17 | 8.3333333333333333e-003, 1.3888888888888889e-003, 1.9841269841269841e-004, 18 | 2.4801587301587302e-005, 2.7557319223985891e-006, 2.7557319223985891e-007, 19 | 2.5052108385441719e-008, 2.0876756987868099e-009, 1.6059043836821615e-010, 20 | 1.1470745597729725e-011, 7.6471637318198165e-013, 4.7794773323873853e-014, 21 | 2.8114572543455208e-015, 1.5619206968586226e-016, 8.2206352466243297e-018, 22 | 4.1103176233121649e-019, 1.9572941063391261e-020, 8.8967913924505733e-022, 23 | 3.8681701706306840e-023, 1.6117375710961183e-024, 6.4469502843844734e-026, 24 | 2.4795962632247975e-027, 9.1836898637955461e-029, 3.2798892370698379e-030, 25 | 1.1309962886447717e-031, 3.7699876288159056e-033, 1.2161250415535179e-034, 26 | 3.8003907548547436e-036, 1.1516335620771950e-037, 3.3871575355211618e-039, 27 | 9.6775929586318910e-041, 2.6882202662866364e-042, 7.2654601791530713e-044, 28 | 1.9119632050402819e-045, 4.9024697565135434e-047, 1.2256174391283858e-048, 29 | 2.9893108271424045e-050, 7.1174067312914393e-052, 1.6552108677421952e-053, 30 | 3.7618428812322618e-055, 8.3596508471828040e-057, 1.8173154015614791e-058, 31 | 3.8666285139605939e-060, 8.0554760707512373e-062, 1.6439747083165790e-063, 32 | 3.2879494166331581e-065, 6.4469596404571727e-067, 1.2397999308571486e-068, 33 | 2.3392451525606577e-070, 4.3319354677049217e-072, 7.8762463049180395e-074, 34 | 1.4064725544496499e-075, 2.4674957095607893e-077, 4.2543029475186023e-079, 35 | 7.2106829618959360e-081, 1.2017804936493227e-082, 1.9701319568021683e-084, 36 | 3.1776321883905941e-086, 5.0438606164930064e-088, 7.8810322132703225e-090, 37 | 1.2124664943492804e-091, 1.8370704459837582e-093, 2.7418961880354600e-095, 38 | 4.0322002765227352e-097, 5.8437685166996163e-099, 8.3482407381423090e-101, 39 | 1.1758085546679308e-102, 1.6330674370387928e-104, 2.2370786808750587e-106, 40 | 3.0230792984798090e-108, 4.0307723979730787e-110, 5.3036478920698404e-112, 41 | 6.8878544052855070e-114, 8.8305825708788551e-116, 1.1177952621365639e-117, 42 | 1.3972440776707049e-119, 1.7249926884823518e-121, 2.1036496201004290e-123, 43 | 2.5345176145788301e-125, 3.0172828744986072e-127, 3.5497445582336556e-129, 44 | 4.1276099514344832e-131, 4.7443792545223945e-133, 5.3913400619572665e-135, 45 | 6.0576854628733332e-137, 6.7307616254148146e-139, 7.3964413466096864e-141, 46 | 8.0396101593583548e-143, 8.6447421068369406e-145, 9.1965341562095113e-147, 47 | 9.6805622696942224e-149, 1.0083919030931482e-150, 1.0395792815393280e-152, 48 | 1.0607951852442123e-154, 1.0715102881254669e-156, 1.0715102881254669e-158, 49 | 1.0609012753717494e-160, 1.0400992895801465e-162, 1.0098051355147053e-164, 50 | 9.7096647645644744e-167, 9.2472997757756899e-169, 8.7238677129959339e-171, 51 | 8.1531473953233027e-173, 7.5492105512252803e-175, 6.9258812396562204e-177, 52 | 6.2962556724147458e-179, 5.6723024075808521e-181, 5.0645557210543322e-183, 53 | 4.4819077177471967e-185, 3.9314979980238567e-187, 3.4186939113250928e-189, 54 | 2.9471499235561145e-191, 2.5189315585949697e-193, 2.1346877615211607e-195, 55 | 1.7938552617824880e-197, 1.4948793848187400e-199, 1.2354375081146612e-201, 56 | 1.0126536951759518e-203, 8.2329568713492014e-206, 6.6394813478622592e-208, 57 | 5.3115850782898073e-210, 4.2155437129284185e-212, 3.3193257582113532e-214, 58 | 2.5932232486026197e-216, 2.0102505803121083e-218, 1.5463466002400833e-220, 59 | 1.1804172520916666e-222, 8.9425549400883835e-225, 6.7237255188634463e-227, 60 | 5.0177056110921241e-229, 3.7168189711793512e-231, 2.7329551258671700e-233, 61 | 1.9948577561074233e-235, 1.4455490986285676e-237, 1.0399633803083220e-239, 62 | 7.4283098593451574e-242, 5.2683048647837996e-244, 3.7100738484392955e-246, 63 | 2.5944572366708360e-248, 1.8017064143547472e-250, 1.2425561478308602e-252, 64 | 8.5106585467867134e-255, 5.7895636372698731e-257, 3.9118673224796440e-259, 65 | 2.6254143103890228e-261, 1.7502762069260152e-263, 1.1591233158450432e-265, 66 | 7.6258112884542314e-268, 4.9841903846106088e-270, 3.2364872627341615e-272, 67 | 2.0880562985381687e-274, 1.3384976272680569e-276, 8.5254625940640566e-279, 68 | 5.3958624013063649e-281, 3.3936241517650094e-283, 2.1210150948531309e-285, 69 | 1.3174006800330005e-287, 8.1321029631666700e-290, 4.9890202228016380e-292, 70 | 3.0420855017083159e-294, 1.8436881828535248e-296, 1.1106555318394728e-298, 71 | 6.6506319271824716e-301, 3.9587094804657569e-303, 2.3424316452460100e-305, 72 | 1.3779009677917706e-307, 8.0579003964431028e-310, 4.6848258118855249e-312, 73 | 2.7079917987777601e-314, 1.5563171257343449e-316, 8.8932407184819707e-319, 74 | 5.0529776809556651e-321, 2.8547896502574379e-323 75 | }; 76 | 77 | } // anonymous namespace 78 | 79 | /// negative Dirichlet eta function 80 | double inv_fac(int64_t n) noexcept 81 | { 82 | if (n < 0) { 83 | return std::numeric_limits::quiet_NaN(); 84 | } else if (n < static_cast(sizeof(INVERSE_FACTORIALS)/sizeof(INVERSE_FACTORIALS[0]))) { 85 | return INVERSE_FACTORIALS[n]; 86 | } else { 87 | return 0.0; 88 | } 89 | } 90 | 91 | } // namespace polylogarithm 92 | -------------------------------------------------------------------------------- /src/cpp/factorial.hpp: -------------------------------------------------------------------------------- 1 | // ==================================================================== 2 | // This file is part of Polylogarithm. 3 | // 4 | // Polylogarithm is licenced under the MIT License. 5 | // ==================================================================== 6 | 7 | #pragma once 8 | #include 9 | 10 | namespace polylogarithm { 11 | 12 | /// returns 1/n! for n >= 0 13 | double inv_fac(int64_t) noexcept; 14 | 15 | } // namespace polylogarithm 16 | -------------------------------------------------------------------------------- /src/cpp/harmonic.cpp: -------------------------------------------------------------------------------- 1 | // ==================================================================== 2 | // This file is part of Polylogarithm. 3 | // 4 | // Polylogarithm is licenced under the MIT License. 5 | // ==================================================================== 6 | 7 | #include "harmonic.hpp" 8 | #include 9 | #include 10 | 11 | namespace polylogarithm { 12 | 13 | namespace { 14 | 15 | /// digamma for integer n > 0, following 16 | /// [K.S. Kölbig: Programs for computing the logarithm of the gamma 17 | /// function, and the digamma function, for complex argument, Computer 18 | /// Physics Communications, Volume 4, Issue 2, 1972, Pages 221-226, ISSN 19 | /// 0010-4655, https://doi.org/10.1016/0010-4655(72)90012-4] 20 | double digamma(int64_t n) noexcept 21 | { 22 | // Table[BernoulliB[2n]/(2 n), {n,1,8}] 23 | const double c[] = { 24 | 0.083333333333333333, -0.0083333333333333333, 0.0039682539682539683, 25 | -0.0041666666666666667, 0.0075757575757575758, -0.021092796092796093, 26 | 0.083333333333333333, -0.44325980392156863 27 | }; 28 | 29 | if (n <= 0) { 30 | return std::numeric_limits::quiet_NaN(); 31 | } 32 | 33 | double res = 0; 34 | 35 | // map potentially small n to n >= 7 36 | if (n < 7) { // recurrence formula 37 | for (int64_t nu = 1; nu < 7 - n; ++nu) { 38 | res -= 1.0/(n + nu); 39 | } 40 | res -= 1.0/n; 41 | n = 7.0; 42 | } 43 | 44 | const double t = 1.0/n; 45 | const double t2 = t*t; 46 | 47 | return res + std::log(n) - 0.5*t 48 | - t2*(c[0] + t2*(c[1] + t2*(c[2] + t2*(c[3] + t2*(c[4] + t2*(c[5] + t2*(c[6] + t2*c[7]))))))); 49 | } 50 | 51 | } // anonymous namespace 52 | 53 | /// harmonic number n 54 | double harmonic(int64_t n) noexcept 55 | { 56 | if (n <= 0) { 57 | return std::numeric_limits::quiet_NaN(); 58 | } else if (n < 20) { 59 | double sum = 1; 60 | for (int64_t k = 2; k <= n; ++k) { 61 | sum += 1.0/k; 62 | } 63 | return sum; 64 | } else { 65 | const double eulergamma = 0.57721566490153286; 66 | return eulergamma + digamma(n + 1); 67 | } 68 | } 69 | 70 | } // namespace polylogarithm 71 | -------------------------------------------------------------------------------- /src/cpp/harmonic.hpp: -------------------------------------------------------------------------------- 1 | // ==================================================================== 2 | // This file is part of Polylogarithm. 3 | // 4 | // Polylogarithm is licenced under the MIT License. 5 | // ==================================================================== 6 | 7 | #pragma once 8 | #include 9 | 10 | namespace polylogarithm { 11 | 12 | /// Harmonic number 13 | double harmonic(int64_t) noexcept; 14 | 15 | } // namespace polylogarithm 16 | -------------------------------------------------------------------------------- /src/cpp/horner.hpp: -------------------------------------------------------------------------------- 1 | // ==================================================================== 2 | // This file is part of Polylogarithm. 3 | // 4 | // Polylogarithm is licenced under the MIT License. 5 | // ==================================================================== 6 | 7 | #pragma once 8 | 9 | #include 10 | 11 | namespace polylogarithm { 12 | 13 | template 14 | T horner(T x, const T (&c)[N]) noexcept 15 | { 16 | T p = c[N - 1]; 17 | for (int i = N - 2; i >= 0; --i) { 18 | p = p*x + c[i]; 19 | } 20 | return p; 21 | } 22 | 23 | 24 | template 25 | std::complex horner(const std::complex& z, const T (&coeffs)[N]) noexcept 26 | { 27 | static_assert(0 <= Nstart && Nstart < N && N >= 2, "invalid array bounds"); 28 | 29 | const T rz = std::real(z); 30 | const T iz = std::imag(z); 31 | const T r = rz + rz; 32 | const T s = std::norm(z); 33 | T a = coeffs[N - 1], b = coeffs[N - 2]; 34 | 35 | for (int i = N - 3; i >= Nstart; --i) { 36 | const T t = a; 37 | a = b + r*a; 38 | b = coeffs[i] - s*t; 39 | } 40 | 41 | return { rz*a + b, iz*a }; 42 | } 43 | 44 | } // namespace polylogarithm 45 | -------------------------------------------------------------------------------- /src/cpp/log.hpp: -------------------------------------------------------------------------------- 1 | // ==================================================================== 2 | // This file is part of Polylogarithm. 3 | // 4 | // Polylogarithm is licenced under the MIT License. 5 | // ==================================================================== 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | 12 | namespace polylogarithm { 13 | 14 | 15 | /// returns log(1 + z) for complex z 16 | template 17 | std::complex log1p(const std::complex& z) noexcept 18 | { 19 | const std::complex u = T(1) + z; 20 | 21 | if (std::real(u) == T(1) && std::imag(u) == T(0)) { 22 | return z; 23 | } else if (std::real(u) <= T(0)) { 24 | return std::log(u); 25 | } 26 | 27 | return std::log(u)*(z/(u - T(1))); 28 | } 29 | 30 | 31 | /** 32 | * returns log(z) for complex z 33 | * @param z complex argument 34 | * @note Points on the branch cut are treated differently from std::log(z): 35 | * Points with Re(z) < 0 and Im(z) == -0.0 are mapped to Im(z) == 0.0 36 | * @return log(z) 37 | */ 38 | template 39 | std::complex pos_log(const std::complex& z) noexcept 40 | { 41 | if (std::imag(z) == T(0) && std::real(z) > T(0)) { 42 | return { std::log(std::real(z)), T(0) }; 43 | } else if (std::imag(z) == T(0)) { 44 | return { std::log(-std::real(z)), 4*std::atan(T(1)) }; 45 | } 46 | 47 | return std::log(z); 48 | } 49 | 50 | 51 | } // namespace polylogarithm 52 | -------------------------------------------------------------------------------- /src/cpp/zeta.cpp: -------------------------------------------------------------------------------- 1 | // ==================================================================== 2 | // This file is part of Polylogarithm. 3 | // 4 | // Polylogarithm is licenced under the MIT License. 5 | // ==================================================================== 6 | 7 | #include "zeta.hpp" 8 | #include 9 | #include 10 | 11 | namespace polylogarithm { 12 | 13 | namespace { 14 | 15 | // zeta(n) for n = 2,...,33 16 | const double ZETAS_POS[32] = { 17 | 1.6449340668482264, 1.2020569031595943, 1.0823232337111382, 18 | 1.0369277551433699, 1.0173430619844491, 1.0083492773819228, 19 | 1.0040773561979443, 1.0020083928260822, 1.0009945751278181, 20 | 1.0004941886041195, 1.0002460865533080, 1.0001227133475785, 21 | 1.0000612481350587, 1.0000305882363070, 1.0000152822594087, 22 | 1.0000076371976379, 1.0000038172932650, 1.0000019082127166, 23 | 1.0000009539620339, 1.0000004769329868, 1.0000002384505027, 24 | 1.0000001192199260, 1.0000000596081891, 1.0000000298035035, 25 | 1.0000000149015548, 1.0000000074507118, 1.0000000037253340, 26 | 1.0000000018626597, 1.0000000009313274, 1.0000000004656629, 27 | 1.0000000002328312, 1.0000000001164155 28 | }; 29 | 30 | // zeta(1 - 2n) for n = 1,...,130, i.e. zeta(-1), zeta(-3), zeta(-5), ... 31 | const double ZETAS_NEG[130] = { 32 | -8.3333333333333333e-02, 8.3333333333333333e-03, -3.9682539682539683e-03, 33 | 4.1666666666666667e-03, -7.5757575757575758e-03, 2.1092796092796093e-02, 34 | -8.3333333333333333e-02, 4.4325980392156863e-01, -3.0539543302701197e000, 35 | 2.6456212121212121e001, -2.8146014492753623e002, 3.6075105463980464e003, 36 | -5.4827583333333333e004, 9.7493682385057471e005, -2.0052695796688079e007, 37 | 4.7238486772162990e008, -1.2635724795916667e010, 3.8087931125245369e011, 38 | -1.2850850499305083e013, 4.8241448354850170e014, -2.0040310656516253e016, 39 | 9.1677436031953308e017, -4.5979888343656503e019, 2.5180471921451096e021, 40 | -1.5001733492153929e023, 9.6899578874635941e024, -6.7645882379292821e026, 41 | 5.0890659468662290e028, -4.1147288792557979e030, 3.5666582095375556e032, 42 | -3.3066089876577577e034, 3.2715634236478716e036, -3.4473782558278054e038, 43 | 3.8614279832705259e040, -4.5892974432454332e042, 5.7775386342770432e044, 44 | -7.6919858759507135e046, 1.0813635449971655e049, -1.6029364522008965e051, 45 | 2.5019479041560463e053, -4.1067052335810212e055, 7.0798774408494581e057, 46 | -1.2804546887939509e060, 2.4267340392333524e062, -4.8143218874045769e064, 47 | 9.9875574175727531e066, -2.1645634868435186e069, 4.8962327039620553e071, 48 | -1.1549023923963520e074, 2.8382249570693707e076, -7.2612008803606716e078, 49 | 1.9323514233419812e081, -5.3450160425288624e083, 1.5356028846422423e086, 50 | -4.5789872682265798e088, 1.4162025212194809e091, -4.5400652296092655e093, 51 | 1.5076656758807860e096, -5.1830949148264564e098, 1.8435647427256529e101, 52 | -6.7805554753090959e103, 2.5773326702754605e106, -1.0119112875704598e109, 53 | 4.1016346161542292e111, -1.7155244534032019e114, 7.4003425705269094e116, 54 | -3.2909225357054443e119, 1.5079831534164771e122, -7.1169879188254549e124, 55 | 3.4580429141577772e127, -1.7290907606676748e130, 8.8936991695032969e132, 56 | -4.7038470619636015e135, 2.5571938231060206e138, -1.4284067500443528e141, 57 | 8.1952152218313783e143, -4.8276485422727372e146, 2.9189612374770324e149, 58 | -1.8108932162568904e152, 1.1523577220021169e155, -7.5192311951981770e157, 59 | 5.0294016576411050e160, -3.4473420444477677e163, 2.4207458645868515e166, 60 | -1.7409465920377677e169, 1.2819489863482243e172, -9.6624121108560918e174, 61 | 7.4526910304300896e177, -5.8808393311674371e180, 4.7462718654907615e183, 62 | -3.9169132594772825e186, 3.3045071443226032e189, -2.8492890550994583e192, 63 | 2.5103329345077587e195, -2.2593901995475253e198, 2.0769138004287608e201, 64 | -1.9494732174927259e204, 1.8680731471265914e207, -1.8270752662814577e210, 65 | 1.8235386322595677e213, -1.8568690810125945e216, 1.9287189851195602e219, 66 | -2.0431170460286448e222, 2.2068411644527846e225, -2.4300821796490274e228, 67 | 2.7274887879083470e231, -3.1197421573755085e234, 3.6358938724282600e237, 68 | -4.3168300030760883e240, 5.2204244879387200e243, -6.4292606949769305e246, 69 | 8.0623033870130844e249, -1.0292714737903011e253, 1.3375329699780524e256, 70 | -1.7689480902797380e259, 2.3806479018092397e262, -3.2597127947194185e265, 71 | 4.5404962371601213e268, -6.4328575193147851e271, 9.2687048675749311e274, 72 | -1.3579619500285181e278, 2.0227839736049322e281, -3.0629906992208336e284, 73 | 4.7143085300742652e287, -7.3741045871355758e290, 1.1720962767050827e294, 74 | -1.8928866644685657e297, 3.1055517596048927e300, -5.1754977470366798e303, 75 | 8.7601563446229215e306 76 | }; 77 | 78 | constexpr bool is_even(int64_t n) noexcept { return n % 2 == 0; } 79 | 80 | } // anonymous namespace 81 | 82 | /// Riemann zeta function for integer arguments 83 | double zeta(int64_t n) noexcept 84 | { 85 | if (n < 0) { 86 | if (is_even(n)) { 87 | return 0.0; 88 | } else if (-(1 + n)/2 < static_cast(sizeof(ZETAS_NEG)/sizeof(ZETAS_NEG[0]))) { 89 | return ZETAS_NEG[-(1 + n)/2]; 90 | } else if (is_even((1 - n)/2)) { 91 | return std::numeric_limits::infinity(); 92 | } else { 93 | return -std::numeric_limits::infinity(); 94 | } 95 | } else if (n == 0) { 96 | return -0.5; 97 | } else if (n == 1) { 98 | return std::numeric_limits::infinity(); 99 | } else if ((n - 2) < static_cast(sizeof(ZETAS_POS)/sizeof(ZETAS_POS[0]))) { 100 | return ZETAS_POS[n - 2]; 101 | } 102 | 103 | return 1.0/(1.0 - std::pow(0.5, n)); 104 | } 105 | 106 | } // namespace polylogarithm 107 | -------------------------------------------------------------------------------- /src/cpp/zeta.hpp: -------------------------------------------------------------------------------- 1 | // ==================================================================== 2 | // This file is part of Polylogarithm. 3 | // 4 | // Polylogarithm is licenced under the MIT License. 5 | // ==================================================================== 6 | 7 | #pragma once 8 | #include 9 | 10 | namespace polylogarithm { 11 | 12 | /// Riemann zeta function for arbitrary integer n 13 | double zeta(int64_t) noexcept; 14 | 15 | } // namespace polylogarithm 16 | -------------------------------------------------------------------------------- /src/fortran/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | if(CMAKE_Fortran_COMPILER) 2 | add_library(polylogarithm_fortran 3 | Cl2.f90 4 | Cl3.f90 5 | Cl4.f90 6 | Cl5.f90 7 | Cl6.f90 8 | Li2.f90 9 | Li3.f90 10 | Li4.f90 11 | Li5.f90 12 | Li6.f90 13 | log.f90 14 | ) 15 | target_include_directories(polylogarithm_fortran PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) 16 | set(FORTRAN_HEADERS 17 | ${CMAKE_CURRENT_SOURCE_DIR}/Cl2.fh 18 | ${CMAKE_CURRENT_SOURCE_DIR}/Cl3.fh 19 | ${CMAKE_CURRENT_SOURCE_DIR}/Cl4.fh 20 | ${CMAKE_CURRENT_SOURCE_DIR}/Cl5.fh 21 | ${CMAKE_CURRENT_SOURCE_DIR}/Cl6.fh 22 | ${CMAKE_CURRENT_SOURCE_DIR}/Li2.fh 23 | ${CMAKE_CURRENT_SOURCE_DIR}/Li3.fh 24 | ${CMAKE_CURRENT_SOURCE_DIR}/Li4.fh 25 | ${CMAKE_CURRENT_SOURCE_DIR}/Li5.fh 26 | ${CMAKE_CURRENT_SOURCE_DIR}/Li6.fh 27 | ) 28 | set_target_properties(polylogarithm_fortran PROPERTIES PUBLIC_HEADER "${FORTRAN_HEADERS}") 29 | else() 30 | add_library(polylogarithm_fortran INTERFACE) 31 | endif() 32 | -------------------------------------------------------------------------------- /src/fortran/Cl2.f90: -------------------------------------------------------------------------------- 1 | !********************************************************************* 2 | ! This file is part of Polylogarithm. 3 | ! 4 | ! Polylogarithm is licenced under the MIT License. 5 | !********************************************************************* 6 | 7 | !********************************************************************* 8 | !> @brief Clausen function \f$\operatorname{Cl}_2(\theta) = \operatorname{Im}(\operatorname{Li}_2(e^{i\theta}))\f$ 9 | !> @param x real angle 10 | !> @return \f$\operatorname{Cl}_2(\theta)\f$ 11 | !> @author Alexander Voigt 12 | !> Implemented as rational function approximation. 13 | !********************************************************************* 14 | 15 | double precision function dcl2(x) 16 | implicit none 17 | double precision :: x, y, z, z2, z4, p, q, p0, p1, sgn 18 | double precision, parameter :: PI = 3.14159265358979324D0 19 | double precision, parameter :: PI2 = 2*PI, PIH = PI/2, PI28 = PI*PI/8 20 | double precision, parameter :: cp(4) = (/ & 21 | 1.3888888888888889D-2, & 22 | -4.3286930203743071D-4, & 23 | 3.2779814789973427D-6, & 24 | -3.6001540369575084D-9 /) 25 | double precision, parameter :: cq(4) = (/ & 26 | 1.0000000000000000D+0, & 27 | -3.6166589746694121D-2, & 28 | 3.6015827281202639D-4, & 29 | -8.3646182842184428D-7 /) 30 | double precision, parameter :: cr(6) = (/ & 31 | 6.4005702446195512D-1, & 32 | -2.0641655351338783D-1, & 33 | 2.4175305223497718D-2, & 34 | -1.2355955287855728D-3, & 35 | 2.5649833551291124D-5, & 36 | -1.4783829128773320D-7 /) 37 | double precision, parameter :: cs(6) = (/ & 38 | 1.0000000000000000D+0, & 39 | -2.5299102015666356D-1, & 40 | 2.2148751048467057D-2, & 41 | -7.8183920462457496D-4, & 42 | 9.5432542196310670D-6, & 43 | -1.8184302880448247D-8 /) 44 | 45 | sgn = 1 46 | 47 | if (x .lt. 0) then 48 | x = -x 49 | sgn = -1 50 | endif 51 | 52 | if (x .ge. PI2) then 53 | x = mod(x, PI2) 54 | endif 55 | 56 | if (x .gt. PI) then 57 | p0 = 6.28125D0 58 | p1 = 0.0019353071795864769253D0 59 | x = (p0 - x) + p1 60 | sgn = -sgn 61 | endif 62 | 63 | if (x .eq. 0) then 64 | dcl2 = x 65 | elseif (x .eq. PI) then 66 | dcl2 = 0 67 | elseif (x .lt. PIH) then 68 | y = x*x 69 | z = y*y 70 | p = cp(1) + y * cp(2) + z * (cp(3) + y * cp(4)) 71 | q = cq(1) + y * cq(2) + z * (cq(3) + y * cq(4)) 72 | dcl2 = sgn*x*(1 - log(x) + y*p/q) 73 | else 74 | y = PI - x 75 | z = y*y - PI28 76 | z2 = z*z 77 | z4 = z2*z2 78 | p = cr(1) + z * cr(2) + z2 * (cr(3) + z * cr(4)) + & 79 | z4 * (cr(5) + z * cr(6)) 80 | q = cs(1) + z * cs(2) + z2 * (cs(3) + z * cs(4)) + & 81 | z4 * (cs(5) + z * cs(6)) 82 | dcl2 = sgn*y*p/q 83 | endif 84 | 85 | end function dcl2 86 | -------------------------------------------------------------------------------- /src/fortran/Cl2.fh: -------------------------------------------------------------------------------- 1 | !********************************************************************* 2 | ! This file is part of Polylogarithm. 3 | ! 4 | ! Polylogarithm is licenced under the MIT License. 5 | !********************************************************************* 6 | 7 | ! real Clausen function Cl_2 with double precision 8 | double precision :: dcl2 9 | -------------------------------------------------------------------------------- /src/fortran/Cl3.f90: -------------------------------------------------------------------------------- 1 | !********************************************************************* 2 | ! This file is part of Polylogarithm. 3 | ! 4 | ! Polylogarithm is licenced under the MIT License. 5 | !********************************************************************* 6 | 7 | !********************************************************************* 8 | !> @brief Clausen function \f$\operatorname{Cl}_3(\theta) = \operatorname{Re}(\operatorname{Li}_3(e^{i\theta}))\f$ 9 | !> @param x real angle 10 | !> @return \f$\operatorname{Cl}_3(\theta)\f$ 11 | !> @author Alexander Voigt 12 | !> Implemented as rational function approximation. 13 | !********************************************************************* 14 | 15 | double precision function dcl3(x) 16 | implicit none 17 | double precision :: x, y, z, z2, z4, p, q, p0, p1 18 | double precision, parameter :: PI = 3.14159265358979324D0 19 | double precision, parameter :: PI2 = 2*PI, PIH = PI/2, PI28 = PI*PI/8 20 | double precision, parameter :: zeta3 = 1.2020569031595943D0 21 | double precision, parameter :: cp(4) = (/ & 22 | -7.5000000000000001D-1, & 23 | 1.5707637881835541D-2, & 24 | -3.5426736843494423D-5, & 25 | -2.4408931585123682D-7 /) 26 | double precision, parameter :: cq(4) = (/ & 27 | 1.0000000000000000D+0, & 28 | -2.5573146805410089D-2, & 29 | 1.5019774853075050D-4, & 30 | -1.0648552418111624D-7 /) 31 | double precision, parameter :: cr(6) = (/ & 32 | -4.9017024647634973D-1, & 33 | 4.1559155224660940D-1, & 34 | -7.9425531417806701D-2, & 35 | 5.9420152260602943D-3, & 36 | -1.8302227163540190D-4, & 37 | 1.8027408929418533D-6 /) 38 | double precision, parameter :: cs(6) = (/ & 39 | 1.0000000000000000D+0, & 40 | -1.9495887541644712D-1, & 41 | 1.2059410236484074D-2, & 42 | -2.5235889467301620D-4, & 43 | 1.0199322763377861D-6, & 44 | 1.9612106499469264D-9 /) 45 | 46 | if (x .lt. 0) then 47 | x = -x 48 | endif 49 | 50 | if (x .ge. PI2) then 51 | x = mod(x, PI2) 52 | endif 53 | 54 | if (x .gt. PI) then 55 | p0 = 6.28125D0 56 | p1 = 0.0019353071795864769253D0 57 | x = (p0 - x) + p1 58 | endif 59 | 60 | if (x .eq. 0) then 61 | dcl3 = zeta3 62 | elseif (x .lt. PIH) then 63 | y = x*x 64 | z = y*y 65 | p = cp(1) + y * cp(2) + z * (cp(3) + y * cp(4)) 66 | q = cq(1) + y * cq(2) + z * (cq(3) + y * cq(4)) 67 | dcl3 = zeta3 + y*(p/q + log(x)/2) 68 | else 69 | y = PI - x 70 | z = y*y - PI28 71 | z2 = z*z 72 | z4 = z2*z2 73 | p = cr(1) + z * cr(2) + z2 * (cr(3) + z * cr(4)) + & 74 | z4 * (cr(5) + z * cr(6)) 75 | q = cs(1) + z * cs(2) + z2 * (cs(3) + z * cs(4)) + & 76 | z4 * (cs(5) + z * cs(6)) 77 | dcl3 = p/q 78 | endif 79 | 80 | end function dcl3 81 | -------------------------------------------------------------------------------- /src/fortran/Cl3.fh: -------------------------------------------------------------------------------- 1 | !********************************************************************* 2 | ! This file is part of Polylogarithm. 3 | ! 4 | ! Polylogarithm is licenced under the MIT License. 5 | !********************************************************************* 6 | 7 | ! real Clausen function Cl_3 with double precision 8 | double precision :: dcl3 9 | -------------------------------------------------------------------------------- /src/fortran/Cl4.f90: -------------------------------------------------------------------------------- 1 | !********************************************************************* 2 | ! This file is part of Polylogarithm. 3 | ! 4 | ! Polylogarithm is licenced under the MIT License. 5 | !********************************************************************* 6 | 7 | !********************************************************************* 8 | !> @brief Clausen function \f$\operatorname{Cl}_4(\theta) = \operatorname{Im}(\operatorname{Li}_4(e^{i\theta}))\f$ 9 | !> @param x real angle 10 | !> @return \f$\operatorname{Cl}_4(\theta)\f$ 11 | !> @author Alexander Voigt 12 | !> Implemented as rational function approximation. 13 | !********************************************************************* 14 | 15 | double precision function dcl4(x) 16 | implicit none 17 | double precision :: x, y, z, z2, z4, p, q, p0, p1, sgn 18 | double precision, parameter :: PI = 3.14159265358979324D0 19 | double precision, parameter :: PI2 = 2*PI, PIH = PI/2, PI28 = PI*PI/8 20 | double precision, parameter :: zeta3 = 1.2020569031595943D0 21 | double precision, parameter :: cp(4) = (/ & 22 | -3.0555555555555556D-1, & 23 | 6.0521392328447206D-3, & 24 | -1.9587493942041528D-5, & 25 | -3.1137343767030358D-8 /) 26 | double precision, parameter :: cq(4) = (/ & 27 | 1.0000000000000000D+0, & 28 | -2.2079728398400851D-2, & 29 | 1.0887447112236682D-4, & 30 | -6.1847621370547954D-8 /) 31 | double precision, parameter :: cr(6) = (/ & 32 | 7.6223911686491336D-1, & 33 | -2.4339587368267260D-1, & 34 | 2.8715364937979943D-2, & 35 | -1.5368612510964667D-3, & 36 | 3.6261044225761673D-5, & 37 | -2.8557977333851308D-7 /) 38 | double precision, parameter :: cs(6) = (/ & 39 | 1.0000000000000000D+0, & 40 | -1.7465715261403233D-1, & 41 | 9.5439417991615653D-3, & 42 | -1.7325070821666274D-4, & 43 | 5.9283675098376635D-7, & 44 | 9.4127575773361230D-10 /) 45 | 46 | sgn = 1 47 | 48 | if (x .lt. 0) then 49 | x = -x 50 | sgn = -1 51 | endif 52 | 53 | if (x .ge. PI2) then 54 | x = mod(x, PI2) 55 | endif 56 | 57 | if (x .gt. PI) then 58 | p0 = 6.28125D0 59 | p1 = 0.0019353071795864769253D0 60 | x = (p0 - x) + p1 61 | sgn = -sgn 62 | endif 63 | 64 | if (x .eq. 0) then 65 | dcl4 = x 66 | elseif (x .eq. PI) then 67 | dcl4 = 0 68 | elseif (x .lt. PIH) then 69 | y = x*x 70 | z = y*y 71 | p = cp(1) + y * cp(2) + z * (cp(3) + y * cp(4)) 72 | q = cq(1) + y * cq(2) + z * (cq(3) + y * cq(4)) 73 | dcl4 = sgn*x*(zeta3 + y*(p/q + log(x)/6)) 74 | else 75 | y = PI - x 76 | z = y*y - PI28 77 | z2 = z*z 78 | z4 = z2*z2 79 | p = cr(1) + z * cr(2) + z2 * (cr(3) + z * cr(4)) + & 80 | z4 * (cr(5) + z * cr(6)) 81 | q = cs(1) + z * cs(2) + z2 * (cs(3) + z * cs(4)) + & 82 | z4 * (cs(5) + z * cs(6)) 83 | dcl4 = sgn*y*p/q 84 | endif 85 | 86 | end function dcl4 87 | -------------------------------------------------------------------------------- /src/fortran/Cl4.fh: -------------------------------------------------------------------------------- 1 | !********************************************************************* 2 | ! This file is part of Polylogarithm. 3 | ! 4 | ! Polylogarithm is licenced under the MIT License. 5 | !********************************************************************* 6 | 7 | ! real Clausen function Cl_4 with double precision 8 | double precision :: dcl4 9 | -------------------------------------------------------------------------------- /src/fortran/Cl5.f90: -------------------------------------------------------------------------------- 1 | !********************************************************************* 2 | ! This file is part of Polylogarithm. 3 | ! 4 | ! Polylogarithm is licenced under the MIT License. 5 | !********************************************************************* 6 | 7 | !********************************************************************* 8 | !> @brief Clausen function \f$\operatorname{Cl}_5(\theta) = \operatorname{Re}(\operatorname{Li}_5(e^{i\theta}))\f$ 9 | !> @param x real angle 10 | !> @return \f$\operatorname{Cl}_5(\theta)\f$ 11 | !> @author Alexander Voigt 12 | !> Implemented as a rational function approximation. 13 | !********************************************************************* 14 | 15 | double precision function dcl5(x) 16 | implicit none 17 | double precision :: x, y, z, z2, z4, p, q, p0, p1 18 | double precision, parameter :: PI = 3.14159265358979324D0 19 | double precision, parameter :: PI2 = 2*PI, PIH = PI/2, PI28 = PI*PI/8 20 | double precision, parameter :: zeta5 = 1.0369277551433699D0 21 | double precision, parameter :: cp(4) = (/ & 22 | 1.0369277551433699D+0, & 23 | -6.1354800479984468D-1, & 24 | 9.4076401395712763D-2, & 25 | -9.4056155866704436D-4 /) 26 | double precision, parameter :: cq(5) = (/ & 27 | 1.0000000000000000D+0, & 28 | -1.2073698633244778D-2, & 29 | 1.3703409625482991D-5, & 30 | -1.9701280330628469D-9, & 31 | 2.1944550184416500D-11 /) 32 | double precision, parameter :: cr(6) = (/ & 33 | -4.5930112735784898D-1, & 34 | 4.3720705508867954D-1, & 35 | -7.5895226486465095D-2, & 36 | 5.2244176912488065D-3, & 37 | -1.5677716622013956D-4, & 38 | 1.6641624171748576D-6 /) 39 | double precision, parameter :: cs(6) = (/ & 40 | 1.0000000000000000D+0, & 41 | -1.2211486825401188D-1, & 42 | 3.8940070749313620D-3, & 43 | -2.2674805547074318D-5, & 44 | -7.4383354448335299D-8, & 45 | -3.4131758392216437D-10 /) 46 | 47 | if (x .lt. 0) then 48 | x = -x 49 | endif 50 | 51 | if (x .ge. PI2) then 52 | x = mod(x, PI2) 53 | endif 54 | 55 | if (x .gt. PI) then 56 | p0 = 6.28125D0 57 | p1 = 0.0019353071795864769253D0 58 | x = (p0 - x) + p1 59 | endif 60 | 61 | if (x .eq. 0) then 62 | dcl5 = zeta5 63 | elseif (x .lt. PIH) then 64 | y = x*x 65 | z = y*y 66 | p = cp(1) + y * cp(2) + z * (cp(3) + y * cp(4)) 67 | q = cq(1) + y * cq(2) + z * (cq(3) + y * cq(4) + z * cq(5)) 68 | dcl5 = p/q - 1.0D0/24*z*log(x); 69 | else 70 | y = PI - x 71 | z = y*y - PI28 72 | z2 = z*z 73 | z4 = z2*z2 74 | p = cr(1) + z * cr(2) + z2 * (cr(3) + z * cr(4)) + & 75 | z4 * (cr(5) + z * cr(6)) 76 | q = cs(1) + z * cs(2) + z2 * (cs(3) + z * cs(4)) + & 77 | z4 * (cs(5) + z * cs(6)) 78 | dcl5 = p/q 79 | endif 80 | 81 | end function dcl5 82 | -------------------------------------------------------------------------------- /src/fortran/Cl5.fh: -------------------------------------------------------------------------------- 1 | !********************************************************************* 2 | ! This file is part of Polylogarithm. 3 | ! 4 | ! Polylogarithm is licenced under the MIT License. 5 | !********************************************************************* 6 | 7 | ! real Clausen function Cl_5 with double precision 8 | double precision :: dcl5 9 | -------------------------------------------------------------------------------- /src/fortran/Cl6.f90: -------------------------------------------------------------------------------- 1 | !********************************************************************* 2 | ! This file is part of Polylogarithm. 3 | ! 4 | ! Polylogarithm is licenced under the MIT License. 5 | !********************************************************************* 6 | 7 | !********************************************************************* 8 | !> @brief Clausen function \f$\operatorname{Cl}_6(\theta) = \operatorname{Im}(\operatorname{Li}_6(e^{i\theta}))\f$ 9 | !> @param x real angle 10 | !> @return \f$\operatorname{Cl}_6(\theta)\f$ 11 | !> @author Alexander Voigt 12 | !> Implemented as rational function approximation. 13 | !********************************************************************* 14 | 15 | double precision function dcl6(x) 16 | implicit none 17 | double precision :: x, y, z, z2, z4, p, q, p0, p1, sgn 18 | double precision, parameter :: PI = 3.14159265358979324D0 19 | double precision, parameter :: PI2 = 2*PI, PIH = PI/2, PI28 = PI*PI/8 20 | double precision, parameter :: zeta3 = 1.2020569031595943D0 21 | double precision, parameter :: cp(4) = (/ & 22 | 1.0369277551433699D+0, & 23 | -2.0871954441071750D-1, & 24 | 2.0652251045312954D-2, & 25 | -1.3834381382568400D-4 /) 26 | double precision, parameter :: cq(4) = (/ & 27 | 1.0000000000000000D+0, & 28 | -8.0784096827362542D-3, & 29 | 5.8074568862993102D-6, & 30 | -5.1960620033050114D-10 /) 31 | double precision, parameter :: cr(5) = (/ & 32 | 7.9544504578027050D-1, & 33 | -1.9255025309738589D-1, & 34 | 1.5805208288846591D-2, & 35 | -5.4175380521534706D-4, & 36 | 6.7577493541009068D-6 /) 37 | double precision, parameter :: cs(6) = (/ & 38 | 1.0000000000000000D+0, & 39 | -7.0798422394109274D-2, & 40 | 7.1744189715634762D-4, & 41 | 3.9098747334347093D-6, & 42 | 3.5669441618295266D-8, & 43 | 2.5315391843409925D-10 /) 44 | 45 | sgn = 1 46 | 47 | if (x .lt. 0) then 48 | x = -x 49 | sgn = -1 50 | endif 51 | 52 | if (x .ge. PI2) then 53 | x = mod(x, PI2) 54 | endif 55 | 56 | if (x .gt. PI) then 57 | p0 = 6.28125D0 58 | p1 = 0.0019353071795864769253D0 59 | x = (p0 - x) + p1 60 | sgn = -sgn 61 | endif 62 | 63 | if (x .eq. 0) then 64 | dcl6 = x 65 | elseif (x .eq. PI) then 66 | dcl6 = 0 67 | elseif (x .lt. PIH) then 68 | y = x*x 69 | z = y*y 70 | p = cp(1) + y * cp(2) + z * (cp(3) + y * cp(4)) 71 | q = cq(1) + y * cq(2) + z * (cq(3) + y * cq(4)) 72 | dcl6 = sgn*x*(p/q - 1.0D0/120*z*log(x)) 73 | else 74 | y = PI - x 75 | z = y*y - PI28 76 | z2 = z*z 77 | z4 = z2*z2 78 | p = cr(1) + z * cr(2) + z2 * (cr(3) + z * cr(4)) + & 79 | z4 * cr(5) 80 | q = cs(1) + z * cs(2) + z2 * (cs(3) + z * cs(4)) + & 81 | z4 * (cs(5) + z * cs(6)) 82 | dcl6 = sgn*y*p/q 83 | endif 84 | 85 | end function dcl6 86 | -------------------------------------------------------------------------------- /src/fortran/Cl6.fh: -------------------------------------------------------------------------------- 1 | !********************************************************************* 2 | ! This file is part of Polylogarithm. 3 | ! 4 | ! Polylogarithm is licenced under the MIT License. 5 | !********************************************************************* 6 | 7 | ! real Clausen function Cl_6 with double precision 8 | double precision :: dcl6 9 | -------------------------------------------------------------------------------- /src/fortran/Li2.fh: -------------------------------------------------------------------------------- 1 | !********************************************************************* 2 | ! This file is part of Polylogarithm. 3 | ! 4 | ! Polylogarithm is licenced under the MIT License. 5 | !********************************************************************* 6 | 7 | ! real polylogarithm with n=2 (dilogarithm) with double precision 8 | double precision :: dli2 9 | 10 | ! complex polylogarithm with n=2 (dilogarithm) with double precision 11 | double complex :: cdli2 12 | -------------------------------------------------------------------------------- /src/fortran/Li3.fh: -------------------------------------------------------------------------------- 1 | !********************************************************************* 2 | ! This file is part of Polylogarithm. 3 | ! 4 | ! Polylogarithm is licenced under the MIT License. 5 | !********************************************************************* 6 | 7 | ! real polylogarithm with n=3 (trilogarithm) with double precision 8 | double precision :: dli3 9 | 10 | ! complex polylogarithm with n=3 (trilogarithm) with double precision 11 | double complex :: cdli3 12 | -------------------------------------------------------------------------------- /src/fortran/Li4.fh: -------------------------------------------------------------------------------- 1 | !********************************************************************* 2 | ! This file is part of Polylogarithm. 3 | ! 4 | ! Polylogarithm is licenced under the MIT License. 5 | !********************************************************************* 6 | 7 | ! real polylogarithm with n=4 with double precision 8 | double precision :: dli4 9 | 10 | ! complex polylogarithm with n=4 with double precision 11 | double complex :: cdli4 12 | -------------------------------------------------------------------------------- /src/fortran/Li5.f90: -------------------------------------------------------------------------------- 1 | !********************************************************************* 2 | ! This file is part of Polylogarithm. 3 | ! 4 | ! Polylogarithm is licenced under the MIT License. 5 | !********************************************************************* 6 | 7 | 8 | !********************************************************************* 9 | !> @brief Complex polylogarithm \f$\operatorname{Li}_5(z)\f$ 10 | !> @param z complex argument 11 | !> @return \f$\operatorname{Li}_5(z)\f$ 12 | !> @author Alexander Voigt 13 | !********************************************************************* 14 | double complex function cdli5(z) 15 | implicit none 16 | double complex :: z, u, u2, u4, u8, c4, lmz, rest, pos_cdlog 17 | double precision :: rz, iz, nz, pz, lnz, arg 18 | double precision, parameter :: PI = 3.1415926535897932D0 19 | double precision, parameter :: PI2 = 9.8696044010893586D0 20 | double precision, parameter :: PI4 = 97.409091034002437D0 21 | double precision, parameter :: zeta5 = 1.0369277551433699D0 22 | double precision, parameter :: c1 = 1.0823232337111382D0 ! zeta(4) 23 | double precision, parameter :: c2 = 0.60102845157979714D0 ! zeta(3)/2 24 | double precision, parameter :: c3 = 0.27415567780803774D0 25 | double precision, parameter :: c5 = -1D0/240 26 | double precision, parameter :: bf(19) = (/ & 27 | 1.0D0 , -15.0D0/32.0D0 , & 28 | 1.3953189300411523D-01, -2.8633777006172840D-02, & 29 | 4.0317412551440329D-03, -3.3985018004115226D-04, & 30 | 4.5445184621617666D-06, 2.3916808048569012D-06, & 31 | -1.2762692600122747D-07, -3.1628984306505932D-08, & 32 | 3.2848118445335192D-09, 4.7613713995660579D-10, & 33 | -8.0846898171909830D-11, -7.2387648587737207D-12, & 34 | 1.9439760115173968D-12, 1.0256978405977236D-13, & 35 | -4.6180551009884830D-14, -1.1535857196470580D-15, & 36 | 1.0903545401333394D-15 /) 37 | double precision, parameter :: cs(6) = (/ & 38 | -1.1574074074074074D-04, 2.0667989417989418D-07, & 39 | -1.0935444136502338D-09, 8.6986487449450412D-12, & 40 | -8.6899587861588824D-14, 1.0081254080218813D-15 /) 41 | 42 | rz = real(z) 43 | iz = aimag(z) 44 | 45 | if (iz .eq. 0) then 46 | if (rz .eq. 0) then 47 | cdli5 = dcmplx(rz, iz) 48 | return 49 | endif 50 | if (rz .eq. 1) then 51 | cdli5 = dcmplx(zeta5, iz) 52 | return 53 | endif 54 | if (rz .eq. -1) then 55 | cdli5 = dcmplx(-15*zeta5/16, iz) 56 | return 57 | endif 58 | endif 59 | 60 | nz = hypot(rz, iz) 61 | pz = datan2(iz, rz) 62 | lnz = log(nz) 63 | 64 | if (lnz**2 + pz**2 .lt. 1) then ! |log(z)| < 1 65 | u = dcmplx(lnz, pz) ! log(z) 66 | u2 = u**2 67 | c4 = (25D0/12 - pos_cdlog(-u))/24 68 | cdli5 = & 69 | zeta5 + u * c1 + & 70 | u2 * (c2 + u * c3 + & 71 | u2 * (c4 + u * c5 + & 72 | u2 * (cs(1) + & 73 | u2 * (cs(2) + & 74 | u2 * (cs(3) + & 75 | u2 * (cs(4) + & 76 | u2 * (cs(5) + & 77 | u2 * (cs(6))))))))) 78 | return 79 | endif 80 | 81 | if (nz .le. 1) then 82 | u = -pos_cdlog(1 - z) 83 | rest = 0 84 | else ! nz > 1 85 | if (pz .gt. 0) then 86 | arg = pz - PI 87 | else 88 | arg = pz + PI 89 | endif 90 | lmz = dcmplx(lnz, arg) ! log(-z) 91 | u = -pos_cdlog(1 - 1/z) 92 | rest = -lmz*(7*PI4 + lmz**2*(10*PI2 + 3*lmz**2))/360 93 | endif 94 | 95 | u2 = u**2 96 | u4 = u2**2 97 | u8 = u4**2 98 | 99 | cdli5 = & 100 | rest + & 101 | u*bf(1) + & 102 | u2*(bf(2) + u*bf(3)) + & 103 | u4*(bf(4) + u*bf(5) + u2*(bf(6) + u*bf(7))) + & 104 | u8*(bf(8) + u*bf(9) + u2*(bf(10) + u*bf(11)) + & 105 | u4*(bf(12) + u*bf(13) + u2*(bf(14) + u*bf(15)))) + & 106 | u8*u8*(bf(16) + u*bf(17) + u2*(bf(18) + u*bf(19))) 107 | 108 | end function cdli5 109 | -------------------------------------------------------------------------------- /src/fortran/Li5.fh: -------------------------------------------------------------------------------- 1 | !********************************************************************* 2 | ! This file is part of Polylogarithm. 3 | ! 4 | ! Polylogarithm is licenced under the MIT License. 5 | !********************************************************************* 6 | 7 | ! complex polylogarithm with n=5 with double precision 8 | double complex :: cdli5 9 | -------------------------------------------------------------------------------- /src/fortran/Li6.f90: -------------------------------------------------------------------------------- 1 | !********************************************************************* 2 | ! This file is part of Polylogarithm. 3 | ! 4 | ! Polylogarithm is licenced under the MIT License. 5 | !********************************************************************* 6 | 7 | 8 | !********************************************************************* 9 | !> @brief Complex polylogarithm \f$\operatorname{Li}_6(z)\f$ 10 | !> @param z complex argument 11 | !> @return \f$\operatorname{Li}_6(z)\f$ 12 | !> @author Alexander Voigt 13 | !********************************************************************* 14 | double complex function cdli6(z) 15 | implicit none 16 | double complex :: z, u, u2, u4, u8, c5, lmz, r, pos_cdlog 17 | double precision :: rz, iz, nz, pz, lnz, arg, sgn 18 | double precision, parameter :: PI = 3.1415926535897932D0 19 | double precision, parameter :: PI2 = 9.8696044010893586D0 20 | double precision, parameter :: PI4 = 97.409091034002437D0 21 | double precision, parameter :: PI6 = 961.38919357530444D0 22 | double precision, parameter :: zeta6 = 1.0173430619844491D0 23 | double precision, parameter :: c1 = 1.0369277551433699D0 ! zeta(5) 24 | double precision, parameter :: c2 = 0.54116161685556910D0 25 | double precision, parameter :: c3 = 0.20034281719326571D0 26 | double precision, parameter :: c4 = 0.068538919452009435D0 27 | double precision, parameter :: c6 = -1D0/1440 28 | double precision, parameter :: bf(18) = (/ & 29 | 1.0D0 , -31.0D0/64.0D0 , & 30 | 1.5241340877914952D-01, -3.4365555877057613D-02, & 31 | 5.7174797239368999D-03, -6.8180453746570645D-04, & 32 | 4.9960361948734493D-05, -4.9166051196039048D-07, & 33 | -3.0632975161302164D-07, 1.4414599270849095D-08, & 34 | 3.7272438230924107D-09, -3.7300867345487607D-10, & 35 | -5.1246526816085832D-11, 9.0541930956636683D-12, & 36 | 6.7381882615512517D-13, -2.1215831150303135D-13, & 37 | -6.8408811719011698D-15, 4.8691178462005581D-15 /) 38 | double precision, parameter :: cs(5) = (/ & 39 | -1.6534391534391534D-05, 2.2964432686654909D-08, & 40 | -9.9413128513657614D-11, 6.6912682653423394D-13, & 41 | -5.7933058574392549D-15 /) 42 | 43 | rz = real(z) 44 | iz = aimag(z) 45 | 46 | if (iz .eq. 0) then 47 | if (rz .eq. 0) then 48 | cdli6 = dcmplx(rz, iz) 49 | return 50 | endif 51 | if (rz .eq. 1) then 52 | cdli6 = dcmplx(zeta6, iz) 53 | return 54 | endif 55 | if (rz .eq. -1) then 56 | cdli6 = dcmplx(-31*zeta6/32, iz) 57 | return 58 | endif 59 | endif 60 | 61 | nz = hypot(rz, iz) 62 | pz = datan2(iz, rz) 63 | lnz = log(nz) 64 | 65 | if (lnz**2 + pz**2 .lt. 1) then ! |log(z)| < 1 66 | u = dcmplx(lnz, pz) ! log(z) 67 | u2 = u**2 68 | c5 = (137D0/60 - pos_cdlog(-u))/120 69 | cdli6 = zeta6 + u * c1 + & 70 | u2 * (c2 + u * c3 + & 71 | u2 * (c4 + u * c5 + & 72 | u2 * (c6 + & 73 | u * (cs(1) + & 74 | u2 * (cs(2) + & 75 | u2 * (cs(3) + & 76 | u2 * (cs(4) + & 77 | u2 * (cs(5))))))))) 78 | return 79 | endif 80 | 81 | if (nz .le. 1) then 82 | u = -pos_cdlog(1 - z) 83 | r = 0 84 | sgn = 1 85 | else ! nz > 1 86 | if (pz .gt. 0) then 87 | arg = pz - PI 88 | else 89 | arg = pz + PI 90 | endif 91 | lmz = dcmplx(lnz, arg) ! log(-z) 92 | u = -pos_cdlog(1 - 1/z) 93 | r = -31*PI6/15120 + lmz**2*(-7*PI4/720 + lmz**2*(-PI2/144 - lmz**2/720)) 94 | sgn = -1 95 | endif 96 | 97 | u2 = u**2 98 | u4 = u2**2 99 | u8 = u4**2 100 | 101 | cdli6 = & 102 | r + sgn * ( & 103 | u*bf(1) + & 104 | u2*(bf(2) + u*bf(3)) + & 105 | u4*(bf(4) + u*bf(5) + u2*(bf(6) + u*bf(7))) + & 106 | u8*(bf(8) + u*bf(9) + u2*(bf(10) + u*bf(11)) + & 107 | u4*(bf(12) + u*bf(13) + u2*(bf(14) + u*bf(15)))) + & 108 | u8*u8*(bf(16) + u*bf(17) + u2*bf(18)) & 109 | ) 110 | 111 | end function cdli6 112 | -------------------------------------------------------------------------------- /src/fortran/Li6.fh: -------------------------------------------------------------------------------- 1 | !********************************************************************* 2 | ! This file is part of Polylogarithm. 3 | ! 4 | ! Polylogarithm is licenced under the MIT License. 5 | !********************************************************************* 6 | 7 | ! complex polylogarithm with n=6 with double precision 8 | double complex :: cdli6 9 | -------------------------------------------------------------------------------- /src/fortran/log.f90: -------------------------------------------------------------------------------- 1 | !********************************************************************* 2 | ! This file is part of Polylogarithm. 3 | ! 4 | ! Polylogarithm is licenced under the MIT License. 5 | !********************************************************************* 6 | 7 | 8 | !********************************************************************* 9 | !> @brief Implementation of log(1 + z) for complex z 10 | !> @param z complex argument 11 | !> @return log(1 + z) 12 | !********************************************************************* 13 | double complex function cdlog1p(z) 14 | implicit none 15 | double complex :: z, u 16 | double precision :: re, im 17 | 18 | u = 1 + z 19 | re = real(u) 20 | im = aimag(u) 21 | 22 | if (re .eq. 1 .and. im .eq. 0) then 23 | cdlog1p = z 24 | elseif (re .le. 0) then 25 | cdlog1p = log(u) 26 | else 27 | cdlog1p = log(u)*(z/(u - 1)); 28 | endif 29 | 30 | end function cdlog1p 31 | 32 | 33 | !********************************************************************* 34 | !> @brief Implementation of complex logarithm 35 | !> @param z complex argument 36 | !> @return log(z) 37 | !> @note Points on the branch cut are treated differently from log(z): 38 | !> Points with Im(z) == -0D0 are mapped to Im(z) == 0D0 39 | !********************************************************************* 40 | double complex function pos_cdlog(z) 41 | implicit none 42 | double complex :: z 43 | double precision :: re, im 44 | 45 | re = real(z) 46 | im = aimag(z) 47 | 48 | if (im .eq. 0 .and. re .gt. 0) then 49 | pos_cdlog = dcmplx(log(re), 0.0D0) 50 | elseif (im .eq. 0) then 51 | pos_cdlog = dcmplx(log(-re), 3.14159265358979324D0) 52 | else 53 | pos_cdlog = log(z) 54 | endif 55 | 56 | end function pos_cdlog 57 | -------------------------------------------------------------------------------- /src/version.h: -------------------------------------------------------------------------------- 1 | #define POLYLOGARITHM_MAJOR 7 2 | #define POLYLOGARITHM_MINOR 0 3 | #define POLYLOGARITHM_PATCH 0 4 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | find_package(GSL QUIET) 2 | 3 | if(GSL_FOUND) 4 | set(LIBGSL GSL::gsl) 5 | add_definitions(-DENABLE_GSL=1) 6 | endif() 7 | 8 | add_definitions(-DTEST_DATA_DIR="${CMAKE_CURRENT_SOURCE_DIR}/data") 9 | 10 | add_subdirectory(alt) 11 | 12 | add_library(polylogarithm_test 13 | c_wrappers.c 14 | fortran_wrappers.f90 15 | ) 16 | 17 | function(add_polylogarithm_exec name) 18 | add_executable(${name} ${name}.cpp) 19 | target_link_libraries(${name} alt polylogarithm polylogarithm_test ${ARGN}) 20 | endfunction() 21 | 22 | function(add_polylogarithm_benc name) 23 | add_polylogarithm_exec(${test} ${name} ${ARGN}) 24 | endfunction() 25 | 26 | function(add_polylogarithm_test name) 27 | add_polylogarithm_exec(${test} ${name} ${ARGN}) 28 | add_test(NAME ${name} COMMAND ${name}) 29 | endfunction() 30 | 31 | add_polylogarithm_benc(bench_Li ${LIBGSL}) 32 | add_polylogarithm_benc(bench_Cl ${LIBGSL}) 33 | add_polylogarithm_benc(bench_Sl) 34 | add_polylogarithm_test(test_Cl) 35 | add_polylogarithm_test(test_Cl1) 36 | add_polylogarithm_test(test_Cl2 ${LIBGSL}) 37 | add_polylogarithm_test(test_Cl3) 38 | add_polylogarithm_test(test_Cl4) 39 | add_polylogarithm_test(test_Cl5) 40 | add_polylogarithm_test(test_Cl6) 41 | add_polylogarithm_test(test_eta) 42 | add_polylogarithm_test(test_example) 43 | add_polylogarithm_test(test_factorial) 44 | add_polylogarithm_test(test_harmonic) 45 | add_polylogarithm_test(test_Li) 46 | add_polylogarithm_test(test_Li2 ${LIBGSL}) 47 | add_polylogarithm_test(test_Li3) 48 | add_polylogarithm_test(test_Li4) 49 | add_polylogarithm_test(test_Li5) 50 | add_polylogarithm_test(test_Li6) 51 | add_polylogarithm_test(test_log) 52 | add_polylogarithm_test(test_Sl) 53 | add_polylogarithm_test(test_zeta) 54 | add_polylogarithm_test(test_version) 55 | -------------------------------------------------------------------------------- /test/alt/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(algorithm_327) 2 | add_subdirectory(algorithm_490) 3 | add_subdirectory(babar) 4 | add_subdirectory(bernoulli) 5 | add_subdirectory(cephes) 6 | add_subdirectory(hassani) 7 | add_subdirectory(hdecay) 8 | add_subdirectory(hollik) 9 | add_subdirectory(koelbig) 10 | add_subdirectory(feynhiggs) 11 | add_subdirectory(morris) 12 | add_subdirectory(pade) 13 | add_subdirectory(sherpa) 14 | add_subdirectory(spheno) 15 | add_subdirectory(tsil) 16 | add_subdirectory(wu) 17 | 18 | add_library(alt alt.c) 19 | 20 | target_include_directories(alt 21 | PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} 22 | ) 23 | 24 | target_link_libraries(alt 25 | PUBLIC 26 | algorithm_327 27 | algorithm_490 28 | babar 29 | bernoulli 30 | cephes 31 | hassani 32 | hdecay 33 | hollik 34 | koelbig 35 | feynhiggs 36 | morris 37 | pade 38 | sherpa 39 | spheno 40 | tsil 41 | wu 42 | ) 43 | -------------------------------------------------------------------------------- /test/alt/README.md: -------------------------------------------------------------------------------- 1 | Alternative implementations 2 | =========================== 3 | 4 | This directory contains alternative implementations of different 5 | polylogarithms from the literature and public codes. Original non-C 6 | implementations have been translated directly to C. References are 7 | given in the respective codes. 8 | -------------------------------------------------------------------------------- /test/alt/algorithm_327/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(algorithm_327 2 | algorithm_327.c 3 | ) 4 | 5 | target_include_directories(algorithm_327 PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) 6 | -------------------------------------------------------------------------------- /test/alt/algorithm_327/algorithm_327.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /* 4 | Algorithm 327, Dilogarithm [S22] 5 | K.S. Kölbig (Rect. 10 Oct. 1967) 6 | Applied Mathematics Group, Data Handling Division, 7 | European Organization for Nuclear Research (CERN) 8 | 1211 Genea 23, Switzerland 9 | 10 | Published in Communications of the ACM, 11 | Volume 11, Number 4, p. 270f, April 1968 12 | 13 | Translated to C by Alexander Voigt 14 | */ 15 | double algorithm_327(double x) 16 | { 17 | const double PI = 3.141592653589793; 18 | const double PI2 = PI*PI; 19 | const double PI3 = PI2/3; 20 | const double PI6 = PI2/6; 21 | 22 | double f, u, y, z, l; 23 | 24 | if (x >= 2) { 25 | l = log(x); 26 | z = 1/x; 27 | u = -0.5*l*l + PI3; 28 | f = -1; 29 | } else if (x > 1) { 30 | z = (x - 1)/x; 31 | u = -0.5*log(x)*log(z*x - z) + PI6; 32 | f = 1; 33 | } else if (x == 1) { 34 | return PI6; 35 | } else if (x > 0.5) { 36 | z = 1 - x; 37 | u = -log(x)*log(z) + PI6; 38 | f = -1; 39 | } else if (x > 0) { 40 | z = x; 41 | u = 0; 42 | f = 1; 43 | } else if (x == 0) { 44 | return 0; 45 | } else if (x >= -1) { 46 | l = log(1 - x); 47 | z = x/(x - 1); 48 | u = -0.5*l*l; 49 | f = -1; 50 | } else { 51 | z = 1/(1 - x); 52 | u = 0.5*log(z)*log(x*x*z) - PI6; 53 | f = 1; 54 | } 55 | 56 | y = 0.008048124718341*z + 0.008288074835108; 57 | y = y*z - 0.001481786416153; 58 | y = y*z - 0.000912777413024; 59 | y = y*z + 0.005047192127203; 60 | y = y*z + 0.005300972587634; 61 | y = y*z + 0.004091615355944; 62 | y = y*z + 0.004815490327461; 63 | y = y*z + 0.005966509196748; 64 | y = y*z + 0.006980881130380; 65 | y = y*z + 0.008260083434161; 66 | y = y*z + 0.009997129506220; 67 | y = y*z + 0.012345919431569; 68 | y = y*z + 0.015625134938703; 69 | y = y*z + 0.020408155605916; 70 | y = y*z + 0.027777774308288; 71 | y = y*z + 0.040000000124677; 72 | y = y*z + 0.062500000040762; 73 | y = y*z + 0.111111111110322; 74 | y = y*z + 0.249999999999859; 75 | y = y*z + 1; 76 | 77 | return f*y*z + u; 78 | } 79 | -------------------------------------------------------------------------------- /test/alt/algorithm_490/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(algorithm_490 2 | algorithm_490.c 3 | ) 4 | 5 | target_include_directories(algorithm_490 PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) 6 | -------------------------------------------------------------------------------- /test/alt/alt.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | TSIL_REAL TSIL_dilog_real(TSIL_REAL x); 4 | 5 | long double tsil_dilog_real(long double x) 6 | { 7 | return TSIL_dilog_real(x); 8 | } 9 | 10 | void tsil_dilog_complex(long double re, long double im, long double* res_re, long double* res_im) 11 | { 12 | TSIL_COMPLEX z = re + I*im; 13 | TSIL_COMPLEX res = TSIL_Dilog(z); 14 | *res_re = creall(res); 15 | *res_im = cimagl(res); 16 | } 17 | 18 | void tsil_trilog_complex(long double re, long double im, long double* res_re, long double* res_im) 19 | { 20 | TSIL_COMPLEX z = re + I*im; 21 | TSIL_COMPLEX res = TSIL_Trilog(z); 22 | *res_re = creall(res); 23 | *res_im = cimagl(res); 24 | } 25 | -------------------------------------------------------------------------------- /test/alt/alt.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifdef __cplusplus 4 | extern "C" { 5 | #endif 6 | 7 | double algorithm_327(double x); 8 | 9 | double algorithm_490(double x); 10 | double algorithm_490_2(double x); 11 | 12 | double babar_dilog(double x); 13 | 14 | double cephes_dilog(double x); 15 | 16 | double cephes_dilog_2(double x); 17 | 18 | double hassani_dilog(double x); 19 | 20 | double koelbig_dilog(double x); 21 | 22 | long double koelbig_dilogl(long double x); 23 | 24 | void feynhiggs_dilog(long double re, long double im, long double* res_re, long double* res_im); 25 | 26 | double morris_dilog(double x); 27 | 28 | void hdecay_dilog(double re, double im, double* res_re, double* res_im); 29 | 30 | void hollik_dilog(double re, double im, double* res_re, double* res_im); 31 | 32 | void sherpa_dilog(double re, double im, double* res_re, double* res_im); 33 | 34 | void spheno_dilog(double re, double im, double* res_re, double* res_im); 35 | 36 | long double tsil_dilog_real(long double x); 37 | 38 | void tsil_dilog_complex(long double re, long double im, long double* res_re, long double* res_im); 39 | 40 | void tsil_trilog_complex(long double re, long double im, long double* res_re, long double* res_im); 41 | 42 | // Clausen functions 43 | 44 | double clausen_2_bernoulli(double x); 45 | double clausen_2_koelbig(double x); 46 | long double clausen_2l_koelbig(long double x); 47 | double clausen_2_pade(double x); 48 | double clausen_3_pade(double x); 49 | double clausen_2_wu(double x); 50 | double clausen_3_wu(double x); 51 | 52 | #ifdef __cplusplus 53 | } 54 | #endif 55 | -------------------------------------------------------------------------------- /test/alt/babar/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(babar 2 | babar.c 3 | ) 4 | 5 | target_include_directories(babar PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) 6 | -------------------------------------------------------------------------------- /test/alt/babar/babar.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /* 4 | Dilogarithm function used by the BaBar collaboration. 5 | Comment: 6 | CERN C304 VERSION 29/07/71 DILOG 59 C 7 | 8 | Translated to C by Alexander Voigt 9 | */ 10 | double babar_dilog(double X) 11 | { 12 | double A, B, T, S, Y; 13 | double Z = -1.64493406684822; 14 | 15 | if (X < -1.0) goto L1; 16 | if (X <= 0.5) goto L2; 17 | if (X == 1.0) goto L3; 18 | if (X <= 2.0) goto L4; 19 | 20 | Z = 3.2898681336964; 21 | 22 | L1: 23 | T = 1.0/X; 24 | S = -0.5; 25 | Y = log(fabs(X)); 26 | Z = Z - 0.5*Y*Y; 27 | goto L5; 28 | 29 | L2: 30 | T = X; 31 | S = 0.5; 32 | Z = 0.0; 33 | goto L5; 34 | 35 | L3: 36 | return 1.64493406684822; 37 | 38 | L4: 39 | T = 1.0 - X; 40 | S = -0.5; 41 | Z = 1.64493406684822 - log(X)*log(fabs(T)); 42 | 43 | L5: 44 | Y = 2.66666666666666*T + 0.66666666666666; 45 | B = 0.000000000000001; 46 | A = Y*B + 0.000000000000004; 47 | B = Y*A - B + 0.000000000000011; 48 | A = Y*B - A + 0.000000000000037; 49 | B = Y*A - B + 0.000000000000121; 50 | A = Y*B - A + 0.000000000000398; 51 | B = Y*A - B + 0.000000000001312; 52 | A = Y*B - A + 0.000000000004342; 53 | B = Y*A - B + 0.000000000014437; 54 | A = Y*B - A + 0.000000000048274; 55 | B = Y*A - B + 0.000000000162421; 56 | A = Y*B - A + 0.000000000550291; 57 | B = Y*A - B + 0.000000001879117; 58 | A = Y*B - A + 0.000000006474338; 59 | B = Y*A - B + 0.000000022536705; 60 | A = Y*B - A + 0.000000079387055; 61 | B = Y*A - B + 0.000000283575385; 62 | A = Y*B - A + 0.000001029904264; 63 | B = Y*A - B + 0.000003816329463; 64 | A = Y*B - A + 0.000014496300557; 65 | B = Y*A - B + 0.000056817822718; 66 | A = Y*B - A + 0.000232002196094; 67 | B = Y*A - B + 0.001001627496164; 68 | A = Y*B - A + 0.004686361959447; 69 | B = Y*A - B + 0.024879322924228; 70 | A = Y*B - A + 0.166073032927855; 71 | A = Y*A - B + 1.93506430086996; 72 | 73 | return S*T*(A-B)+Z; 74 | } 75 | -------------------------------------------------------------------------------- /test/alt/bernoulli/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(bernoulli 2 | bernoulli.c 3 | ) 4 | 5 | target_include_directories(bernoulli PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) 6 | -------------------------------------------------------------------------------- /test/alt/bernoulli/bernoulli.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /** 4 | * @brief Clausen function \f$\operatorname{Cl}_2(\theta)\f$ 5 | * @param x real angle 6 | * @return \f$\operatorname{Cl}_2(\theta)\f$ 7 | * @author Alexander Voigt 8 | * 9 | * Implementation as series expansion in terms of Bernoulli numbers 10 | * [Abramowitz and Stegun, "Handbook of Mathematical Functions with 11 | * Formulas, Graphs, and Mathematical Tables", 27.8.2-3]. 12 | */ 13 | double clausen_2_bernoulli(double x) 14 | { 15 | const double PI = 3.14159265358979324; 16 | const double PI2 = 2*PI; 17 | const double A[] = { 18 | 1.0000000000000000e+00, 1.3888888888888889e-02, 19 | 6.9444444444444444e-05, 7.8735197782816830e-07, 20 | 1.1482216343327454e-08, 1.8978869988970999e-10, 21 | 3.3873013709535213e-12, 6.3726364431831804e-14, 22 | 1.2462059912950672e-15, 2.5105444608999546e-17, 23 | 5.1782588060906235e-19, 1.0887357368300849e-20, 24 | 2.3257441143020872e-22, 5.0351952131473896e-24, 25 | 1.1026499294381215e-25, 2.4386585509007345e-27, 26 | 5.4401426788562523e-29, 1.2228340131217352e-30, 27 | 2.7672634689679506e-32, 6.3000905918320139e-34, 28 | 1.4420868388418475e-35, 3.3170939991595428e-37, 29 | 7.6639135579206579e-39 30 | }; 31 | const double B[] = { 32 | 6.9314718055994531e-01, -4.1666666666666667e-02, 33 | -1.0416666666666667e-03, -4.9603174603174603e-05, 34 | -2.9279651675485009e-06, -1.9415383998717332e-07, 35 | -1.3870999114054670e-08, -1.0440290284867004e-09, 36 | -8.1670109639522231e-11, -6.5812165661369679e-12, 37 | -5.4297927275964755e-13, -4.5664875671936355e-14, 38 | -3.9019509040630692e-15, -3.3790622573736396e-16, 39 | -2.9599033551444005e-17, -2.6184896781186929e-18, 40 | -2.3365234885821292e-19, -2.1008128377954316e-20, 41 | -1.9016489757535847e-21, -1.7317557154340701e-22, 42 | -1.5855912475679039e-23, -1.4588733690004325e-24 43 | }; 44 | 45 | double sgn = 1; 46 | 47 | if (x < 0) { 48 | x = -x; 49 | sgn = -1; 50 | } 51 | 52 | if (x >= PI2) { 53 | x = fmod(x, PI2); 54 | } 55 | 56 | if (x > PI) { 57 | const double p0 = 6.28125; 58 | const double p1 = 0.0019353071795864769253; 59 | x = (p0 - x) + p1; 60 | sgn = -sgn; 61 | } 62 | 63 | if (x == 0 || x == PI) { 64 | return 0; 65 | } 66 | 67 | double sum = 0; 68 | 69 | if (x < PI/2) { 70 | const double x2 = x*x; 71 | sum = A[sizeof(A)/sizeof(A[0]) - 1]; 72 | for (int i = sizeof(A)/sizeof(A[0]) - 2; i >= 0; --i) { 73 | sum = x2*sum + A[i]; 74 | } 75 | sum -= log(x); 76 | sum *= x; 77 | } else { 78 | const double d = PI - x; 79 | const double d2 = d*d; 80 | sum = B[sizeof(B)/sizeof(B[0]) - 1]; 81 | for (int i = sizeof(B)/sizeof(B[0]) - 2; i >= 0; --i) { 82 | sum = d2*sum + B[i]; 83 | } 84 | sum *= d; 85 | } 86 | 87 | return sgn*sum; 88 | } 89 | -------------------------------------------------------------------------------- /test/alt/cephes/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(cephes 2 | cephes.c 3 | ) 4 | 5 | target_include_directories(cephes PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) 6 | -------------------------------------------------------------------------------- /test/alt/cephes/cephes.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define PI 3.141592653589793 4 | #define NTERMS 8 5 | 6 | static double polevl(double x, const double* coef) 7 | { 8 | double ans = 0; 9 | int i = NTERMS; 10 | 11 | while (i--) 12 | ans = ans * x + *coef++; 13 | 14 | return ans; 15 | } 16 | 17 | /* 18 | Spence function 19 | 20 | DESCRIPTION: 21 | 22 | Computes the integral 23 | 24 | x 25 | - 26 | | | log t 27 | spence(x) = - | ----- dt 28 | | | t - 1 29 | - 30 | 1 31 | 32 | for x >= 0. A rational approximation gives the integral in 33 | the interval (0.5, 1.5). Transformation formulas for 1/x 34 | and 1-x are employed outside the basic expansion range. 35 | 36 | ACCURACY: 37 | 38 | Relative error: 39 | arithmetic domain # trials peak rms 40 | IEEE 0,4 30000 3.9e-15 5.4e-16 41 | DEC 0,4 3000 2.5e-16 4.5e-17 42 | 43 | Cephes Math Library Release 2.8: June, 2000 44 | Copyright 1985, 1987, 1989, 2000 by Stephen L. Moshier 45 | */ 46 | static double spence(double x) 47 | { 48 | static const double A[NTERMS] = { 49 | 4.65128586073990045278E-5, 50 | 7.31589045238094711071E-3, 51 | 1.33847639578309018650E-1, 52 | 8.79691311754530315341E-1, 53 | 2.71149851196553469920E0, 54 | 4.25697156008121755724E0, 55 | 3.29771340985225106936E0, 56 | 1.00000000000000000126E0, 57 | }; 58 | 59 | static const double B[NTERMS] = { 60 | 6.90990488912553276999E-4, 61 | 2.54043763932544379113E-2, 62 | 2.82974860602568089943E-1, 63 | 1.41172597751831069617E0, 64 | 3.63800533345137075418E0, 65 | 5.03278880143316990390E0, 66 | 3.54771340985225096217E0, 67 | 9.99999999999999998740E-1, 68 | }; 69 | 70 | double w, y, z; 71 | int flag; 72 | 73 | if (x < 0.0) { 74 | return (0.0); 75 | } 76 | 77 | if (x == 1.0) 78 | return (0.0); 79 | 80 | if (x == 0.0) 81 | return (PI * PI / 6.0); 82 | 83 | flag = 0; 84 | 85 | if (x > 2.0) { 86 | x = 1.0 / x; 87 | flag |= 2; 88 | } 89 | 90 | if (x > 1.5) { 91 | w = (1.0 / x) - 1.0; 92 | flag |= 2; 93 | } 94 | 95 | else if (x < 0.5) { 96 | w = -x; 97 | flag |= 1; 98 | } 99 | 100 | else 101 | w = x - 1.0; 102 | 103 | y = -w * polevl(w, A) / polevl(w, B); 104 | 105 | if (flag & 1) 106 | y = (PI * PI) / 6.0 - log(x) * log(1.0 - x) - y; 107 | 108 | if (flag & 2) { 109 | z = log(x); 110 | y = -0.5 * z * z - y; 111 | } 112 | 113 | return (y); 114 | } 115 | 116 | /* 117 | Dilogarithm 118 | 119 | Implemented using the spence function from the Cephes math library 120 | */ 121 | double cephes_dilog(double x) 122 | { 123 | if (x > 1) { 124 | const double l = log(x); 125 | return -cephes_dilog(1/x) + PI*PI/3 - 0.5*l*l; 126 | } 127 | 128 | return spence(1 - x); 129 | } 130 | 131 | /* 132 | Dilogarithm 133 | 134 | Implemented using the spence function from the Cephes math library. 135 | Cephes Math Library Release 2.8: June, 2000 136 | Copyright 1985, 1987, 1989, 2000 by Stephen L. Moshier 137 | 138 | Optimized version written by Alexander Voigt 139 | */ 140 | double cephes_dilog_2(double x) 141 | { 142 | static const double A[NTERMS] = { 143 | 4.65128586073990045278E-5, 144 | 7.31589045238094711071E-3, 145 | 1.33847639578309018650E-1, 146 | 8.79691311754530315341E-1, 147 | 2.71149851196553469920E0, 148 | 4.25697156008121755724E0, 149 | 3.29771340985225106936E0, 150 | 1.00000000000000000126E0, 151 | }; 152 | 153 | static const double B[NTERMS] = { 154 | 6.90990488912553276999E-4, 155 | 2.54043763932544379113E-2, 156 | 2.82974860602568089943E-1, 157 | 1.41172597751831069617E0, 158 | 3.63800533345137075418E0, 159 | 5.03278880143316990390E0, 160 | 3.54771340985225096217E0, 161 | 9.99999999999999998740E-1, 162 | }; 163 | 164 | double w = 0, y = 0, lx = 0, l1mx = 0; 165 | int flag = 0; 166 | 167 | if (x == 0) 168 | return 0; 169 | 170 | if (x == 1) 171 | return PI*PI/6; 172 | 173 | if (x > 1) { 174 | x = 1 - 1/x; 175 | flag |= 4; 176 | } else 177 | x = 1 - x; 178 | 179 | if (x > 2) { 180 | x = 1/x; 181 | flag |= 2; 182 | } 183 | 184 | if (x > 1.5) { 185 | w = 1/x - 1; 186 | flag |= 2; 187 | } else if (x < 0.5) { 188 | w = -x; 189 | flag |= 1; 190 | } else 191 | w = x - 1; 192 | 193 | y = -w * polevl(w, A) / polevl(w, B); 194 | 195 | if ((flag & 1) || (flag & 2)) 196 | lx = log(x); 197 | 198 | if ((flag & 1) || (flag & 4)) 199 | l1mx = log(1 - x); 200 | 201 | if (flag & 1) 202 | y = PI*PI/6 - lx*l1mx - y; 203 | 204 | if (flag & 2) 205 | y = -0.5*lx*lx - y; 206 | 207 | if (flag & 4) 208 | y = PI*PI/3 - 0.5*l1mx*l1mx - y; 209 | 210 | return y; 211 | } 212 | -------------------------------------------------------------------------------- /test/alt/feynhiggs/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(feynhiggs 2 | feynhiggs.c 3 | ) 4 | 5 | target_include_directories(feynhiggs PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) 6 | -------------------------------------------------------------------------------- /test/alt/feynhiggs/feynhiggs.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | 5 | /* transforms -0.0 -> 0.0 */ 6 | static long double complex pclogl(long double complex z) 7 | { 8 | long double re = creall(z) == 0.0l ? fabsl(creall(z)) : creall(z); 9 | long double im = cimagl(z) == 0.0l ? fabsl(cimagl(z)) : cimagl(z); 10 | return clogl(re + I*im); 11 | } 12 | 13 | 14 | static long double complex Li2series(long double complex x1) 15 | { 16 | /* these are the even-n Bernoulli numbers, already divided by (n + 1)! 17 | as in Table[BernoulliB[n]/(n + 1)!, {n, 2, 50, 2}] */ 18 | long double b[25] = { 19 | 0.02777777777777777777777777777777777777777777778e0l, 20 | -0.000277777777777777777777777777777777777777777778e0l, 21 | 4.72411186696900982615268329554043839758125472e-6l, 22 | -9.18577307466196355085243974132863021751910641e-8l, 23 | 1.89788699889709990720091730192740293750394761e-9l, 24 | -4.06476164514422552680590938629196667454705711e-11l, 25 | 8.92169102045645255521798731675274885151428361e-13l, 26 | -1.993929586072107568723644347793789705630694749e-14l, 27 | 4.51898002961991819165047655285559322839681901e-16l, 28 | -1.035651761218124701448341154221865666596091238e-17l, 29 | 2.39521862102618674574028374300098038167894899e-19l, 30 | -5.58178587432500933628307450562541990556705462e-21l, 31 | 1.309150755418321285812307399186592301749849833e-22l, 32 | -3.087419802426740293242279764866462431595565203e-24l, 33 | 7.31597565270220342035790560925214859103339899e-26l, 34 | -1.740845657234000740989055147759702545340841422e-27l, 35 | 4.15763564461389971961789962077522667348825413e-29l, 36 | -9.96214848828462210319400670245583884985485196e-31l, 37 | 2.394034424896165300521167987893749562934279156e-32l, 38 | -5.76834735536739008429179316187765424407233225e-34l, 39 | 1.393179479647007977827886603911548331732410612e-35l, 40 | -3.372121965485089470468473635254930958979742891e-37l, 41 | 8.17820877756210262176477721487283426787618937e-39l, 42 | -1.987010831152385925564820669234786567541858996e-40l, 43 | 4.83577851804055089628705937311537820769430091e-42l 44 | }; 45 | 46 | long double complex xm = -pclogl(x1); 47 | long double complex x2 = xm*xm; 48 | long double complex ls = xm - x2/4; 49 | 50 | for (int j = 0; j < 25; j++) { 51 | long double complex ls0 = ls; 52 | xm = xm*x2; 53 | ls = ls + xm*b[j]; 54 | long double complex ls1 = ls; 55 | if (ls0 == ls1) 56 | break; 57 | } 58 | 59 | return ls; 60 | } 61 | 62 | 63 | /* 64 | Implementation of dilogarithm from FeynHiggs 2.16.0. 65 | 66 | file: src/LT/spence.F 67 | 68 | Translated to C by Alexander Voigt 69 | */ 70 | static long double complex spence(int i_in, long double complex x_in, int s) 71 | { 72 | long double complex x[2], sp; 73 | long double I1 = 1; 74 | long double I2 = I1/2; 75 | long double pi = 3.1415926535897932384626433832795029l; 76 | long double zeta2 = pi*pi/6; 77 | long double zeroeps = 1e-20l; 78 | long double complex cI = 0.0l + 1.0l*I; 79 | long double complex cIeps = cI*1e-50l; 80 | 81 | x[i_in] = x_in; 82 | x[1 - i_in] = 1 - x_in; 83 | 84 | if (creall(x[0]) < I2) { 85 | if (cabsl(x[0]) < 1) { 86 | sp = Li2series(x[1] - s * cIeps); 87 | } else { 88 | long double complex l = pclogl(-x[0] - s * cIeps); 89 | sp = -zeta2 - l * l / 2 - Li2series(-x[1] / x[0] + s * cIeps); 90 | } 91 | } else { 92 | sp = zeta2; 93 | long double ax1 = cabsl(x[1]); 94 | 95 | if (ax1 > zeroeps) { 96 | sp = zeta2 - pclogl(x[0] + s * cIeps) * pclogl(x[1] - s * cIeps); 97 | if (ax1 < 1) { 98 | sp = sp - Li2series(x[0] + s * cIeps); 99 | } else { 100 | long double complex l = pclogl(-x[1] - s * cIeps); 101 | sp = sp + zeta2 + l * l / 2 + Li2series(-x[0] / x[1] - s * cIeps); 102 | } 103 | } 104 | } 105 | 106 | return sp; 107 | } 108 | 109 | 110 | void feynhiggs_dilog(long double re, long double im, long double* res_re, long double* res_im) 111 | { 112 | int zPrec = 0; 113 | long double complex z = re + I*im; 114 | long double complex result = spence(0, z, zPrec); 115 | *res_re = creall(result); 116 | *res_im = cimagl(result); 117 | } 118 | -------------------------------------------------------------------------------- /test/alt/fortran77/Li2.f: -------------------------------------------------------------------------------- 1 | !********************************************************************* 2 | ! This file is part of Polylogarithm. 3 | ! 4 | ! Polylogarithm is licenced under the MIT License. 5 | !********************************************************************* 6 | 7 | 8 | !********************************************************************* 9 | !> @brief Real dilogarithm \f$\operatorname{Li}_2(x)\f$ 10 | !> @param x real argument 11 | !> @return \f$\operatorname{Li}_2(x)\f$ 12 | !> @author Alexander Voigt 13 | !> 14 | !> Implemented as an economized Pade approximation with a 15 | !> maximum error of 4.16e-18. 16 | !********************************************************************* 17 | double precision function dli2(x) 18 | implicit none 19 | double precision x, y, r, s, z, z2, z4, p, q, l, PI 20 | parameter (PI = 3.14159265358979324D0) 21 | double precision cp(8), cq(8) 22 | data cp / 1.0706105563309304277D+0, 23 | & -4.5353562730201404017D+0, 24 | & 7.4819657596286408905D+0, 25 | & -6.0516124315132409155D+0, 26 | & 2.4733515209909815443D+0, 27 | & -4.6937565143754629578D-1, 28 | & 3.1608910440687221695D-2, 29 | & -2.4630612614645039828D-4 / 30 | data cq / 1.0000000000000000000D+0, 31 | & -4.5355682121856044935D+0, 32 | & 8.1790029773247428573D+0, 33 | & -7.4634190853767468810D+0, 34 | & 3.6245392503925290187D+0, 35 | & -8.9936784740041174897D-1, 36 | & 9.8554565816757007266D-2, 37 | & -3.2116618742475189569D-3 / 38 | 39 | ! transform to [0, 1/2) 40 | if (x .lt. -1) then 41 | l = log(1 - x) 42 | y = 1/(1 - x) 43 | r = -PI**2/6 + l*(0.5D0*l - log(-x)) 44 | s = 1 45 | elseif (x .eq. -1) then 46 | dli2 = -PI**2/12 47 | return 48 | elseif (x .lt. 0) then 49 | y = x/(x - 1) 50 | r = -0.5D0*log(1 - x)**2 51 | s = -1 52 | elseif (x .eq. 0) then 53 | dli2 = 0 54 | return 55 | elseif (x .lt. 0.5D0) then 56 | y = x 57 | r = 0 58 | s = 1 59 | elseif (x .lt. 1) then 60 | y = 1 - x 61 | r = PI**2/6 - log(x)*log(1 - x) 62 | s = -1 63 | elseif (x .eq. 1) then 64 | dli2 = PI**2/6 65 | return 66 | elseif (x .lt. 2) then 67 | l = log(x) 68 | y = 1 - 1/x 69 | r = PI**2/6 - l*(log(1 - 1/x) + 0.5D0*l) 70 | s = 1 71 | else 72 | y = 1/x 73 | r = PI**2/3 - 0.5D0*log(x)**2 74 | s = -1 75 | endif 76 | 77 | z = y - 0.25D0 78 | z2 = z*z 79 | z4 = z2*z2 80 | 81 | p = cp(1) + z * cp(2) + z2 * (cp(3) + z * cp(4)) + 82 | & z4 * (cp(5) + z * cp(6) + z2 * (cp(7) + z * cp(8))) 83 | q = cq(1) + z * cq(2) + z2 * (cq(3) + z * cq(4)) + 84 | & z4 * (cq(5) + z * cq(6) + z2 * (cq(7) + z * cq(8))) 85 | 86 | dli2 = r + s*y*p/q 87 | 88 | end 89 | 90 | 91 | !********************************************************************* 92 | !> @brief Complex dilogarithm \f$\operatorname{Li}_2(z)\f$ 93 | !> @param z complex argument 94 | !> @return \f$\operatorname{Li}_2(z)\f$ 95 | !> @note Implementation adapted from SPheno by Alexander Voigt 96 | !********************************************************************* 97 | double complex function cdli2(z) 98 | implicit none 99 | double complex z, rest, u, u2, u4, sum, fast_cdlog 100 | double precision rz, iz, nz, sgn, dli2, PI 101 | parameter (PI = 3.14159265358979324D0) 102 | double precision bf(10) 103 | data bf /- 2.5000000000000000D-01, 104 | & + 2.7777777777777778D-02, 105 | & - 2.7777777777777778D-04, 106 | & + 4.7241118669690098D-06, 107 | & - 9.1857730746619636D-08, 108 | & + 1.8978869988970999D-09, 109 | & - 4.0647616451442255D-11, 110 | & + 8.9216910204564526D-13, 111 | & - 1.9939295860721076D-14, 112 | & + 4.5189800296199182D-16 / 113 | 114 | rz = real(z) 115 | iz = dimag(z) 116 | 117 | ! special cases 118 | if (iz .eq. 0) then 119 | if (rz .le. 1) cdli2 = dcmplx(dli2(rz), 0) 120 | if (rz .gt. 1) cdli2 = dcmplx(dli2(rz), -PI*log(rz)) 121 | return 122 | endif 123 | 124 | nz = rz**2 + iz**2 125 | 126 | if (nz .lt. 1.0D-15) then 127 | cdli2 = z*(1 + 0.25D0*z) 128 | return 129 | endif 130 | 131 | ! transformation to |z| < 1, Re(z) <= 0.5 132 | if (rz .le. 0.5D0) then 133 | if (nz .gt. 1) then 134 | u = -fast_cdlog(1 - 1/z) 135 | rest = -0.5D0*fast_cdlog(-z)**2 - PI**2/6 136 | sgn = -1 137 | else ! nz <= 1 138 | u = -fast_cdlog(1 - z) 139 | rest = 0 140 | sgn = 1 141 | endif 142 | else ! rz > 0.5D0 143 | if (nz .le. 2*rz) then 144 | u = -fast_cdlog(z) 145 | rest = u*fast_cdlog(1 - z) + PI**2/6 146 | sgn = -1 147 | else ! nz > 2*rz 148 | u = -fast_cdlog(1 - 1/z) 149 | rest = -0.5D0*fast_cdlog(-z)**2 - PI**2/6 150 | sgn = -1 151 | endif 152 | endif 153 | 154 | u2 = u**2 155 | u4 = u2**2 156 | sum = 157 | & u + 158 | & u2 * (bf(1) + 159 | & u * (bf(2) + 160 | & u2 * ( 161 | & bf(3) + 162 | & u2*bf(4) + 163 | & u4*(bf(5) + u2*bf(6)) + 164 | & u4*u4*(bf(7) + u2*bf(8) + u4*(bf(9) + u2*bf(10))) 165 | & ))) 166 | 167 | cdli2 = sgn*sum + rest 168 | 169 | end 170 | -------------------------------------------------------------------------------- /test/alt/hassani/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(hassani 2 | hassani.c 3 | ) 4 | 5 | target_include_directories(hassani PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) 6 | -------------------------------------------------------------------------------- /test/alt/hassani/hassani.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | static const double PI = 3.141592653589793; 4 | 5 | /* 6 | Series expansion of Spence function for real x > 1 7 | 8 | Mehdi Hassani - Approximation of the dilogarithm function. 9 | INSTITUTE FOR ADVANCED STUDIES IN BASIC SCIENCES 10 | P.O. B OX 45195-1159 11 | ZANJAN, IRAN. 12 | Received 15 April, 2006; accepted 03 January, 2007 13 | Communicated by A. Lupaş 14 | 15 | Translated to C by Alexander Voigt 16 | */ 17 | static double hassani_spence(double x) 18 | { 19 | const double lx = log(x); 20 | 21 | double sum = 0.0; 22 | double xn = 1; 23 | const int N = 50; // Log[1/2, 10^-15] 24 | 25 | for (int i = 1; i < N; i++) { 26 | xn *= x; 27 | sum += (1.0/i + lx)/(i*xn); 28 | } 29 | 30 | return -0.5*lx*lx - PI*PI/6 + sum; 31 | } 32 | 33 | double hassani_dilog(double x) 34 | { 35 | /* tranform to x < 0 */ 36 | if (x > 2) { 37 | return -hassani_dilog(1 - x) + PI*PI/6 - log(x)*log(x - 1); 38 | } else if (x > 1) { 39 | const double l = log(x - 1); 40 | return hassani_dilog(1/(1 - x)) + PI*PI/3 + l*(0.5*l - log(x)); 41 | } else if (x == 1) { 42 | return PI*PI/6; 43 | } else if (x > 0.5) { 44 | const double l = log(1 - x); 45 | return -hassani_dilog(x/(x - 1)) - 0.5*l*l; 46 | } else if (x == 0.5) { 47 | const double l2 = 0.69314718055994531; 48 | return PI*PI/12 - 0.5*l2*l2; 49 | } else if (x > 0) { 50 | const double l = log(x); 51 | return hassani_dilog(1 - 1/x) + PI*PI/6 - l*(log(1/x - 1) + 0.5*l); 52 | } else if (x == 0) { 53 | return 0; 54 | } else if (x > -1) { 55 | const double l = log(-x); 56 | return -hassani_dilog(1/x) - PI*PI/6 - 0.5*l*l; 57 | } 58 | 59 | return hassani_spence(1 - x); 60 | } 61 | -------------------------------------------------------------------------------- /test/alt/hdecay/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(hdecay 2 | hdecay.c 3 | ) 4 | 5 | target_include_directories(hdecay PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) 6 | -------------------------------------------------------------------------------- /test/alt/hdecay/hdecay.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | 5 | /* transforms -0.0 -> 0.0 */ 6 | static double complex clog_hdec(double complex z) 7 | { 8 | double re = creal(z) == 0.0 ? fabs(creal(z)) : creal(z); 9 | double im = cimag(z) == 0.0 ? fabs(cimag(z)) : cimag(z); 10 | return clog(re + I*im); 11 | } 12 | 13 | 14 | static double complex sqr_hdec(double complex z) 15 | { 16 | return z*z; 17 | } 18 | 19 | 20 | /* DOUBLE PRECISION VERSION OF FACTORIAL */ 21 | double factrl_hdec(int n) 22 | { 23 | double result = 1.0; 24 | 25 | if (n == 0) { 26 | return result; 27 | } 28 | 29 | for (int i = 1; i <= n; i++) { 30 | result = result * (double)i; 31 | } 32 | 33 | return result; 34 | } 35 | 36 | 37 | /* TAYLOR-EXPANSION FOR COMPLEX DILOGARITHM (SPENCE-FUNCTION) */ 38 | static double complex cli2_hdec(double complex x) 39 | { 40 | const double b[18] = { 41 | -1.0/2.0, 42 | 1.0/6.0, 43 | 0.0, 44 | -1.0/30.0, 45 | 0.0, 46 | 1.0/42.0, 47 | 0.0, 48 | -1.0/30.0, 49 | 0.0, 50 | 5.0/66.0, 51 | 0.0, 52 | -691.0/2730.0, 53 | 0.0, 54 | 7.0/6.0, 55 | 0.0, 56 | -3617.0/510.0, 57 | 0.0, 58 | 43867.0/798.0 59 | }; 60 | 61 | double b2[18]; 62 | 63 | for (int i = 0; i < 18; i++) { 64 | b2[i] = b[i]/factrl_hdec(i + 2); 65 | } 66 | 67 | const int nber = 18; 68 | const int n = nber - 1; 69 | const double complex z = -clog_hdec(1.0 - x); 70 | double complex result = b2[nber - 1]; 71 | 72 | for (int i = n - 1; i >= 0; i--) { 73 | result = z*result + b2[i]; 74 | } 75 | 76 | result = sqr_hdec(z)*result + z; 77 | 78 | return result; 79 | } 80 | 81 | 82 | /* 83 | Complex dilogarithm from HDECAY 84 | Authors: A. Djouadi, J. Kalinowski, M. Spira 85 | License: GPL 2.0 86 | 87 | Translated to C by Alexander Voigt 88 | */ 89 | double complex li2_hdec(double complex x) 90 | { 91 | const double pi = 4.0*atan(1.0); 92 | const double zeta2 = pi*pi/6; 93 | const double zero = 1e-16; 94 | const double xr = creal(x); 95 | const double xi = cimag(x); 96 | const double r2 = xr*xr + xi*xi; 97 | 98 | if (r2 < zero) { 99 | return x; 100 | } 101 | 102 | const double rr = xr/r2; 103 | double complex y = 0.0; 104 | 105 | if (r2 == 1.0 && xi == 0.0) { 106 | if (xr == 1.0) { 107 | return zeta2; 108 | } else { 109 | return -zeta2/2.0; 110 | } 111 | } else if (r2 > 1.0 && rr > 0.5) { 112 | y = (x - 1.0)/x; 113 | return cli2_hdec(y) + zeta2 - clog_hdec(x)*clog_hdec(1.0 - x) + 0.5*sqr_hdec(clog_hdec(x)); 114 | } else if (r2 > 1.0 && rr <= 0.5) { 115 | y = 1.0/x; 116 | return -cli2_hdec(y) - zeta2 - 0.5*sqr_hdec(clog_hdec(-x)); 117 | } else if (r2 <= 1.0 && xr > 0.5) { 118 | y = 1.0 - x; 119 | return -cli2_hdec(y) + zeta2 - clog_hdec(x)*clog_hdec(1.0 - x); 120 | } else if (r2 <= 1.0 && xr <= 0.5) { 121 | y = x; 122 | return cli2_hdec(y); 123 | } 124 | 125 | return 0.0; 126 | } 127 | 128 | 129 | void hdecay_dilog(double re, double im, double* res_re, double* res_im) 130 | { 131 | double complex z = re + I*im; 132 | double complex result = li2_hdec(z); 133 | *res_re = creal(result); 134 | *res_im = cimag(result); 135 | } 136 | -------------------------------------------------------------------------------- /test/alt/hollik/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(hollik 2 | hollik.c 3 | ) 4 | 5 | target_include_directories(hollik PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) 6 | -------------------------------------------------------------------------------- /test/alt/hollik/hollik.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | 5 | /* transforms -0.0 -> 0.0 */ 6 | static double complex pclog(double complex z) 7 | { 8 | double re = creal(z) == 0.0 ? fabs(creal(z)) : creal(z); 9 | double im = cimag(z) == 0.0 ? fabs(cimag(z)) : cimag(z); 10 | return clog(re + I*im); 11 | } 12 | 13 | 14 | /* 15 | SPENCE-FUNKTION KOMPLEX, FREI NACH HOLLIK 16 | 20.07.83 17 | LAST CHANGED 10.05.89, ANSGAR DENNER 18 | 19 | Translated to C by Alexander Voigt 20 | */ 21 | double complex pCSPEN(double complex Z) 22 | { 23 | double complex W,SUM,U,L; 24 | double RZ,AZ,A1; 25 | 26 | // BEACHTE: B(N)=B2N 27 | // B(1)=1./6. 28 | // B(2)=-1./30. 29 | // B(3)=1./42. 30 | // B(4)=-1./30. 31 | // B(5)=5./66. 32 | // B(6)=-691./2730. 33 | // B(7)=7./6. 34 | // B(8)=-3617./510. 35 | // B(9)=43867./798. 36 | // PI=3.1415926535897932384 37 | // PI*PI/6.=1.6449..., PI*PI/3=3.28986... 38 | const double B[9] = { 39 | 0.1666666666666666666666666667, 40 | -0.0333333333333333333333333333, 41 | 0.0238095238095238095238095238, 42 | -0.0333333333333333333333333333, 43 | 0.0757575757575757575757575758, 44 | -0.2531135531135531135531135531, 45 | 1.1666666666666666666666666667, 46 | -7.09215686274509804, 47 | 54.97117794486215539 48 | }; 49 | 50 | RZ = creal(Z); 51 | AZ = cabs(Z); 52 | A1 = cabs(1-Z); 53 | 54 | if (AZ < 1E-20) 55 | return -pclog(1-Z); 56 | 57 | if ((RZ == 1.0) && (cimag(Z) == 0.0)) 58 | return 1.64493406684822643; 59 | 60 | if (RZ > 5E-1) goto L20; 61 | if (AZ > 1) goto L10; 62 | 63 | W = -pclog(1-Z); 64 | SUM = W - 0.25*W*W; 65 | U = W; 66 | 67 | if (cabs(U) < 1E-10) goto L2; 68 | 69 | for (int K = 1; K <= 9; K++) { 70 | U = U*W*W/(2*K*(2*K+1)); 71 | if (cabs(U*B[K-1]/SUM) < 1E-20) 72 | break; 73 | SUM = SUM + U*B[K-1]; 74 | } 75 | 76 | L2: 77 | return SUM; 78 | 79 | L10: 80 | W = -pclog(1-1/Z); 81 | SUM = W - 0.25*W*W; 82 | U = W; 83 | 84 | if (cabs(U) < 1E-10) goto L12; 85 | 86 | for (int K = 1; K <= 9; K++) { 87 | U = U*W*W/(2*K*(2*K+1)); 88 | if (cabs(B[K-1]*U/SUM) < 1E-20) 89 | break; 90 | SUM = SUM + U*B[K-1]; 91 | } 92 | L12: 93 | L = pclog(-Z); 94 | 95 | return -SUM - 1.64493406684822643 - 0.5*L*L; 96 | 97 | L20: 98 | if (A1 > 1) goto L30; 99 | 100 | W = -pclog(Z); 101 | SUM = W - 0.25*W*W; 102 | U = W; 103 | 104 | if (cabs(U) < 1E-10) goto L22; 105 | 106 | for (int K = 1; K <= 9; K++) { 107 | U = U*W*W/(2*K*(2*K+1)); 108 | if (cabs(U*B[K-1]/SUM) < 1E-20) 109 | break; 110 | SUM = SUM + U*B[K-1]; 111 | } 112 | L22: 113 | return -SUM + 1.64493406684822643 - pclog(Z)*pclog(1-Z); 114 | 115 | L30: 116 | W = pclog(1-1/Z); 117 | SUM = W - 0.25*W*W; 118 | U = W; 119 | 120 | if (cabs(U) < 1E-10) goto L32; 121 | 122 | for (int K = 1; K <= 9; K++) { 123 | U = U*W*W/(2*K*(2*K+1)); 124 | if (cabs(U*B[K-1]/SUM) < 1E-20) 125 | break; 126 | SUM = SUM + U*B[K-1]; 127 | } 128 | L32: 129 | L = pclog(Z-1); 130 | 131 | return SUM + 3.28986813369645287 132 | + 0.5*L*L - pclog(Z)*pclog(1-Z); 133 | } 134 | 135 | 136 | void hollik_dilog(double re, double im, double* res_re, double* res_im) 137 | { 138 | double complex z = re + I*im; 139 | double complex result = pCSPEN(z); 140 | *res_re = creal(result); 141 | *res_im = cimag(result); 142 | } 143 | -------------------------------------------------------------------------------- /test/alt/koelbig/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(koelbig 2 | koelbig.c 3 | ) 4 | 5 | target_include_directories(koelbig PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) 6 | -------------------------------------------------------------------------------- /test/alt/morris/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(morris 2 | morris.c 3 | ) 4 | 5 | target_include_directories(morris PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) 6 | -------------------------------------------------------------------------------- /test/alt/morris/morris.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | static double horner(double x, const double* c, int len) 5 | { 6 | double p = 0.0; 7 | while (len--) 8 | p = p*x + c[len]; 9 | return p; 10 | } 11 | 12 | 13 | /* 14 | Real dilogarithm function 15 | 16 | Based on Robert Morris, 17 | "The Dilogarithm Function of a Real Argument" 18 | MATHEMATICS OF COMPUTATION, VOLUME 33, NUMBER 146 19 | APRIL 1979, PAGES 778-787, 20 | DILOG 0011 21 | 22 | Translated to C by Alexander Voigt 23 | */ 24 | double morris_dilog(double x) 25 | { 26 | const double PI = 3.141592653589793; 27 | const double P[] = { 28 | +0.12050991261341671705797e4, 29 | -0.32407609254539474989552e4, 30 | +0.31928976938241289723624e4, 31 | -0.13920671465266965241768e4, 32 | +0.25212662919363406616773e3, 33 | -0.13120034432716341584577e2, 34 | }; 35 | const double Q[] = { 36 | +0.12050991261341672354682e4, 37 | -0.35420357069875166000880e4, 38 | +0.39445067176691511608434e4, 39 | -0.20599529983831116588803e4, 40 | +0.50200962202768116987420e3, 41 | -0.48063997258736084391455e2, 42 | +0.10000000000000000000000e1, 43 | }; 44 | 45 | double y = 0, r = 0, s = 1; 46 | 47 | /* transform to [0, 1/2] */ 48 | if (x < -1) { 49 | const double l = log(1 - x); 50 | y = 1/(1 - x); 51 | r = -PI*PI/6 + l*(0.5*l - log(-x)); 52 | s = 1; 53 | } else if (x == -1) { 54 | return -PI*PI/12; 55 | } else if (x < 0) { 56 | const double l = log1p(-x); 57 | y = x/(x - 1); 58 | r = -0.5*l*l; 59 | s = -1; 60 | } else if (x == 0) { 61 | return 0; 62 | } else if (x < 0.5) { 63 | y = x; 64 | r = 0; 65 | s = 1; 66 | } else if (x < 1) { 67 | y = 1 - x; 68 | r = PI*PI/6 - log(x)*log(1 - x); 69 | s = -1; 70 | } else if (x == 1) { 71 | return PI*PI/6; 72 | } else if (x < 2) { 73 | const double l = log(x); 74 | y = 1 - 1/x; 75 | r = PI*PI/6 - l*(log(1 - 1/x) + 0.5*l); 76 | s = 1; 77 | } else { 78 | const double l = log(x); 79 | y = 1/x; 80 | r = PI*PI/3 - 0.5*l*l; 81 | s = -1; 82 | } 83 | 84 | const double p = horner(y, P, sizeof(P)/sizeof(P[0])); 85 | const double q = horner(y, Q, sizeof(Q)/sizeof(Q[0])); 86 | 87 | return r + s*y*p/q; 88 | } 89 | -------------------------------------------------------------------------------- /test/alt/pade/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(pade 2 | pade.c 3 | ) 4 | 5 | target_include_directories(pade PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) 6 | -------------------------------------------------------------------------------- /test/alt/pade/pade.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /** 4 | * @brief Clausen function \f$\operatorname{Cl}_2(\theta) = \operatorname{Im}(\operatorname{Li}_2(e^{i\theta}))\f$ 5 | * @param x real angle 6 | * @return \f$\operatorname{Cl}_2(\theta)\f$ 7 | * @author Alexander Voigt 8 | * @note Implementation as economized Padé approximation. 9 | */ 10 | double clausen_2_pade(double x) 11 | { 12 | const double PI = 3.14159265358979324; 13 | const double PI2 = 2*PI, PIH = PI/2, PI28 = PI*PI/8; 14 | double sgn = 1; 15 | 16 | if (x < 0) { 17 | x = -x; 18 | sgn = -1; 19 | } 20 | 21 | if (x >= PI2) { 22 | x = fmod(x, PI2); 23 | } 24 | 25 | if (x > PI) { 26 | const double p0 = 6.28125; 27 | const double p1 = 0.0019353071795864769253; 28 | x = (p0 - x) + p1; 29 | sgn = -sgn; 30 | } 31 | 32 | if (x == 0 || x == PI) { 33 | return 0; 34 | } 35 | 36 | double h = 0; 37 | 38 | if (x < PIH) { 39 | const double P[] = { 40 | 1.3975782911209635e-02, -4.4432680257270761e-04, 41 | 3.4141174111242951e-06, -3.7638116201783404e-09 42 | }; 43 | const double Q[] = { 44 | 1.0000000000000000e+00, -3.6904397961160525e-02, 45 | 3.7342870576106476e-04, -8.7460760866531179e-07 46 | }; 47 | const double y = x*x; 48 | const double z = y - PI28; 49 | const double z2 = z*z; 50 | const double p = P[0] + z * P[1] + z2 * (P[2] + z * P[3]); 51 | const double q = Q[0] + z * Q[1] + z2 * (Q[2] + z * Q[3]); 52 | 53 | h = x*(1 - log(x) + y*p/q); 54 | } else { 55 | const double P[] = { 56 | 6.4005702446195512e-01, -2.0641655351338783e-01, 57 | 2.4175305223497718e-02, -1.2355955287855728e-03, 58 | 2.5649833551291124e-05, -1.4783829128773320e-07 59 | }; 60 | const double Q[] = { 61 | 1.0000000000000000e+00, -2.5299102015666356e-01, 62 | 2.2148751048467057e-02, -7.8183920462457496e-04, 63 | 9.5432542196310670e-06, -1.8184302880448247e-08 64 | }; 65 | const double y = PI - x; 66 | const double z = y*y - PI28; 67 | const double z2 = z*z; 68 | const double z4 = z2*z2; 69 | const double p = P[0] + z * P[1] + z2 * (P[2] + z * P[3]) + 70 | z4 * (P[4] + z * P[5]); 71 | const double q = Q[0] + z * Q[1] + z2 * (Q[2] + z * Q[3]) + 72 | z4 * (Q[4] + z * Q[5]); 73 | 74 | h = y*p/q; 75 | } 76 | 77 | return sgn*h; 78 | } 79 | 80 | /** 81 | * @brief Clausen function \f$\operatorname{Cl}_3(\theta) = \operatorname{Re}(\operatorname{Li}_3(e^{i\theta}))\f$ 82 | * @param x real angle 83 | * @return \f$\operatorname{Cl}_3(\theta)\f$ 84 | * @author Alexander Voigt 85 | * @note Implementation as economized Padé approximation in 86 | * combination with the series expansion from [Jiming Wu, Xiaoping 87 | * Zhang, Dongjie Liu: "An efficient calculation of the Clausen 88 | * functions Cl_n(0)(n >= 2)"]. 89 | */ 90 | double clausen_3_pade(double x) 91 | { 92 | const double PI = 3.14159265358979324; 93 | const double PI2 = 2*PI, PIH = PI/2, PI28 = PI*PI/8; 94 | const double zeta3 = 1.2020569031595943; 95 | 96 | if (x < 0) { 97 | x = -x; 98 | } 99 | 100 | if (x >= PI2) { 101 | x = fmod(x, PI2); 102 | } 103 | 104 | if (x > PI) { 105 | const double p0 = 6.28125; 106 | const double p1 = 0.0019353071795864769253; 107 | x = (p0 - x) + p1; 108 | } 109 | 110 | if (x == 0) { 111 | return zeta3; 112 | } 113 | 114 | const double y = x*x; 115 | double p = 0, q = 0; 116 | 117 | if (x < PIH) { 118 | const double P[] = { 119 | -7.2832985481448279e-01, 4.4443503980076525e-02, 120 | -7.1973646626163953e-04, 2.8044709581614591e-06 121 | }; 122 | const double Q[] = { 123 | 1.0000000000000000e+00, -3.6618102564796636e-02, 124 | 3.3125108587789328e-04, -4.1893453026087742e-07 125 | }; 126 | const double z = y - PI28; 127 | const double z2 = z*z; 128 | p = P[0] + z * P[1] + z2 * (P[2] + z * P[3]); 129 | q = Q[0] + z * Q[1] + z2 * (Q[2] + z * Q[3]); 130 | } else { 131 | const double P[] = { 132 | -6.3603493635005218e-01, 6.5684157446730646e-02, 133 | -2.3565499130760498e-03, 3.5782068616362699e-05, 134 | -2.1603488890230991e-07, 3.5781888382472248e-10 135 | }; 136 | const double Q[] = { 137 | 1.0000000000000000e+00, -7.2267100371655266e-02, 138 | 1.8193983947330242e-03, -1.8536201173545669e-05, 139 | 6.4758810460566848e-08, -3.5368448623664113e-11 140 | }; 141 | const double z = y - 5*PI28; 142 | const double z2 = z*z; 143 | const double z4 = z2*z2; 144 | p = P[0] + z * P[1] + z2 * (P[2] + z * P[3]) + z4 * (P[4] + z * P[5]); 145 | q = Q[0] + z * Q[1] + z2 * (Q[2] + z * Q[3]) + z4 * (Q[4] + z * Q[5]); 146 | } 147 | 148 | return zeta3 + y*(p/q + log(2*sin(x/2))/2); 149 | } 150 | -------------------------------------------------------------------------------- /test/alt/sherpa/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(sherpa 2 | sherpa.c 3 | ) 4 | 5 | target_include_directories(sherpa PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) 6 | -------------------------------------------------------------------------------- /test/alt/sherpa/sherpa.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | 5 | /* transforms -0.0 -> 0.0 */ 6 | static double complex pclog(double complex z) 7 | { 8 | double im = cimag(z) == 0.0 ? fabs(cimag(z)) : cimag(z); 9 | return clog(creal(z) + I*im); 10 | } 11 | 12 | 13 | /* 14 | Implementation of dilogarithm from Sherpa 2.2.9 15 | 16 | file: Examples/H_in_TTBar/LHC_TTH_MCatNLO/lib.f 17 | file: Examples/V_plus_Bs/LHC_Wbb/Wbb_Virtual.f 18 | 19 | Translated to C by Alexander Voigt 20 | */ 21 | static double complex spence(double complex x) 22 | { 23 | double pi, xr, xi, vor; 24 | complex double z, d, p, result; 25 | const double a[19] = { 26 | [0] = 1.0, 27 | [1] = -0.5, 28 | [2] = 1.0/6.0, 29 | [4] = -1.0/30.0, 30 | [6] = 1.0/42.0, 31 | [8] = -1.0/30.0, 32 | [10] = 5.0/66.0, 33 | [12] = -691.0/2730.0, 34 | [14] = 7.0/6.0, 35 | [16] = -3617.0/510.0, 36 | [18] = 43867.0/798.0, 37 | }; 38 | 39 | pi = 4.0*atan(1.0); 40 | xr = creal(x); 41 | xi = cimag(x); 42 | 43 | if (xr != 1.0) goto L111; 44 | if (xi == 0.0) goto L20; 45 | 46 | L111: 47 | /* projection into the convergence radius */ 48 | vor = 1.0; 49 | p = 0.0 + I*0.0; 50 | 51 | if (creal(x) <= 0.5) goto L1; 52 | 53 | p = pi*pi/6.0 - pclog(x)*pclog(1.0 - x); 54 | vor = -1.0; 55 | x = 1.0 - x; 56 | 57 | L1: 58 | if (cabs(x) < 1.0) goto L2; 59 | 60 | p = p - (pi*pi/6.0 + pclog(-x)*pclog(-x)/2.0)*vor; 61 | vor = vor*(-1.0); 62 | x = 1.0/x; 63 | 64 | L2: 65 | /* calculation of the spence function */ 66 | z = (-1.0)*pclog(1.0 - x); 67 | d = a[18] + I*0.0; 68 | 69 | for (int n = 1; n <= 18; n++) { 70 | d = d*z/(20.0 - n) + a[18 - n]; 71 | } 72 | 73 | d = d*z; 74 | result = d*vor + p; 75 | goto L30; 76 | 77 | L20: 78 | result = pi*pi/6.0; 79 | 80 | L30: 81 | return result; 82 | } 83 | 84 | 85 | void sherpa_dilog(double re, double im, double* res_re, double* res_im) 86 | { 87 | double complex z = re + I*im; 88 | double complex result = spence(z); 89 | *res_re = creal(result); 90 | *res_im = cimag(result); 91 | } 92 | -------------------------------------------------------------------------------- /test/alt/spheno/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(spheno 2 | spheno.c 3 | ) 4 | 5 | target_include_directories(spheno PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) 6 | -------------------------------------------------------------------------------- /test/alt/tsil/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(tsil 2 | dilog.c 3 | trilog.c 4 | ) 5 | 6 | target_include_directories(tsil PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) 7 | -------------------------------------------------------------------------------- /test/alt/wu/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(wu 2 | wu.c 3 | ) 4 | 5 | target_include_directories(wu PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) 6 | -------------------------------------------------------------------------------- /test/alt/wu/wu.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /** 4 | * @brief Clausen function \f$\operatorname{Cl}_2(\theta)\f$ 5 | * @param x real angle 6 | * @return \f$\operatorname{Cl}_2(\theta)\f$ 7 | * @author Alexander Voigt 8 | * 9 | * Implementation as series expansion from Jiming Wu, Xiaoping Zhang, 10 | * Dongjie Liu: "An efficient calculation of the Clausen functions 11 | * Cl_n(0)(n >= 2)" 12 | */ 13 | double clausen_2_wu(double x) 14 | { 15 | const double PI = 3.14159265358979324; 16 | const double PI2 = 2*PI; 17 | const double C[] = { 18 | 1.0, 19 | -2.7777777777777778e-02, 20 | -2.7777777777777778e-04, 21 | -4.7241118669690098e-06, 22 | -9.1857730746619636e-08, 23 | -1.8978869988970999e-09, 24 | -4.0647616451442255e-11, 25 | -8.9216910204564526e-13, 26 | -1.9939295860721076e-14, 27 | -4.5189800296199182e-16, 28 | -1.0356517612181247e-17, 29 | -2.3952186210261867e-19, 30 | -5.5817858743250093e-21, 31 | -1.3091507554183213e-22, 32 | -3.0874198024267403e-24, 33 | -7.3159756527022034e-26, 34 | -1.7408456572340007e-27, 35 | -4.1576356446138997e-29, 36 | -9.9621484882846221e-31, 37 | -2.3940344248961653e-32, 38 | -5.7683473553673901e-34, 39 | -1.3931794796470080e-35, 40 | -3.3721219654850895e-37, 41 | -8.1782087775621026e-39, 42 | -1.9870108311523859e-40 43 | }; 44 | 45 | double sgn = 1; 46 | 47 | if (x < 0) { 48 | x = -x; 49 | sgn = -1; 50 | } 51 | 52 | if (x >= PI2) { 53 | x = fmod(x, PI2); 54 | } 55 | 56 | if (x > PI) { 57 | const double p0 = 6.28125; 58 | const double p1 = 0.0019353071795864769253; 59 | x = (p0 - x) + p1; 60 | sgn = -sgn; 61 | } 62 | 63 | if (x == 0 || x == PI) { 64 | return 0; 65 | } 66 | 67 | const double x2 = x*x; 68 | double sum = C[sizeof(C)/sizeof(C[0]) - 1]; 69 | 70 | for (int i = sizeof(C)/sizeof(C[0]) - 2; i >= 0; --i) { 71 | sum = x2*sum + C[i]; 72 | } 73 | 74 | sum -= log(2*sin(x/2)); 75 | 76 | return sgn*x*sum; 77 | } 78 | 79 | /** 80 | * @brief Clausen function \f$\operatorname{Cl}_3(\theta)\f$ 81 | * @param x real angle 82 | * @return \f$\operatorname{Cl}_3(\theta)\f$ 83 | * @author Alexander Voigt 84 | * 85 | * Implementation as series expansion from Jiming Wu, Xiaoping Zhang, 86 | * Dongjie Liu: "An efficient calculation of the Clausen functions 87 | * Cl_n(0)(n >= 2)" 88 | */ 89 | double clausen_3_wu(double x) 90 | { 91 | const double PI = 3.14159265358979324; 92 | const double PI2 = 2*PI; 93 | const double C[] = { 94 | 1.2020569031595943, 95 | -0.75, 96 | 1.7361111111111111e-02, 97 | 1.6203703703703704e-04, 98 | 2.6573129251700680e-06, 99 | 5.0521751910640800e-08, 100 | 1.0280221244025958e-09, 101 | 2.1775508813272637e-11, 102 | 4.7396483546174904e-13, 103 | 1.0523517259825012e-14, 104 | 2.3724645155504571e-16, 105 | 5.4136342063674700e-18, 106 | 1.2475096984511389e-19, 107 | 2.8982349732072164e-21, 108 | 6.7795306977020209e-23, 109 | 1.5951668979204825e-24, 110 | 3.7722999459245736e-26, 111 | 8.9602350004691215e-28, 112 | 2.1365627618154762e-29, 113 | 5.1121551453039508e-31, 114 | 1.2269426427592847e-32, 115 | 2.9528444795333068e-34, 116 | 7.1242132481949272e-36, 117 | 1.7227144823673827e-37, 118 | 4.1742940635473232e-39 119 | }; 120 | 121 | if (x < 0) { 122 | x = -x; 123 | } 124 | 125 | if (x >= PI2) { 126 | x = fmod(x, PI2); 127 | } 128 | 129 | if (x > PI) { 130 | const double p0 = 6.28125; 131 | const double p1 = 0.0019353071795864769253; 132 | x = (p0 - x) + p1; 133 | } 134 | 135 | if (x == 0) { 136 | return C[0]; 137 | } 138 | 139 | if (x == PI) { 140 | return -0.75*C[0]; 141 | } 142 | 143 | const double x2 = x*x; 144 | double sum = C[sizeof(C)/sizeof(C[0]) - 1]; 145 | 146 | for (int i = sizeof(C)/sizeof(C[0]) - 2; i >= 0; --i) { 147 | sum = x2*sum + C[i]; 148 | } 149 | 150 | sum += x2/2*log(2*sin(x/2)); 151 | 152 | return sum; 153 | } 154 | -------------------------------------------------------------------------------- /test/bench.hpp: -------------------------------------------------------------------------------- 1 | // ==================================================================== 2 | // This file is part of Polylogarithm. 3 | // 4 | // Polylogarithm is licenced under the MIT License. 5 | // ==================================================================== 6 | 7 | #pragma once 8 | 9 | #include "stopwatch.hpp" 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | namespace polylogarithm { 16 | namespace bench { 17 | 18 | template 19 | std::vector generate_random_scalars(int n, T start, T stop) 20 | { 21 | static std::minstd_rand gen; 22 | std::uniform_real_distribution dist(start, stop); 23 | 24 | std::vector v(n); 25 | std::generate(begin(v), end(v), 26 | [&dist](){ return dist(gen); }); 27 | 28 | return v; 29 | } 30 | 31 | template 32 | std::vector> generate_random_complexes( 33 | int n, T start, T stop) 34 | { 35 | const auto reals = generate_random_scalars(n, start, stop); 36 | const auto imags = generate_random_scalars(n, start, stop); 37 | 38 | std::vector> v(n); 39 | 40 | for (int i = 0; i < n; i++) { 41 | v[i] = std::complex(reals[i], imags[i]); 42 | } 43 | 44 | return v; 45 | } 46 | 47 | template 48 | inline void do_not_optimize(const T& value) 49 | { 50 | asm volatile("" : : "r,m"(value) : "memory"); 51 | } 52 | 53 | template 54 | double time_in_seconds(F&& f) 55 | { 56 | polylogarithm::Stopwatch sw; 57 | sw.start(); 58 | f(); 59 | sw.stop(); 60 | return sw.get_time_in_seconds(); 61 | } 62 | 63 | } // namespace bench 64 | } // namespace polylogarithm 65 | -------------------------------------------------------------------------------- /test/bench_Sl.cpp: -------------------------------------------------------------------------------- 1 | #include "bench.hpp" 2 | #include "Sl.hpp" 3 | #include 4 | #include 5 | #include 6 | 7 | template 8 | void bench_fn(Fn f, const std::vector& values, const std::string& name, 9 | const std::string& type) 10 | { 11 | // warm-up 12 | for (const auto& v: values) { 13 | polylogarithm::bench::do_not_optimize(f(v)); 14 | } 15 | 16 | const auto total_time = polylogarithm::bench::time_in_seconds([&] { 17 | for (const auto& v: values) { 18 | polylogarithm::bench::do_not_optimize(f(v)); 19 | } 20 | }); 21 | 22 | std::cout << std::setw(24) << std::left << name << "type: " << std::setw(16) 23 | << std::left << type << "time: " << total_time << "s\n"; 24 | } 25 | 26 | void print_line(char c) 27 | { 28 | for (int i = 0; i < 60; ++i) { 29 | std::cout << c; 30 | } 31 | std::cout << '\n'; 32 | } 33 | 34 | void print_headline_1(const std::string& text) 35 | { 36 | print_line('='); 37 | std::cout << text << '\n'; 38 | print_line('='); 39 | } 40 | 41 | template 42 | void bench(const T& values_d) 43 | { 44 | const int ni[] = { 45 | 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 46 | 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 47 | 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 48 | 31, 1000, 10000, 100000, 1000000, 10000000 49 | }; 50 | 51 | for (const auto n: ni) { 52 | bench_fn([&](double x) { return polylogarithm::Sl(n,x); }, values_d, 53 | std::string("Sl(") + std::to_string(n) + ", x)", "double"); 54 | } 55 | } 56 | 57 | int main() 58 | { 59 | using polylogarithm::bench::generate_random_scalars; 60 | 61 | const std::size_t N = 10000000; 62 | const auto pi = 3.1415926535897932; 63 | const auto min = -8*pi; 64 | const auto max = 8*pi; 65 | 66 | // range [0,pi), where no range reduction is necessary 67 | const auto values_d_redu = generate_random_scalars(N, 0, pi); 68 | // extended range, where range reduction is necessary 69 | const auto values_d_full = generate_random_scalars(N, min, max); 70 | 71 | print_headline_1("Benchmark without range reduction"); 72 | bench(values_d_redu); 73 | 74 | print_headline_1("Benchmark with range reduction"); 75 | bench(values_d_full); 76 | 77 | return 0; 78 | } 79 | -------------------------------------------------------------------------------- /test/c_wrappers.c: -------------------------------------------------------------------------------- 1 | /* ==================================================================== 2 | * This file is part of Polylogarithm. 3 | * 4 | * Polylogarithm is licenced under the MIT License. 5 | * ==================================================================== */ 6 | 7 | #include "c_wrappers.h" 8 | #include 9 | 10 | float _Complex cli2f(float _Complex); 11 | 12 | double _Complex cli2(double _Complex); 13 | double _Complex cli3(double _Complex); 14 | double _Complex cli4(double _Complex); 15 | double _Complex cli5(double _Complex); 16 | double _Complex cli6(double _Complex); 17 | 18 | long double _Complex cli2l(long double _Complex); 19 | long double _Complex cli3l(long double _Complex); 20 | long double _Complex cli4l(long double _Complex); 21 | long double _Complex cli5l(long double _Complex); 22 | long double _Complex cli6l(long double _Complex); 23 | 24 | /** C++ wrapper for cli2f */ 25 | void cli2f_c(float re, float im, float* res_re, float* res_im) 26 | { 27 | const float _Complex result = cli2f(CMPLXF(re, im)); 28 | *res_re = crealf(result); 29 | *res_im = cimagf(result); 30 | } 31 | 32 | /** C++ wrapper for cli2 */ 33 | void cli2_c(double re, double im, double* res_re, double* res_im) 34 | { 35 | const double _Complex result = cli2(CMPLX(re, im)); 36 | *res_re = creal(result); 37 | *res_im = cimag(result); 38 | } 39 | 40 | /** C++ wrapper for cli2l */ 41 | void cli2l_c(long double re, long double im, long double* res_re, long double* res_im) 42 | { 43 | const long double _Complex result = cli2l(CMPLXL(re, im)); 44 | *res_re = creall(result); 45 | *res_im = cimagl(result); 46 | } 47 | 48 | /** C++ wrapper for cli3 */ 49 | void cli3_c(double re, double im, double* res_re, double* res_im) 50 | { 51 | const double _Complex result = cli3(CMPLX(re, im)); 52 | *res_re = creal(result); 53 | *res_im = cimag(result); 54 | } 55 | 56 | /** C++ wrapper for cli3l */ 57 | void cli3l_c(long double re, long double im, long double* res_re, long double* res_im) 58 | { 59 | const long double _Complex result = cli3l(CMPLXL(re, im)); 60 | *res_re = creall(result); 61 | *res_im = cimagl(result); 62 | } 63 | 64 | /** C++ wrapper for cli4 */ 65 | void cli4_c(double re, double im, double* res_re, double* res_im) 66 | { 67 | const double _Complex result = cli4(CMPLX(re, im)); 68 | *res_re = creal(result); 69 | *res_im = cimag(result); 70 | } 71 | 72 | /** C++ wrapper for cli4l */ 73 | void cli4l_c(long double re, long double im, long double* res_re, long double* res_im) 74 | { 75 | const long double _Complex result = cli4l(CMPLXL(re, im)); 76 | *res_re = creall(result); 77 | *res_im = cimagl(result); 78 | } 79 | 80 | /** C++ wrapper for cli5 */ 81 | void cli5_c(double re, double im, double* res_re, double* res_im) 82 | { 83 | const double _Complex result = cli5(CMPLX(re, im)); 84 | *res_re = creal(result); 85 | *res_im = cimag(result); 86 | } 87 | 88 | /** C++ wrapper for cli5l */ 89 | void cli5l_c(long double re, long double im, long double* res_re, long double* res_im) 90 | { 91 | const long double _Complex result = cli5l(CMPLXL(re, im)); 92 | *res_re = creall(result); 93 | *res_im = cimagl(result); 94 | } 95 | 96 | /** C++ wrapper for cli6 */ 97 | void cli6_c(double re, double im, double* res_re, double* res_im) 98 | { 99 | const double _Complex result = cli6(CMPLX(re, im)); 100 | *res_re = creal(result); 101 | *res_im = cimag(result); 102 | } 103 | 104 | /** C++ wrapper for cli6l */ 105 | void cli6l_c(long double re, long double im, long double* res_re, long double* res_im) 106 | { 107 | const long double _Complex result = cli6l(CMPLXL(re, im)); 108 | *res_re = creall(result); 109 | *res_im = cimagl(result); 110 | } 111 | -------------------------------------------------------------------------------- /test/c_wrappers.h: -------------------------------------------------------------------------------- 1 | /* ==================================================================== 2 | * This file is part of Polylogarithm. 3 | * 4 | * Polylogarithm is licenced under the MIT License. 5 | * ==================================================================== */ 6 | 7 | #pragma once 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | /** Clausen function with n=2 */ 14 | double cl2(double x); 15 | 16 | /** Clausen function with n=3 */ 17 | double cl3(double x); 18 | 19 | /** Clausen function with n=4 */ 20 | double cl4(double x); 21 | 22 | /** Clausen function with n=5 */ 23 | double cl5(double x); 24 | 25 | /** Clausen function with n=6 */ 26 | double cl6(double x); 27 | 28 | /** Clausen function with n=2 with long double precision */ 29 | long double cl2l(long double x); 30 | 31 | /** Clausen function with n=3 with long double precision */ 32 | long double cl3l(long double x); 33 | 34 | /** Clausen function with n=4 with long double precision */ 35 | long double cl4l(long double x); 36 | 37 | /** Clausen function with n=5 with long double precision */ 38 | long double cl5l(long double x); 39 | 40 | /** Clausen function with n=6 with long double precision */ 41 | long double cl6l(long double x); 42 | 43 | /** real polylogarithm with n=2 (dilogarithm) with single precision */ 44 | float li2f(float x); 45 | 46 | /** real polylogarithm with n=2 (dilogarithm) */ 47 | double li2(double x); 48 | 49 | /** real polylogarithm with n=3 (trilogarithm) */ 50 | double li3(double x); 51 | 52 | /** real polylogarithm with n=4 (trilogarithm) */ 53 | double li4(double x); 54 | 55 | /** real polylogarithm with n=2 (dilogarithm) with long double precision */ 56 | long double li2l(long double x); 57 | 58 | /** complex polylogarithm with n=2 (dilogarithm) with single precision */ 59 | void cli2f_c(float re, float im, float* res_re, float* res_im); 60 | 61 | /** complex polylogarithm with n=2 (dilogarithm) with double precision */ 62 | void cli2_c(double re, double im, double* res_re, double* res_im); 63 | 64 | /** complex polylogarithm with n=2 (dilogarithm) with long double precision */ 65 | void cli2l_c(long double re, long double im, long double* res_re, long double* res_im); 66 | 67 | /** complex polylogarithm with n=3 (trilogarithm) */ 68 | void cli3_c(double re, double im, double* res_re, double* res_im); 69 | 70 | /** complex polylogarithm with n=3 (trilogarithm) with long double precision */ 71 | void cli3l_c(long double re, long double im, long double* res_re, long double* res_im); 72 | 73 | /** complex polylogarithm with n=4 */ 74 | void cli4_c(double re, double im, double* res_re, double* res_im); 75 | 76 | /** complex polylogarithm with n=4 with long double precision */ 77 | void cli4l_c(long double re, long double im, long double* res_re, long double* res_im); 78 | 79 | /** complex polylogarithm with n=5 */ 80 | void cli5_c(double re, double im, double* res_re, double* res_im); 81 | 82 | /** complex polylogarithm with n=5 with long double precision */ 83 | void cli5l_c(long double re, long double im, long double* res_re, long double* res_im); 84 | 85 | /** complex polylogarithm with n=6 */ 86 | void cli6_c(double re, double im, double* res_re, double* res_im); 87 | 88 | /** complex polylogarithm with n=6 with long double precision */ 89 | void cli6l_c(long double re, long double im, long double* res_re, long double* res_im); 90 | 91 | #ifdef __cplusplus 92 | } 93 | #endif 94 | -------------------------------------------------------------------------------- /test/fortran_wrappers.f90: -------------------------------------------------------------------------------- 1 | !********************************************************************* 2 | ! This file is part of Polylogarithm. 3 | ! 4 | ! Polylogarithm is licenced under the MIT License. 5 | !********************************************************************* 6 | 7 | 8 | subroutine cl2_fortran(x, res) bind(C) 9 | use, intrinsic :: iso_c_binding 10 | implicit none 11 | real(c_double), intent(in) :: x 12 | real(c_double), intent(out) :: res 13 | double precision dcl2 14 | res = dcl2(x) 15 | end subroutine cl2_fortran 16 | 17 | 18 | subroutine cl3_fortran(x, res) bind(C) 19 | use, intrinsic :: iso_c_binding 20 | implicit none 21 | real(c_double), intent(in) :: x 22 | real(c_double), intent(out) :: res 23 | double precision dcl3 24 | res = dcl3(x) 25 | end subroutine cl3_fortran 26 | 27 | 28 | subroutine cl4_fortran(x, res) bind(C) 29 | use, intrinsic :: iso_c_binding 30 | implicit none 31 | real(c_double), intent(in) :: x 32 | real(c_double), intent(out) :: res 33 | double precision dcl4 34 | res = dcl4(x) 35 | end subroutine cl4_fortran 36 | 37 | 38 | subroutine cl5_fortran(x, res) bind(C) 39 | use, intrinsic :: iso_c_binding 40 | implicit none 41 | real(c_double), intent(in) :: x 42 | real(c_double), intent(out) :: res 43 | double precision dcl5 44 | res = dcl5(x) 45 | end subroutine cl5_fortran 46 | 47 | 48 | subroutine cl6_fortran(x, res) bind(C) 49 | use, intrinsic :: iso_c_binding 50 | implicit none 51 | real(c_double), intent(in) :: x 52 | real(c_double), intent(out) :: res 53 | double precision dcl6 54 | res = dcl6(x) 55 | end subroutine cl6_fortran 56 | 57 | 58 | subroutine li2_fortran(x, res) bind(C) 59 | use, intrinsic :: iso_c_binding 60 | implicit none 61 | real(c_double), intent(in) :: x 62 | real(c_double), intent(out) :: res 63 | double precision dli2 64 | res = dli2(x) 65 | end subroutine li2_fortran 66 | 67 | 68 | subroutine li3_fortran(x, res) bind(C) 69 | use, intrinsic :: iso_c_binding 70 | implicit none 71 | real(c_double), intent(in) :: x 72 | real(c_double), intent(out) :: res 73 | double precision dli3 74 | res = dli3(x) 75 | end subroutine li3_fortran 76 | 77 | 78 | subroutine li4_fortran(x, res) bind(C) 79 | use, intrinsic :: iso_c_binding 80 | implicit none 81 | real(c_double), intent(in) :: x 82 | real(c_double), intent(out) :: res 83 | double precision dli4 84 | res = dli4(x) 85 | end subroutine li4_fortran 86 | 87 | 88 | subroutine cli2_fortran(re, im, res_re, res_im) bind(C) 89 | use, intrinsic :: iso_c_binding 90 | implicit none 91 | real(c_double), intent(in) :: im, re 92 | real(c_double), intent(out) :: res_re, res_im 93 | double complex res, cdli2 94 | res = cdli2(dcmplx(re, im)) 95 | res_re = real(res) 96 | res_im = aimag(res) 97 | end subroutine cli2_fortran 98 | 99 | 100 | subroutine cli3_fortran(re, im, res_re, res_im) bind(C) 101 | use, intrinsic :: iso_c_binding 102 | implicit none 103 | real(c_double), intent(in) :: im, re 104 | real(c_double), intent(out) :: res_re, res_im 105 | double complex res, cdli3 106 | res = cdli3(dcmplx(re, im)) 107 | res_re = real(res) 108 | res_im = aimag(res) 109 | end subroutine cli3_fortran 110 | 111 | 112 | subroutine cli4_fortran(re, im, res_re, res_im) bind(C) 113 | use, intrinsic :: iso_c_binding 114 | implicit none 115 | real(c_double), intent(in) :: im, re 116 | real(c_double), intent(out) :: res_re, res_im 117 | double complex res, cdli4 118 | res = cdli4(dcmplx(re, im)) 119 | res_re = real(res) 120 | res_im = aimag(res) 121 | end subroutine cli4_fortran 122 | 123 | 124 | subroutine cli5_fortran(re, im, res_re, res_im) bind(C) 125 | use, intrinsic :: iso_c_binding 126 | implicit none 127 | real(c_double), intent(in) :: im, re 128 | real(c_double), intent(out) :: res_re, res_im 129 | double complex res, cdli5 130 | res = cdli5(dcmplx(re, im)) 131 | res_re = real(res) 132 | res_im = aimag(res) 133 | end subroutine cli5_fortran 134 | 135 | 136 | subroutine cli6_fortran(re, im, res_re, res_im) bind(C) 137 | use, intrinsic :: iso_c_binding 138 | implicit none 139 | real(c_double), intent(in) :: im, re 140 | real(c_double), intent(out) :: res_re, res_im 141 | double complex res, cdli6 142 | res = cdli6(dcmplx(re, im)) 143 | res_re = real(res) 144 | res_im = aimag(res) 145 | end subroutine cli6_fortran 146 | -------------------------------------------------------------------------------- /test/fortran_wrappers.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifdef __cplusplus 4 | extern "C" { 5 | #endif 6 | 7 | #ifdef ENABLE_FORTRAN 8 | 9 | /** Clausen function with n=2, Fortran implementation */ 10 | void cl2_fortran(const double* x, double* res); 11 | 12 | /** Clausen function with n=3, Fortran implementation */ 13 | void cl3_fortran(const double* x, double* res); 14 | 15 | /** Clausen function with n=4, Fortran implementation */ 16 | void cl4_fortran(const double* x, double* res); 17 | 18 | /** Clausen function with n=5, Fortran implementation */ 19 | void cl5_fortran(const double* x, double* res); 20 | 21 | /** Clausen function with n=6, Fortran implementation */ 22 | void cl6_fortran(const double* x, double* res); 23 | 24 | /** real polylogarithm with n=2 (dilogarithm), Fortran implementation */ 25 | void li2_fortran(const double* x, double* res); 26 | 27 | /** real polylogarithm with n=3 (trilogarithm), Fortran implementation */ 28 | void li3_fortran(const double* x, double* res); 29 | 30 | /** real polylogarithm with n=4, Fortran implementation */ 31 | void li4_fortran(const double* x, double* res); 32 | 33 | /** complex polylogarithm with n=2 (dilogarithm), Fortran implementation */ 34 | void cli2_fortran(const double* re, const double* im, double* res_re, double* res_im); 35 | 36 | /** complex polylogarithm with n=3 (trilogarithm), Fortran implementation */ 37 | void cli3_fortran(const double* re, const double* im, double* res_re, double* res_im); 38 | 39 | /** complex polylogarithm with n=4, Fortran implementation */ 40 | void cli4_fortran(const double* re, const double* im, double* res_re, double* res_im); 41 | 42 | /** complex polylogarithm with n=5, Fortran implementation */ 43 | void cli5_fortran(const double* re, const double* im, double* res_re, double* res_im); 44 | 45 | /** complex polylogarithm with n=6, Fortran implementation */ 46 | void cli6_fortran(const double* re, const double* im, double* res_re, double* res_im); 47 | 48 | #endif 49 | 50 | #ifdef __cplusplus 51 | } 52 | #endif 53 | -------------------------------------------------------------------------------- /test/generate_data_Cl.m: -------------------------------------------------------------------------------- 1 | (* calculate function with precision prec *) 2 | GeneratePoint[f_, prec_, x_] := 3 | { N[x, prec], Re[N[f[x], prec]] } 4 | 5 | (* calculate functions with precision prec on a grid *) 6 | GenerateGridData[f_, prec_, {min_, max_, step_}] := 7 | Table[GeneratePoint[f, prec, x], {x, min, max, step}] 8 | 9 | (* data arount {re, im} from given direction {reDir, imDir} *) 10 | GenerateLimitData[f_, prec_, n_, frac_, x_, xDir_] := 11 | Table[GeneratePoint[f, prec, x + xDir frac^k], {k, 1, n, 1}] 12 | 13 | (* data arount {re, im} from all directions *) 14 | GenerateLimitData[f_, prec_, n_, frac_, x_] := 15 | Join[ 16 | GenerateLimitData[f, prec, n, frac, x, +1], 17 | GenerateLimitData[f, prec, n, frac, x, -1] 18 | ] 19 | 20 | ExportData[f_, prec_] := 21 | Module[{data, filename}, 22 | Print["Generating data for " <> ToString[f]]; 23 | data = Join[ 24 | GenerateGridData[f, prec, {0, 2 Pi, 1/100}], 25 | GenerateLimitData[f, prec, prec , 1/10, 0, +1], 26 | GenerateLimitData[f, prec, prec , 1/10, Pi/2 ], 27 | GenerateLimitData[f, prec, prec , 1/10, Pi ], 28 | GenerateLimitData[f, prec, prec , 1/10, 3Pi/2 ], 29 | GenerateLimitData[f, prec, prec-3, 1/10, 2Pi, -1] 30 | ]; 31 | filename = ToString[f] <> ".txt"; 32 | Print["Writing data to ", filename]; 33 | Export[filename, data, "Table"]; 34 | ] 35 | 36 | 37 | Cl1[x_] := ResourceFunction["ClausenCl"][1, x] 38 | Cl2[x_] := ResourceFunction["ClausenCl"][2, x] 39 | Cl3[x_] := ResourceFunction["ClausenCl"][3, x] 40 | Cl4[x_] := ResourceFunction["ClausenCl"][4, x] 41 | Cl5[x_] := ResourceFunction["ClausenCl"][5, N[x,40]] 42 | Cl6[x_] := ResourceFunction["ClausenCl"][6, N[x,40]] 43 | Cl7[x_] := ResourceFunction["ClausenCl"][7, N[x,40]] 44 | Cl8[x_] := ResourceFunction["ClausenCl"][8, N[x,40]] 45 | Cl9[x_] := ResourceFunction["ClausenCl"][9, N[x,40]] 46 | Cl10[x_] := ResourceFunction["ClausenCl"][10, N[x,40]] 47 | Cl11[x_] := ResourceFunction["ClausenCl"][11, N[x,40]] 48 | Cl12[x_] := ResourceFunction["ClausenCl"][12, N[x,40]] 49 | Cl13[x_] := ResourceFunction["ClausenCl"][13, N[x,40]] 50 | Cl14[x_] := ResourceFunction["ClausenCl"][14, N[x,40]] 51 | Cl15[x_] := ResourceFunction["ClausenCl"][15, N[x,40]] 52 | Cl16[x_] := ResourceFunction["ClausenCl"][16, N[x,40]] 53 | Cl1000[x_] := ResourceFunction["ClausenCl"][1000, N[x,40]] 54 | Cl1001[x_] := ResourceFunction["ClausenCl"][1001, N[x,40]] 55 | Cl1000000[x_] := ResourceFunction["ClausenCl"][1000000, N[x,40]] 56 | 57 | ExportData[Cl1, 40]; 58 | ExportData[Cl2, 40]; 59 | ExportData[Cl3, 40]; 60 | ExportData[Cl4, 40]; 61 | ExportData[Cl5, 40]; 62 | ExportData[Cl6, 40]; 63 | ExportData[Cl7, 40]; 64 | ExportData[Cl8, 40]; 65 | ExportData[Cl9, 40]; 66 | ExportData[Cl10, 40]; 67 | ExportData[Cl11, 40]; 68 | ExportData[Cl12, 40]; 69 | ExportData[Cl13, 40]; 70 | ExportData[Cl14, 40]; 71 | ExportData[Cl15, 40]; 72 | ExportData[Cl16, 40]; 73 | ExportData[Cl1000, 40]; 74 | ExportData[Cl1001, 40]; 75 | ExportData[Cl1000000, 40]; 76 | -------------------------------------------------------------------------------- /test/generate_data_Li.m: -------------------------------------------------------------------------------- 1 | NEval[x_, prec_] := N[x, 3 prec] 2 | 3 | (* calculate polylogarithm of order s with precision prec *) 4 | GeneratePoint[s_, prec_, re_, im_] := 5 | Module[{val = PolyLog[s, re + I im]}, 6 | { 7 | NEval[#, prec]& @ {re, im}, 8 | {Re[NEval[val, prec]], Im[NEval[val, prec]]} 9 | } 10 | ] 11 | 12 | (* calculate polylogarithms of order s with precision prec on a 13 | grid *) 14 | GenerateGridData[s_, prec_, {min_, max_, step_}] := 15 | Flatten /@ Join @@ Table[ 16 | GeneratePoint[s, prec, re, im], 17 | {re, min, max, step}, 18 | {im, min, max, step} 19 | ] 20 | 21 | (* calculate polylogarithms of order s with precision prec on a 22 | grid close to unity *) 23 | GenerateUnitData[s_, prec_, n_, frac_, dir_] := 24 | Flatten /@ Join @@ Table[ 25 | GeneratePoint[s, prec, 1 + dir frac^k, im], 26 | {k, 1, n, 1}, 27 | {im, 0, 0, 1} 28 | ] 29 | 30 | (* data arount {re, im} from given direction {reDir, imDir} *) 31 | GenerateLimitData[s_, prec_, n_, frac_, {re_, im_}, {reDir_, imDir_}] := 32 | Flatten /@ Join @@ Table[ 33 | GeneratePoint[s, prec, re + reDir frac^k, im + imDir frac^m], 34 | {k, 1, n, 1}, 35 | {m, 1, n, 1} 36 | ] 37 | 38 | (* data arount {re, im} from all directions *) 39 | GenerateLimitData[s_, prec_, n_, frac_, {re_, im_}] := 40 | Join[ 41 | GenerateLimitData[s, prec, n, frac, {re, im}, {+1, +1}], 42 | GenerateLimitData[s, prec, n, frac, {re, im}, {+1, -1}], 43 | GenerateLimitData[s, prec, n, frac, {re, im}, {-1, +1}], 44 | GenerateLimitData[s, prec, n, frac, {re, im}, {-1, -1}] 45 | ] 46 | 47 | ExportData[s_, prec_] := 48 | Module[{data, omega = 1/2 + Sqrt[3]/2, filename}, 49 | Print["Generating data for Li" <> ToString[s]]; 50 | data = Join[ 51 | GenerateGridData[s, prec, {-5, 5, 1/10}], 52 | GenerateGridData[s, prec, {-10, 30, 4/10}], 53 | GenerateGridData[s, prec, {-1000, 1000, 100}], 54 | GenerateUnitData[s, prec, prec, 1/10, -1], 55 | GenerateUnitData[s, prec, prec, 1/10, +1], 56 | GenerateLimitData[s, prec, prec, 1/10, {+1, 0}], 57 | GenerateLimitData[s, prec, prec, 1/10, { 0, 0}], 58 | GenerateLimitData[s, prec, prec, 1/10, {-1, 0}] 59 | (* Join @@@ { *) 60 | (* GeneratePoint[s, prec, 0 , 0], *) 61 | (* GeneratePoint[s, prec, 1/2, 0], *) 62 | (* GeneratePoint[s, prec, 1 , 0], *) 63 | (* GeneratePoint[s, prec, 3/2, 0], *) 64 | (* GeneratePoint[s, prec, -0 , 0], *) 65 | (* GeneratePoint[s, prec, -1/2, 0], *) 66 | (* GeneratePoint[s, prec, -1 , 0], *) 67 | (* GeneratePoint[s, prec, -3/2, 0], *) 68 | (* GeneratePoint[s, prec, -(Sqrt[5] - 1)/2, 0], *) 69 | (* GeneratePoint[s, prec, -(Sqrt[5] + 1)/2, 0], *) 70 | (* GeneratePoint[s, prec, (Sqrt[5] + 1)/2, 0], *) 71 | (* GeneratePoint[s, prec, (Sqrt[5] + 3)/2, 0], *) 72 | (* GeneratePoint[s, prec, omega, 0], *) 73 | (* GeneratePoint[s, prec, omega^2, 0], *) 74 | (* GeneratePoint[s, prec, 1 + omega, 0], *) 75 | (* GeneratePoint[s, prec, 1/(1 + omega), 0] *) 76 | (* } *) 77 | ]; 78 | filename = "Li" <> ToString[s] <> ".txt"; 79 | Print["Writing data to ", filename]; 80 | Export[filename, data, "Table"]; 81 | ] 82 | 83 | ExportData[2, 40]; 84 | ExportData[3, 40]; 85 | ExportData[4, 40]; 86 | ExportData[5, 40]; 87 | ExportData[6, 40]; 88 | 89 | ExportData[1/2, 40]; 90 | ExportData[3/2, 40]; 91 | ExportData[5/2, 40]; 92 | ExportData[21/2, 40]; 93 | ExportData[41/2, 40]; 94 | -------------------------------------------------------------------------------- /test/math/clausenBernoulli.m: -------------------------------------------------------------------------------- 1 | (* 2 | 3 | This Mathematica script contains implementations of the Clausen[2,x] 4 | function in the intervals [0,Pi) and (0,2Pi) in terms of Bernoulli 5 | numbers [Abramowitz and Stegun, "Handbook of Mathematical Functions 6 | with Formulas, Graphs, and Mathematical Tables", 27.8.2-3]. 7 | 8 | *) 9 | 10 | (* x in [0, Pi) *) 11 | Cl2Lo[x_, nMax_] := 12 | x - x Log[x] + x^3/2 Sum[Abs[BernoulliB[2n + 2]] x^(2n)/((n + 1) Factorial[2n + 3]), {n,0,nMax}] 13 | 14 | (* x in (0, 2Pi) *) 15 | Cl2Hi[x_, nMax_] := 16 | (Pi - x) (Log[2] - Sum[(2^(2n) - 1) Abs[BernoulliB[2n]] (Pi - x)^(2n)/(2n Factorial[2n + 1]), {n,1,nMax}]) 17 | 18 | Cl2[0, _] := 0 19 | 20 | Cl2[Pi, _] := 0 21 | 22 | Cl2[x_, nMax_] := -Cl2[-x, nMax] /; x < 0 23 | 24 | Cl2[x_, nMax_] := Cl2[Mod[x, 2Pi], nMax] /; x >= 2Pi 25 | 26 | Cl2[x_, nMax_] := -Cl2[2Pi - x, nMax] /; x > Pi 27 | 28 | Cl2[x_, nMax_] := Cl2Lo[x, nMax] /; x > 0 && x < Pi/2 29 | 30 | Cl2[x_, nMax_] := Cl2Hi[x, nMax] /; x >= Pi/2 && x < Pi 31 | -------------------------------------------------------------------------------- /test/math/clausenCheby.m: -------------------------------------------------------------------------------- 1 | (* 2 | 3 | This Mathematica script calculates the coefficients of the expansion 4 | of Clausen[2,x] in the intervals [-Pi/2,Pi/2] and [Pi/2,3Pi/2] in 5 | terms of Chebyshev polynomials. It reproduces the results found in 6 | [K.S. Kölbig, Journal of Computational and Applied Mathematics 64 7 | (1995) 295-297]. 8 | *) 9 | 10 | ChebyshevCoefficients[n_Integer?Positive, f_Function] := 11 | Module[{c, xk, coeffs}, 12 | (* zeros of Chebyshev polynomials *) 13 | xk = Pi (Range[n] - 1/2)/n; 14 | (* Chebyshev coefficients *) 15 | c[j_] := 2/n Total[Cos[j xk] (f /@ Cos[xk])]; 16 | (* coefficients in expansion of even Chebyshev polynomials *) 17 | coeffs = Table[c[k], {k, 0, n-1, 2}]; 18 | coeffs[[1]] *= 1/2; 19 | coeffs 20 | ] 21 | 22 | (* interval mapping y(x): [a,b] -> [-1,1] *) 23 | y[x_, a_, b_] := (a + b - 2*x)/(a - b) 24 | 25 | (* inverse interval mapping x(y): [-1,1] -> [a,b] *) 26 | x[y_, a_, b_] := y * (b - a)/2 + (b + a)/2 27 | 28 | (* Clausen function, n = 2 *) 29 | Cl2[x_] := I/2 (PolyLog[2, E^(-I*x)] - PolyLog[2, E^(I*x)]) 30 | 31 | (* expansion interval [a,b] *) 32 | a = -Pi/2; 33 | b = Pi/2; 34 | 35 | (* function to approximate on [a,b] *) 36 | f1 = 2/x[#,a,b]^2 (Cl2[x[#,a,b]]/x[#,a,b] - 1 + Log[Abs[x[#,a,b]]])& 37 | 38 | coeffs1 = ChebyshevCoefficients[38, f1] 39 | 40 | (* expansion interval [a,b] *) 41 | a = Pi/2; 42 | b = 3 Pi/2; 43 | 44 | (* function to approximate on [a,b] *) 45 | f2 = Cl2[x[#,a,b]]/(Pi - x[#,a,b])& 46 | 47 | coeffs2 = ChebyshevCoefficients[60, f2] 48 | 49 | (* precision *) 50 | prec = 37 51 | 52 | Print @ DecimalForm[#, {prec, prec}]& @ Re @ N[#, prec]& @ coeffs1 53 | 54 | Print @ DecimalForm[#, {prec, prec}]& @ Re @ N[#, prec]& @ coeffs2 55 | -------------------------------------------------------------------------------- /test/math/clausenMinimaxApprox.m: -------------------------------------------------------------------------------- 1 | (* 2 | Approximations of Cl2[2,x] by rational function approximations 3 | on the intervals [0, Pi/2) and [Pi/2, Pi). 4 | *) 5 | 6 | Needs["FunctionApproximations`"]; 7 | 8 | Get["../test/math/clausenBernoulli.m"]; 9 | Get["../test/math/clausenWu.m"]; 10 | 11 | (* maximum number of terms in Cl2 series *) 12 | nMax = 100; 13 | 14 | (* output precision *) 15 | outPrec = 17; 16 | 17 | (* bring rational function to standard form *) 18 | PolynomialStandardForm[expr_, x_] := 19 | Module[{n = Numerator[expr], d = Denominator[expr], c}, 20 | c = d /. x -> 0; 21 | Expand[n/c] / Expand[d/c] 22 | ] 23 | 24 | FormatCoeffs[expr_, x_, prec_] := 25 | ScientificForm @ CForm @ N[#, prec]& /@ CoefficientList[expr, x] 26 | 27 | CalcPade[fn_, interval_, {numTerms_, denTerms_}] := 28 | Module[{half = interval[[1]] + (interval[[2]] - interval[[1]])/2, 29 | approx, diff, maxErr, y, range}, 30 | approx = EconomizedRationalApproximation[fn[x], {x, interval, numTerms, denTerms}] /. x -> (y + half); 31 | approx = PolynomialStandardForm[approx, y]; 32 | Print["Pade approximant for ", InputForm[fn], " on the interval ", InputForm[interval]]; 33 | Print["Numerator coefficients: ", 34 | FormatCoeffs[#,y,outPrec]& @ Numerator[approx]]; 35 | Print["Denominator coefficients: ", 36 | FormatCoeffs[#,y,outPrec]& @ Denominator[approx]]; 37 | (* calculate maximum deviation *) 38 | Print["half interval: ", InputForm[half]]; 39 | diff = (approx - fn[x]) /. y -> x - half; 40 | range = Range[interval[[1]] + 10^(-outPrec), interval[[2]], (interval[[2]] - interval[[1]])/100]; 41 | maxErr = Max @ Abs @ N[diff /. x -> #, outPrec]& @ range; 42 | Print["max error: ", InputForm @ maxErr]; 43 | ] 44 | 45 | CalcMinimax[fn_, interval_, {numTerms_, denTerms_}] := 46 | Module[{approx, maxErr}, 47 | approx = MiniMaxApproximation[fn[x], {x, interval, numTerms, denTerms}, WorkingPrecision -> 1000]; 48 | maxErr = approx[[2,2]]; 49 | approx = PolynomialStandardForm[approx[[2,1]], x]; 50 | Print["Approximant for ", InputForm[fn], " on the interval ", InputForm[interval]]; 51 | Print["Numerator coefficients: ", 52 | FormatCoeffs[#,x,outPrec]& @ Numerator[approx]]; 53 | Print["Denominator coefficients: ", 54 | FormatCoeffs[#,x,outPrec]& @ Denominator[approx]]; 55 | (* calculate maximum deviation *) 56 | Print["max error: ", InputForm @ N[maxErr,6]]; 57 | approx 58 | ] 59 | 60 | Print["======================================================="]; 61 | Print[" Cl2 "]; 62 | Print["======================================================="]; 63 | 64 | (* interval = {0, Pi/2}; *) 65 | fLo[x_] := Module[{y}, Expand[1/y^2 (Cl2Lo[y, nMax]/y - 1 + Log[y])] /. y -> x] 66 | 67 | CalcMinimax[N[fLo[Sqrt[#]], 10*outPrec]&, {0, (Pi/2)^2}, {3, 3}]; 68 | 69 | (* interval = {Pi/2, Pi}; *) 70 | fHi[x_] := Cl2Hi[x, nMax]/(Pi - x) 71 | 72 | (* transformation *) 73 | trans[x_] := Sqrt[x] + Pi 74 | 75 | (* inverse transformation *) 76 | itrans[x_] := (Pi - x)^2 77 | 78 | CalcPade[N[fHi[trans[#]], 10*outPrec]&, itrans /@ {Pi/2, Pi}, {5,5}]; 79 | 80 | Print["======================================================="]; 81 | Print[" Cl3 "]; 82 | Print["======================================================="]; 83 | 84 | (* interval = {0, Pi/2}; *) 85 | fLo[x_] := Module[{y}, Normal[Series[Expand[(Cl[3, y, nMax] - Zeta[3])/y^2 - Log[y]/2], {y,0,nMax}]] /. y -> x] 86 | 87 | CalcMinimax[N[fLo[Sqrt[#]], 10*outPrec]&, {0, (Pi/2)^2}, {3,3}]; 88 | 89 | (* interval = {Pi/2, Pi}; *) 90 | fHi[x_] := Cl[3, x, nMax] 91 | 92 | CalcPade[N[fHi[trans[#]], 10*outPrec]&, itrans /@ {Pi/2, Pi}, {5,5}]; 93 | 94 | Print["======================================================="]; 95 | Print[" Cl4 "]; 96 | Print["======================================================="]; 97 | 98 | (* interval = {0, Pi/2}; *) 99 | fLo[x_] := Module[{y}, Normal[Series[Expand[(Cl[4, y, nMax]/y - Zeta[3])/y^2 - Log[y]/6], {y,0,nMax}]] /. y -> x] 100 | 101 | CalcMinimax[N[fLo[Sqrt[#]], 10*outPrec]&, {0, (Pi/2)^2}, {3,3}]; 102 | 103 | (* interval = {Pi/2, Pi}; *) 104 | fHi[x_] := Cl[4, x, nMax]/(Pi - x) 105 | 106 | CalcPade[N[fHi[trans[#]], 10*outPrec]&, itrans /@ {Pi/2, Pi}, {5,5}]; 107 | 108 | Print["======================================================="]; 109 | Print[" Cl5 "]; 110 | Print["======================================================="]; 111 | 112 | (* interval = {0, Pi/2}; *) 113 | fLo[x_] := Module[{y}, Normal[Series[Expand[Cl[5, y, nMax] + y^4 Log[y]/24], {y,0,nMax}]] /. y -> x] 114 | 115 | CalcMinimax[N[fLo[Sqrt[#]], 10*outPrec]&, {0, (Pi/2)^2}, {3,4}]; 116 | 117 | (* interval = {Pi/2, Pi}; *) 118 | fHi[x_] := Cl[5, x, nMax] 119 | 120 | CalcPade[N[fHi[trans[#]], 10*outPrec]&, itrans /@ {Pi/2, Pi}, {5,5}]; 121 | 122 | Print["======================================================="]; 123 | Print[" Cl6 "]; 124 | Print["======================================================="]; 125 | 126 | (* interval = {0, Pi/2}; *) 127 | fLo[x_] := Module[{y}, Normal[Series[Expand[Cl[6, y, nMax]/y + y^4 Log[y]/120], {y,0,nMax}]] /. y -> x] 128 | 129 | CalcMinimax[N[fLo[Sqrt[#]], 10*outPrec]&, {0, (Pi/2)^2}, {3,3}]; 130 | 131 | (* interval = {Pi/2, Pi}; *) 132 | fHi[x_] := Cl[6, x, nMax]/(Pi - x) 133 | 134 | CalcPade[N[fHi[trans[#]], 10*outPrec]&, itrans /@ {Pi/2, Pi}, {4,5}]; 135 | -------------------------------------------------------------------------------- /test/math/clausenWu.m: -------------------------------------------------------------------------------- 1 | (* 2 | 3 | Implementation of the Clausen function Cl_n(theta) for n >= 2 from 4 | 5 | Jiming Wu, Xiaoping Zhang, Dongjie Liu: "An efficient calculation of 6 | the Clausen functions Cl_n(0)(n >= 2)" 7 | 8 | *) 9 | 10 | (* Eq.(2.11) *) 11 | Ncal[n_, theta_, nMax_] := 1/(n+1) ( 12 | theta^(n+1)/(n+1) 13 | + Sum[(-1)^k BernoulliB[2k] theta^(2k+n+1)/((2k+n+1)Factorial[2k]), {k,1,nMax}] 14 | ) 15 | 16 | Pcal[n_, theta_] := 17 | Sum[(-1)^(Floor[(n-1)/2] + Floor[(i-1)/2]) theta^(n-i)/Factorial[n-i] Cl[i,0], {i,2,n}] 18 | 19 | (* Eq.(1.4) *) 20 | Cl[n_, 0, ___] := 0 /; EvenQ[n] 21 | 22 | (* Eq.(1.4) *) 23 | Cl[n_, 0, ___] := Zeta[n] /; OddQ[n] 24 | 25 | (* Eq.(1.7), restrict theta to [0, Infinity) *) 26 | Cl[n_, theta_, nMax_] := 27 | (-1)^(n+1) Cl[n, -theta, nMax] /; theta < 0 28 | 29 | (* Eq.(1.6), restrict theta to [0, Pi] *) 30 | Cl[n_, theta_, nMax_] := 31 | Cl[n, theta - Ceiling[theta/(2Pi)] 2Pi, nMax] /; theta > Pi 32 | 33 | (* Eq.(2.8), (2.13) *) 34 | Cl[n_, theta_, nMax_] := ( 35 | (-1)^(Floor[(n+1)/2]) theta^(n-1)/Factorial[n-1] Log[2 Sin[theta/2]] 36 | + (-1)^(Floor[n/2] + 1)/Factorial[n-2] * 37 | Sum[(-1)^i Binomial[n-2,i] theta^i Ncal[n-2-i, theta, nMax], {i,0,n-2}] 38 | + Pcal[n, theta] 39 | ) 40 | -------------------------------------------------------------------------------- /test/math/dilogCheby.m: -------------------------------------------------------------------------------- 1 | (* 2 | 3 | This Mathematica script calculates the coefficients of the expansion 4 | of (-1)PolyLog[2,T] with T = -x in the interval [-1,0] in terms of 5 | Chebyshev polynomials. It reproduces the results found in [Yudell 6 | L. Luke: Mathematical functions and their approximations, Academic 7 | Press Inc., New York 1975, p.67, Table 3.12]. 8 | 9 | *) 10 | 11 | ChebyshevCoefficients[n_Integer?Positive, f_Function] := 12 | Module[{c, xk, coeffs}, 13 | (* zeros of Chebyshev polynomials *) 14 | xk = Pi (Range[n] - 1/2)/n; 15 | (* Chebyshev coefficients *) 16 | c[j_] := 2/n Total[Cos[j xk] (f /@ Cos[xk])]; 17 | (* coefficients in expansion of Chebyshev polynomials *) 18 | coeffs = Table[c[k], {k, 0, n-1}]; 19 | coeffs[[1]] *= 1/2; 20 | coeffs 21 | ] 22 | 23 | (* expansion interval [a,b] = [-1,0] *) 24 | a = -1; 25 | b = 0; 26 | 27 | (* interval mapping y(x): [a,b] -> [-1,1] *) 28 | y[x_] := (a + b - 2*x)/(a - b) 29 | 30 | (* inverse interval mapping x(y): [-1,1] -> [a,b] *) 31 | x[y_] := y * (b - a)/2 + (b + a)/2 32 | 33 | (* function to approximate, # is in [-1,1] *) 34 | f = -PolyLog[2, x[-#]]& 35 | 36 | coeffs = ChebyshevCoefficients[45, f] 37 | 38 | (* precision *) 39 | prec = 37 40 | 41 | Print @ DecimalForm[#, {prec, prec}]& @ Re @ N[#, prec]& @ coeffs 42 | -------------------------------------------------------------------------------- /test/math/dilogMinimaxApprox.m: -------------------------------------------------------------------------------- 1 | (* 2 | Approximation of PolyLog[2,x]/x by an economized Pade approximation 3 | on the interval [0, 1/2). 4 | *) 5 | 6 | Needs["FunctionApproximations`"]; 7 | 8 | (* maximum number of terms in Li2 series, 9 | so that [0,0.5]^nMax << machine precision *) 10 | nMax = 200; 11 | 12 | (* output precision *) 13 | outPrec = 20; 14 | 15 | interval = {0, 1/2}; 16 | 17 | half = (interval[[2]] - interval[[1]])/2; 18 | 19 | (* series for PolyLog[2,x]/x *) 20 | Li2x[x_, n_:nMax] := Sum[x^(i-1)/i^2, {i,1,n}]; 21 | 22 | (* bring rational function to standard form *) 23 | PolynomialStandardForm[expr_, x_] := 24 | Module[{n = Numerator[expr], d = Denominator[expr], c}, 25 | c = d /. x -> 0; 26 | Expand[n/c] / Expand[d/c] 27 | ]; 28 | 29 | approx = MiniMaxApproximation[Li2x[x], {x, interval, 5, 6}, WorkingPrecision -> 100]; 30 | 31 | maxErr = approx[[2,2]] 32 | 33 | Print["max rel. error: ", InputForm @ maxErr]; 34 | 35 | approx = PolynomialStandardForm[approx[[2,1]], x]; 36 | 37 | FormatCoeffs[expr_, x_, prec_] := 38 | N[#, prec]& /@ CoefficientList[expr, x] 39 | 40 | Print["Numerator coefficients: ", 41 | FormatCoeffs[#,x,outPrec]& @ Numerator[approx]]; 42 | 43 | Print["Denominator coefficients: ", 44 | FormatCoeffs[#,x,outPrec]& @ Denominator[approx]]; 45 | -------------------------------------------------------------------------------- /test/math/dilogRelations.m: -------------------------------------------------------------------------------- 1 | (* Functional properties of the dilogarithm *) 2 | 3 | r1 = { Li2[z_] :> -Li2[1/z] - Pi^2/6 - 1/2 Log[-z]^2 } 4 | 5 | r2 = { Li2[z_] :> -Li2[1-z] + Pi^2/6 - Log[z] Log[1-z] } 6 | -------------------------------------------------------------------------------- /test/math/dilogRemezApprox.m: -------------------------------------------------------------------------------- 1 | (* 2 | Approximation of PolyLog[2,x]/x by a rational function using Remez 3 | algorithm on the interval [0, 1/2). 4 | *) 5 | 6 | Needs["FunctionApproximations`"]; 7 | 8 | (* maximum number of terms in Li2 series, 9 | so that [0,0.5]^nMax << machine precision *) 10 | nMax = 200; 11 | 12 | (* claculation precision *) 13 | prec = 100; 14 | 15 | (* output precision *) 16 | outPrec = 20; 17 | 18 | (* series for PolyLog[2,x]/x *) 19 | Li2x[x_, n_:nMax] := Sum[x^(i-1)/i^2, {i,1,n}]; 20 | 21 | {abscissa, {appox, maxErr}} = 22 | MiniMaxApproximation[Li2x[x], {x, {0,1/2}, 7, 7}, 23 | WorkingPrecision -> prec, 24 | MaxIterations -> 1000]; 25 | 26 | FormatCoeffs[expr_, x_, prec_] := 27 | NumberForm[#, prec]& /@ CoefficientList[expr, x] 28 | 29 | Print["Numerator coefficients: ", 30 | FormatCoeffs[#,x,outPrec]& @ Numerator[appox]]; 31 | 32 | Print["Denominator coefficients: ", 33 | FormatCoeffs[#,x,outPrec]& @ Denominator[appox]]; 34 | 35 | Print["max error: ", InputForm @ maxErr]; 36 | -------------------------------------------------------------------------------- /test/math/polylog.m: -------------------------------------------------------------------------------- 1 | u[z_] := -Log[1 - z]; 2 | 3 | X[0, n_] := BernoulliB[n]; 4 | 5 | X[p_, n_] := 6 | Sum[Binomial[n, k] BernoulliB[n - k]/(k + 1) X[p - 1, k], {k, 0, n}]; 7 | 8 | (* Series expansion of polylogarithm Li_p(z) up to given order, n > 0 *) 9 | Li[p_, z_, order_:50] := 10 | Sum[X[p - 2, n] u[z]^(n + 1)/Factorial[n + 1], {n, 0, order}]; 11 | 12 | (* Remainder function on the r.h.s. of 13 | Li[p,z] + (-1)^p Li[p,1/z] = Rem[p,z] *) 14 | Rem[p_, z_] := 15 | -(2 Pi I)^p/Factorial[p] BernoulliB[p, 1/2 + Log[-z]/(2 Pi I)]; 16 | 17 | (* Series expansion of polylogarithm Li_p(z) up to given order, n <= 0 *) 18 | Lineg[p_, z_] := 19 | Sum[(-z/(1-z))^(k+1) Sum[(-1)^(j+1) Binomial[k, j] (j + 1)^(-p), {j, 0, k}], {k, 0, -p}]; 20 | 21 | (* Series expansion of trilogarithm Li_3(z) in terms of Log[z] *) 22 | Trilog[z_, order_:10] := (3 Log[z]^2 - 2 Log[z]^2 Log[-Log[z]] + 23 | 4 Sum[(Log[z]^k Zeta[3 - k])/k!, {k, 0, 1}] + 24 | 4 Sum[(Log[z]^k Zeta[3 - k])/k!, {k, 3, order}])/4; 25 | 26 | (* Series expansion of polylogarithm Li_p(z) around unity up to given order, n > 0 *) 27 | Li1[n_, z_, order_:10] := (Zeta[n] + 28 | ((EulerGamma + PolyGamma[n] - Log[-Log[z]])/(n - 1)!) Log[z]^(n - 1) + 29 | Sum[(Zeta[n - j]/j!) Log[z]^j, {j, 1, n - 2}] + 30 | Sum[(Zeta[n - j]/j!) Log[z]^j, {j, n, order}]); 31 | -------------------------------------------------------------------------------- /test/math/tetralogMinimaxApprox.m: -------------------------------------------------------------------------------- 1 | (* 2 | Approximation of PolyLog[4,x] by a rational function approximations. 3 | *) 4 | 5 | Needs["FunctionApproximations`"]; 6 | 7 | (* maximum number of terms in the series *) 8 | nMax = 200; 9 | 10 | (* output precision *) 11 | outPrec = 20; 12 | 13 | (* series for PolyLog[4,x]/x *) 14 | Li4x[x_, n_:nMax] := Sum[x^(i-1)/i^4, {i,1,n}]; 15 | 16 | (* bring rational function to standard form *) 17 | PolynomialStandardForm[expr_, x_] := 18 | Module[{n = Numerator[expr], d = Denominator[expr], c}, 19 | c = d /. x -> 0; 20 | Expand[n/c] / Expand[d/c] 21 | ]; 22 | 23 | FormatCoeffs[expr_, x_, prec_] := 24 | N[#, prec]& /@ CoefficientList[expr, x] 25 | 26 | (* inversion formula rest term *) 27 | 28 | (* -(2 Pi I)^n/Factorial[n] BernoulliB[n, 1/2 + Log[-x]/(2 Pi I)] /. n -> 4 *) 29 | 30 | (* [-1,0] *) 31 | 32 | Print["Approximation of Li4[x]/x on [-1,0]"]; 33 | 34 | li4 = Normal@Series[PolyLog[4,x]/x, {x,-1,100}] 35 | 36 | approx = MiniMaxApproximation[li4, {x, {-1, 0}, 5, 6}, WorkingPrecision -> nMax]; 37 | 38 | maxErr = approx[[2,2]] 39 | 40 | Print["max rel. error: ", InputForm @ maxErr]; 41 | 42 | approx = PolynomialStandardForm[approx[[2,1]], x]; 43 | 44 | Print["Numerator coefficients: ", 45 | FormatCoeffs[#,x,outPrec]& @ Numerator[approx]]; 46 | 47 | Print["Denominator coefficients: ", 48 | FormatCoeffs[#,x,outPrec]& @ Denominator[approx]]; 49 | 50 | (* [0,1/2] *) 51 | 52 | Print["Approximation of Li4[x]/x on [0,1/2]"]; 53 | 54 | approx = MiniMaxApproximation[Li4x[x], {x, {0, 1/2}, 5, 5}, WorkingPrecision -> 100]; 55 | 56 | maxErr = approx[[2,2]] 57 | 58 | Print["max rel. error: ", InputForm @ maxErr]; 59 | 60 | approx = PolynomialStandardForm[approx[[2,1]], x]; 61 | 62 | Print["Numerator coefficients: ", 63 | FormatCoeffs[#,x,outPrec]& @ Numerator[approx]]; 64 | 65 | Print["Denominator coefficients: ", 66 | FormatCoeffs[#,x,outPrec]& @ Denominator[approx]]; 67 | 68 | (* [1/2,8/10] *) 69 | 70 | Print["Approximation of Li4[x] on [1/2,8/10]"]; 71 | 72 | approx = MiniMaxApproximation[PolyLog[4,x], {x, {1/2, 8/10}, 6, 6}, WorkingPrecision -> 100]; 73 | 74 | maxErr = approx[[2,2]] 75 | 76 | Print["max rel. error: ", InputForm @ maxErr]; 77 | 78 | approx = PolynomialStandardForm[approx[[2,1]], x]; 79 | 80 | Print["Numerator coefficients: ", 81 | FormatCoeffs[#,x,outPrec]& @ Numerator[approx]]; 82 | 83 | Print["Denominator coefficients: ", 84 | FormatCoeffs[#,x,outPrec]& @ Denominator[approx]]; 85 | -------------------------------------------------------------------------------- /test/math/trilogMinimaxApprox.m: -------------------------------------------------------------------------------- 1 | (* 2 | Approximation of PolyLog[3,x]/x by a rational function approximation 3 | on the intervals [0, 1/2] and [-1, 0]. 4 | *) 5 | 6 | Needs["FunctionApproximations`"]; 7 | 8 | (* maximum number of terms in Li3 series, 9 | so that [0,0.5]^nMax << machine precision *) 10 | nMax = 200; 11 | 12 | (* output precision *) 13 | outPrec = 20; 14 | 15 | interval = {0, 1/2}; 16 | 17 | (* series for PolyLog[3,x]/x *) 18 | Li3x[x_, n_:nMax] := Sum[x^(i-1)/i^3, {i,1,n}]; 19 | 20 | (* bring rational function to standard form *) 21 | PolynomialStandardForm[expr_, x_] := 22 | Module[{n = Numerator[expr], d = Denominator[expr], c}, 23 | c = d /. x -> 0; 24 | Expand[n/c] / Expand[d/c] 25 | ]; 26 | 27 | approx = MiniMaxApproximation[Li3x[x], {x, interval, 5, 6}, WorkingPrecision -> 100]; 28 | 29 | maxErr = approx[[2,2]] 30 | 31 | Print["max rel. error: ", InputForm @ maxErr]; 32 | 33 | approx = PolynomialStandardForm[approx[[2,1]], x]; 34 | 35 | FormatCoeffs[expr_, x_, prec_] := 36 | N[#, prec]& /@ CoefficientList[expr, x] 37 | 38 | Print["Numerator coefficients: ", 39 | FormatCoeffs[#,x,outPrec]& @ Numerator[approx]]; 40 | 41 | Print["Denominator coefficients: ", 42 | FormatCoeffs[#,x,outPrec]& @ Denominator[approx]]; 43 | 44 | (* interval [-1,0] *) 45 | 46 | interval = {-1, 0}; 47 | 48 | li3 = Normal@Series[PolyLog[3,x]/x, {x,-1,100}] 49 | 50 | approx = MiniMaxApproximation[li3, {x, interval, 5, 6}, WorkingPrecision -> 100]; 51 | 52 | maxErr = approx[[2,2]] 53 | 54 | Print["max rel. error: ", InputForm @ maxErr]; 55 | 56 | approx = PolynomialStandardForm[approx[[2,1]], x]; 57 | 58 | FormatCoeffs[expr_, x_, prec_] := 59 | N[#, prec]& /@ CoefficientList[expr, x] 60 | 61 | Print["Numerator coefficients: ", 62 | FormatCoeffs[#,x,outPrec]& @ Numerator[approx]]; 63 | 64 | Print["Denominator coefficients: ", 65 | FormatCoeffs[#,x,outPrec]& @ Denominator[approx]]; 66 | -------------------------------------------------------------------------------- /test/read_data.hpp: -------------------------------------------------------------------------------- 1 | // ==================================================================== 2 | // This file is part of Polylogarithm. 3 | // 4 | // Polylogarithm is licenced under the MIT License. 5 | // ==================================================================== 6 | 7 | #pragma once 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | const char PATH_SEPARATOR = 16 | #ifdef _WIN32 17 | '\\'; 18 | #else 19 | '/'; 20 | #endif 21 | 22 | namespace polylogarithm { 23 | namespace test { 24 | 25 | /** 26 | * Reads complex numbers and corresponding polylogarithms from a file. 27 | * 28 | * @param filename file name 29 | * @tparam T data type for real and imaginary parts 30 | * 31 | * @return vector of pairs, where the first element in the pair is the 32 | * complex number and the second element is the corresponding 33 | * polylogarithm. 34 | */ 35 | template 36 | std::vector, std::complex>> 37 | read_from_file(const std::string& filename) 38 | { 39 | using Cmpl_t = std::complex; 40 | 41 | std::vector> data; 42 | std::string line; 43 | std::ifstream fstr(filename); 44 | 45 | while (std::getline(fstr, line)) { 46 | T re_z{}, im_z{}, re_li{}, im_li{}; 47 | 48 | std::istringstream isstr(line); 49 | isstr >> re_z >> im_z >> re_li >> im_li; 50 | 51 | data.push_back(std::make_pair(Cmpl_t(re_z, im_z), Cmpl_t(re_li, im_li))); 52 | } 53 | 54 | return data; 55 | } 56 | 57 | /** 58 | * Reads real numbers and corresponding results from a file. 59 | * 60 | * @param filename file name 61 | * @tparam T data type for real numbers 62 | * 63 | * @return vector of pairs, where the first element in the pair is the 64 | * number and the second element is the corresponding result. 65 | */ 66 | template 67 | std::vector> 68 | read_reals_from_file(const std::string& filename) 69 | { 70 | std::vector> data; 71 | std::string line; 72 | std::ifstream fstr(filename); 73 | 74 | while (std::getline(fstr, line)) { 75 | T x{}, y{}; 76 | 77 | std::istringstream isstr(line); 78 | isstr >> x >> y; 79 | 80 | data.push_back(std::make_pair(x, y)); 81 | } 82 | 83 | return data; 84 | } 85 | 86 | } // namespace test 87 | } // namespace polylogarithm 88 | -------------------------------------------------------------------------------- /test/stopwatch.hpp: -------------------------------------------------------------------------------- 1 | // ==================================================================== 2 | // This file is part of Polylogarithm. 3 | // 4 | // Polylogarithm is licenced under the MIT License. 5 | // ==================================================================== 6 | 7 | #pragma once 8 | 9 | #include 10 | 11 | namespace polylogarithm { 12 | 13 | class Stopwatch { 14 | private: 15 | using microseconds_t = std::chrono::duration; 16 | 17 | microseconds_t::rep get_ticks() const { 18 | microseconds_t duration(std::chrono::duration_cast( 19 | stop_point - start_point)); 20 | return duration.count(); 21 | } 22 | 23 | public: 24 | void start() { 25 | start_point = std::chrono::high_resolution_clock::now(); 26 | } 27 | 28 | void stop() { 29 | stop_point = std::chrono::high_resolution_clock::now(); 30 | } 31 | 32 | double get_time_in_seconds() const { 33 | return get_ticks() * 0.000001; 34 | } 35 | 36 | double get_time_in_milliseconds() const { 37 | return get_ticks() * 0.001; 38 | } 39 | 40 | private: 41 | std::chrono::high_resolution_clock::time_point start_point, stop_point; 42 | }; 43 | 44 | } // namespace polylogarithm 45 | -------------------------------------------------------------------------------- /test/test.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | 7 | #ifndef M_PI 8 | #define M_PI 3.1415926535897932 9 | #endif 10 | 11 | 12 | #ifndef M_PIL 13 | #define M_PIL 3.14159265358979323846264338327950288L 14 | #endif 15 | 16 | 17 | #define CHECK_CLOSE(a,b,eps) \ 18 | do { \ 19 | if (std::isinf(a) && std::isinf(b)) { \ 20 | CHECK(true); \ 21 | } else { \ 22 | CHECK((a) == doctest::Approx(b).epsilon(eps)); \ 23 | } \ 24 | } while (0); 25 | 26 | 27 | #define CHECK_CLOSE_COMPLEX(a,b,eps) do { \ 28 | CHECK_CLOSE(std::real(a), std::real(b), (eps)); \ 29 | CHECK_CLOSE(std::imag(a), std::imag(b), (eps)); \ 30 | } while (0) 31 | 32 | 33 | #define CHECK_SMALL(a,eps) CHECK(std::abs(a) < (eps)) 34 | 35 | 36 | #define CHECK_CLOSE_REL(a,b,eps) do { \ 37 | const bool pred = is_close_rel((a), (b), (eps)); \ 38 | INFO("Comparing numbers " << std::setprecision(17) << (a) << " =?= " << (b) << " with relative precision " << (eps)); \ 39 | CHECK(pred); \ 40 | } while (0) 41 | 42 | 43 | inline bool has_inf() noexcept 44 | { 45 | const auto fn = [] (bool return_inf) { return return_inf ? std::numeric_limits::infinity() : 0.0; }; 46 | return std::isinf(fn(true)); 47 | } 48 | 49 | 50 | inline bool has_signed_zero() noexcept 51 | { 52 | const auto fn = [] (double x) { return x == 0.0 ? x : x; }; 53 | return std::signbit(fn(-0.0)); 54 | } 55 | 56 | 57 | inline bool is_ieee754_compliant() noexcept 58 | { 59 | return has_inf() && has_signed_zero(); 60 | } 61 | 62 | 63 | inline bool is_close_rel(double x, double y, double eps) noexcept 64 | { 65 | const double ma = std::max(std::abs(x), std::abs(y)); 66 | if (ma == 0.0) { 67 | return true; 68 | } 69 | return std::abs(x - y)/ma < std::abs(eps); 70 | } 71 | 72 | 73 | template T sqr(T x) { 74 | return x*x; 75 | } 76 | 77 | 78 | template T pow3(T x) { 79 | return x*x*x; 80 | } 81 | 82 | 83 | template T pow4(T x) { 84 | return sqr(sqr(x)); 85 | } 86 | 87 | 88 | template 89 | std::complex to(std::complex z) 90 | { 91 | return std::complex(static_cast(std::real(z)), static_cast(std::imag(z))); 92 | } 93 | -------------------------------------------------------------------------------- /test/test_Cl.cpp: -------------------------------------------------------------------------------- 1 | #define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN 1 2 | 3 | #include "doctest.h" 4 | #include "Cl.hpp" 5 | #include "Cl1.hpp" 6 | #include "Cl2.hpp" 7 | #include "Cl3.hpp" 8 | #include "Cl4.hpp" 9 | #include "Cl5.hpp" 10 | #include "Cl6.hpp" 11 | #include "Li.hpp" 12 | #include "read_data.hpp" 13 | #include "test.hpp" 14 | #include 15 | #include 16 | #include 17 | 18 | std::vector float_range( 19 | double start, double stop, std::size_t number_of_steps) 20 | { 21 | const double step_size = (stop - start) / number_of_steps; 22 | std::vector result(number_of_steps); 23 | 24 | for (std::size_t i = 0; i < number_of_steps; ++i) { 25 | const double point = start + i * step_size; 26 | result[i] = point; 27 | } 28 | 29 | return result; 30 | } 31 | 32 | double Cl_via_Li(int64_t n, double x) 33 | { 34 | const std::complex li = polylogarithm::Li(n, std::polar(1.0, x)); 35 | 36 | if (n % 2 == 0) { 37 | return std::imag(li); 38 | } 39 | 40 | return std::real(li); 41 | } 42 | 43 | TEST_CASE("test_special_values") 44 | { 45 | using polylogarithm::Cl; 46 | const double pi = M_PI; 47 | const double catalan = 0.91596559417721901505460351493238411077414937428167; 48 | 49 | CHECK_CLOSE(Cl(2,pi/2.), catalan, 1e-15); 50 | } 51 | 52 | TEST_CASE("test_kummer_relation") 53 | { 54 | using polylogarithm::Cl; 55 | using polylogarithm::Li; 56 | const double pi = M_PI; 57 | const double z2 = 1.644934066848226436472415166646025189218949901206798437735558229; 58 | const std::complex i(0.,1.); 59 | 60 | const auto thetas = float_range(0., 2*pi, 100); 61 | 62 | for (const auto t: thetas) { 63 | const auto lhs = Li(2,std::exp(i*t)); 64 | const auto rhs = z2 - t*(2*pi - t)/4. + i*Cl(2,t); 65 | 66 | CHECK_CLOSE(std::real(lhs), std::real(rhs), 1e-14); 67 | CHECK_CLOSE(std::imag(lhs), std::imag(rhs), 1e-14); 68 | } 69 | } 70 | 71 | TEST_CASE("test_fixed_implementations") 72 | { 73 | using polylogarithm::Cl; 74 | using polylogarithm::Cl1; 75 | using polylogarithm::Cl2; 76 | using polylogarithm::Cl3; 77 | using polylogarithm::Cl4; 78 | using polylogarithm::Cl5; 79 | using polylogarithm::Cl6; 80 | 81 | const double pi = M_PI; 82 | const double eps = 1e-14; 83 | const auto thetas = float_range(0., 2*pi, 100); 84 | 85 | for (const auto t: thetas) { 86 | const auto cl1 = Cl1(t); 87 | const auto cl2 = Cl2(t); 88 | const auto cl3 = Cl3(t); 89 | const auto cl4 = Cl4(t); 90 | const auto cl5 = Cl5(t); 91 | const auto cl6 = Cl6(t); 92 | 93 | if (t != 0) { 94 | CHECK_CLOSE(cl1, Cl(1,t), eps); 95 | } 96 | CHECK_CLOSE(cl2, Cl(2,t), eps); 97 | CHECK_CLOSE(cl3, Cl(3,t), eps); 98 | CHECK_CLOSE(cl4, Cl(4,t), eps); 99 | CHECK_CLOSE(cl5, Cl(5,t), eps); 100 | CHECK_CLOSE(cl6, Cl(6,t), eps); 101 | } 102 | } 103 | 104 | // tests signbit for 0.0 and -0.0 arguments 105 | TEST_CASE("test_signed_zero") 106 | { 107 | // skip test if platform does not supprt signed zero 108 | if (!has_signed_zero()) { 109 | return; 110 | } 111 | 112 | using polylogarithm::Cl; 113 | 114 | const double pz64 = 0.0, nz64 = -0.0; 115 | 116 | for (int64_t n = 1; n <= 100; n++) { 117 | INFO("2*n = " << 2*n); 118 | CHECK( std::signbit(Cl(2*n, nz64))); 119 | CHECK(!std::signbit(Cl(2*n, pz64))); 120 | } 121 | } 122 | 123 | TEST_CASE("test_fixed_values") 124 | { 125 | const int ni[] = { 126 | 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 127 | 1000, 1001, 1000000 128 | }; 129 | 130 | for (const auto n: ni) { 131 | const std::string filename(std::string(TEST_DATA_DIR) + PATH_SEPARATOR + "Cl" + std::to_string(n) + ".txt"); 132 | const auto fixed_values = polylogarithm::test::read_reals_from_file(filename); 133 | 134 | for (const auto& v: fixed_values) { 135 | const auto x = v.first; 136 | const auto cl_expected = v.second; 137 | INFO("n = " << n << ", x = " << x); 138 | CHECK_CLOSE(polylogarithm::Cl(n, x), cl_expected, 1e-13); 139 | CHECK_CLOSE(Cl_via_Li(n, x), cl_expected, 1e-9); 140 | 141 | // test symmetries 142 | if (std::abs(std::fmod(x, 2*M_PI)) > 0.1 && std::abs(x - 2*M_PI) > 0.1) { 143 | const int sgn = n % 2 == 0 ? -1 : 1; 144 | CHECK_CLOSE(polylogarithm::Cl(n, x + 2*M_PI), cl_expected, 1e-10); 145 | CHECK_CLOSE(polylogarithm::Cl(n, x - 2*M_PI), cl_expected, 1e-10); 146 | CHECK_CLOSE(polylogarithm::Cl(n, -x ), sgn*cl_expected, 1e-10); 147 | CHECK_CLOSE(polylogarithm::Cl(n, -x ), sgn*cl_expected, 1e-10); 148 | } 149 | } 150 | } 151 | } 152 | 153 | TEST_CASE("test_duplication_formula") 154 | { 155 | using polylogarithm::Cl; 156 | 157 | const double pi = M_PI; 158 | const double eps = 1e-9; 159 | const auto thetas = float_range(0., pi, 100); 160 | 161 | for (const auto t: thetas) { 162 | for (int m = 1; m < 20; m++) { 163 | const int sgn = m % 2 == 0 ? 1 : -1; 164 | const double lhs = Cl(m+1,2*t); 165 | const double rhs = std::pow(2,m)*(Cl(m+1,t) + sgn*Cl(m+1,pi-t)); 166 | 167 | CHECK_CLOSE(lhs, rhs, eps); 168 | } 169 | } 170 | } 171 | 172 | TEST_CASE("test_roots") 173 | { 174 | using polylogarithm::Cl; 175 | const double pi = M_PI; 176 | 177 | for (int k = -10; k < 10; k++) { 178 | CHECK_SMALL(Cl(2,k*pi), 1e-14); 179 | } 180 | } 181 | -------------------------------------------------------------------------------- /test/test_Cl1.cpp: -------------------------------------------------------------------------------- 1 | #define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN 1 2 | 3 | #include "doctest.h" 4 | #include "Cl1.hpp" 5 | #include "read_data.hpp" 6 | #include "test.hpp" 7 | #include 8 | 9 | TEST_CASE("test_real_fixed_values") 10 | { 11 | const auto eps64 = std::pow(10.0 , -std::numeric_limits::digits10); 12 | const std::string filename(std::string(TEST_DATA_DIR) + PATH_SEPARATOR + "Cl1.txt"); 13 | const auto fixed_values = polylogarithm::test::read_reals_from_file(filename); 14 | 15 | for (auto v: fixed_values) { 16 | const auto x128 = v.first; 17 | const auto x64 = static_cast(x128); 18 | const auto cl128_expected = v.second; 19 | const auto cl64_expected = static_cast(cl128_expected); 20 | const auto cl64_poly = polylogarithm::Cl1(x64); 21 | 22 | INFO("x(64) = " << x64); 23 | INFO("Cl1(64) real = " << cl64_expected << " (expected)"); 24 | INFO("Cl1(64) real = " << cl64_poly << " (polylogarithm C++)"); 25 | 26 | CHECK_CLOSE(cl64_poly, cl64_expected, 4*eps64); 27 | CHECK_CLOSE(polylogarithm::Cl1(-x64), cl64_expected, 4*eps64); 28 | CHECK_CLOSE(polylogarithm::Cl1(x64 + 2*M_PI), cl64_expected, 10*eps64); 29 | CHECK_CLOSE(polylogarithm::Cl1(x64 - 2*M_PI), cl64_expected, 10*eps64); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /test/test_Li.cpp: -------------------------------------------------------------------------------- 1 | #define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN 1 2 | 3 | #include "doctest.h" 4 | #include "Li.hpp" 5 | #include "read_data.hpp" 6 | #include "test.hpp" 7 | #include 8 | #include 9 | #include 10 | 11 | TEST_CASE("test_infinite_values") 12 | { 13 | if (!has_inf()) { 14 | return; 15 | } 16 | 17 | using polylogarithm::Li; 18 | 19 | for (int n = -10; n <= 0; ++n) { 20 | CHECK(std::isinf(std::real(Li(n, 1.0)))); 21 | CHECK(std::isinf(std::imag(Li(n, 1.0)))); 22 | } 23 | } 24 | 25 | TEST_CASE("test_complex_fixed_values") 26 | { 27 | using polylogarithm::Li; 28 | 29 | const struct { 30 | int n; 31 | double eps; 32 | } nis[] = { 33 | // { -100, 1e-05 }, 34 | { -10, 1e-09 }, 35 | { -9, 1e-10 }, 36 | { -8, 1e-10 }, 37 | { -7, 1e-11 }, 38 | { -6, 1e-11 }, 39 | { -5, 1e-10 }, 40 | { -4, 1e-13 }, 41 | { -3, 1e-13 }, 42 | { -2, 1e-13 }, 43 | { -1, 1e-14 }, 44 | { 0, 1e-14 }, 45 | { 1, 1e-14 }, 46 | { 2, 1e-14 }, 47 | { 3, 1e-14 }, 48 | { 4, 1e-14 }, 49 | { 5, 1e-14 }, 50 | { 6, 1e-14 }, 51 | { 100, 1e-14 } 52 | }; 53 | 54 | for (const auto ni: nis) { 55 | const std::string filename(std::string(TEST_DATA_DIR) + PATH_SEPARATOR + "Li" + std::to_string(ni.n) + ".txt"); 56 | const auto values = polylogarithm::test::read_from_file(filename); 57 | 58 | for (auto v: values) { 59 | const auto z = v.first; 60 | const auto li_expected = v.second; 61 | const auto li = Li(ni.n, z); 62 | INFO("n = " << ni.n << ", z = " << z); 63 | CHECK_CLOSE_COMPLEX(li, li_expected, ni.eps); 64 | } 65 | } 66 | 67 | // value close to boundary between series 1 and 2 in arXiv:2010.09860 68 | CHECK_CLOSE_COMPLEX(Li(-2, -0.50001), -0.074072592582716422, 1e-14); 69 | 70 | const auto z = std::complex(1.5, 0.0); 71 | CHECK_CLOSE_COMPLEX(Li(10, z), std::complex(1.5022603281703005298, -2.56429642116111388671e-9), 1e-14); 72 | CHECK_CLOSE_COMPLEX(Li(10, -z), std::complex(-1.4978556954869267594, 0.0), 1e-14); 73 | } 74 | 75 | // tests signbit for 0.0 and -0.0 arguments 76 | TEST_CASE("test_signed_zero") 77 | { 78 | // skip test if platform does not supprt signed zero 79 | if (!has_signed_zero()) { 80 | return; 81 | } 82 | 83 | using polylogarithm::Li; 84 | 85 | const double pz64 = 0.0, nz64 = -0.0; 86 | 87 | // complex Li 88 | for (int n = -20; n <= 20; ++n) { 89 | CHECK( std::signbit(std::real(Li(n, std::complex(nz64, nz64))))); 90 | CHECK( std::signbit(std::imag(Li(n, std::complex(nz64, nz64))))); 91 | CHECK(!std::signbit(std::real(Li(n, std::complex(pz64, nz64))))); 92 | CHECK( std::signbit(std::imag(Li(n, std::complex(pz64, nz64))))); 93 | CHECK( std::signbit(std::real(Li(n, std::complex(nz64, pz64))))); 94 | CHECK(!std::signbit(std::imag(Li(n, std::complex(nz64, pz64))))); 95 | CHECK(!std::signbit(std::real(Li(n, std::complex(pz64, pz64))))); 96 | CHECK(!std::signbit(std::imag(Li(n, std::complex(pz64, pz64))))); 97 | } 98 | } 99 | 100 | template 101 | struct Data { 102 | int n; 103 | std::complex z; 104 | std::complex li_expected; 105 | T eps; 106 | }; 107 | 108 | TEST_CASE("test_overflow") 109 | { 110 | if (!has_inf()) { 111 | return; 112 | } 113 | 114 | using polylogarithm::Li; 115 | 116 | const double eps64 = std::pow(10.0, -std::numeric_limits::digits10); 117 | 118 | const Data data64[] = { 119 | {7, {1e300, 1.0}, {-1.4886831990993457e16, 4.74066248802866e14}, eps64}, 120 | {7, {1.0, 1e300}, {-1.489168315226607e16, 2.3705150998401e14}, eps64} 121 | }; 122 | 123 | for (const auto& d : data64) { 124 | CHECK_CLOSE_COMPLEX(Li(d.n, d.z), d.li_expected, d.eps); 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /test/test_Sl.cpp: -------------------------------------------------------------------------------- 1 | #define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN 1 2 | 3 | #include "doctest.h" 4 | #include "Sl.hpp" 5 | #include "Li.hpp" 6 | #include "read_data.hpp" 7 | #include "test.hpp" 8 | #include 9 | #include 10 | 11 | double Sl_via_Li(int64_t n, double x) 12 | { 13 | const std::complex li = polylogarithm::Li(n, std::polar(1.0, x)); 14 | 15 | if (n % 2 == 0) { 16 | return std::real(li); 17 | } 18 | 19 | return std::imag(li); 20 | } 21 | 22 | // tests signbit for 0.0 and -0.0 arguments 23 | TEST_CASE("test_signed_zero") 24 | { 25 | // skip test if platform does not supprt signed zero 26 | if (!has_signed_zero()) { 27 | return; 28 | } 29 | 30 | using polylogarithm::Sl; 31 | 32 | const double pz64 = 0.0, nz64 = -0.0; 33 | 34 | for (int64_t n = 0; n <= 100; n++) { 35 | INFO("2*n + 1 = " << 2*n + 1); 36 | CHECK( std::signbit(Sl(2*n + 1, nz64))); 37 | CHECK(!std::signbit(Sl(2*n + 1, pz64))); 38 | } 39 | } 40 | 41 | TEST_CASE("test_fixed_values") 42 | { 43 | const int ni[] = { 44 | 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 45 | 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 46 | 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 47 | 31, 1000, 1001 48 | }; 49 | 50 | for (const auto n: ni) { 51 | const std::string filename(std::string(TEST_DATA_DIR) + PATH_SEPARATOR + "Sl" + std::to_string(n) + ".txt"); 52 | const auto fixed_values = polylogarithm::test::read_reals_from_file(filename); 53 | 54 | for (const auto& v: fixed_values) { 55 | const auto x = v.first; 56 | const auto sl_expected = v.second; 57 | INFO("n = " << n << ", x = " << x); 58 | CHECK_CLOSE(polylogarithm::Sl(n, x), sl_expected, 1e-13); 59 | CHECK_CLOSE(Sl_via_Li(n, x), sl_expected, 1e-9); 60 | 61 | // test symmetries 62 | if (std::abs(std::fmod(x, 2*M_PI)) > 0.1 && std::abs(x - 2*M_PI) > 0.1) { 63 | const int sgn = n % 2 == 0 ? 1 : -1; 64 | CHECK_CLOSE(polylogarithm::Sl(n, x + 2*M_PI), sl_expected, 1e-10); 65 | CHECK_CLOSE(polylogarithm::Sl(n, x - 2*M_PI), sl_expected, 1e-10); 66 | CHECK_CLOSE(polylogarithm::Sl(n, -x ), sgn*sl_expected, 1e-10); 67 | CHECK_CLOSE(polylogarithm::Sl(n, -x ), sgn*sl_expected, 1e-10); 68 | } 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /test/test_eta.cpp: -------------------------------------------------------------------------------- 1 | #define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN 1 2 | 3 | #include "doctest.h" 4 | #include "eta.hpp" 5 | #include "test.hpp" 6 | #include 7 | 8 | TEST_CASE("test_fixed_values") 9 | { 10 | using polylogarithm::neg_eta; 11 | 12 | if (has_inf()) { 13 | CHECK(std::isinf(neg_eta(-221))); 14 | CHECK(std::isinf(neg_eta(-219))); 15 | } 16 | CHECK(neg_eta(-222) == 0.0); 17 | CHECK(neg_eta(-220) == 0.0); 18 | CHECK(neg_eta(-218) == 0.0); 19 | CHECK(neg_eta(-110) == 0.0); 20 | CHECK(neg_eta(-3) == 1.0/8); 21 | CHECK(neg_eta(-2) == 0.0); 22 | CHECK(neg_eta(-1) == -0.25); 23 | CHECK(neg_eta(0) == -0.5); 24 | CHECK(neg_eta(1) == -0.69314718055994531); 25 | CHECK(neg_eta(2) == -0.82246703342411322); 26 | CHECK(neg_eta(52) == -0.9999999999999998); 27 | CHECK(neg_eta(53) == -0.9999999999999999); 28 | CHECK(neg_eta(54) == -0.9999999999999999); 29 | CHECK(neg_eta(55) == -1.0); 30 | CHECK(neg_eta(56) == -1.0); 31 | } 32 | -------------------------------------------------------------------------------- /test/test_example.cpp: -------------------------------------------------------------------------------- 1 | #include "Li.hpp" 2 | #include "Li2.hpp" 3 | #include "Li3.hpp" 4 | #include "Li4.hpp" 5 | #include "Li5.hpp" 6 | #include "Li6.hpp" 7 | #include 8 | 9 | int main() { 10 | using namespace polylogarithm; 11 | 12 | const double x = 1.0; 13 | const std::complex z(1.0, 1.0); 14 | 15 | // real polylogarithms for real arguments 16 | std::cout 17 | << "Li_2(" << x << ") = " << Li2(x) << '\n' 18 | << "Li_3(" << x << ") = " << Li3(x) << '\n' 19 | << "Li_4(" << x << ") = " << Li4(x) << '\n'; 20 | 21 | // complex polylogarithms for complex arguments 22 | std::cout 23 | << "Li_2(" << z << ") = " << Li2(z) << '\n' 24 | << "Li_3(" << z << ") = " << Li3(z) << '\n' 25 | << "Li_4(" << z << ") = " << Li4(z) << '\n' 26 | << "Li_5(" << z << ") = " << Li5(z) << '\n' 27 | << "Li_6(" << z << ") = " << Li6(z) << '\n' 28 | << "Li_10(" << z << ") = " << Li(10,z) << '\n'; 29 | } 30 | -------------------------------------------------------------------------------- /test/test_factorial.cpp: -------------------------------------------------------------------------------- 1 | #define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN 1 2 | 3 | #include "doctest.h" 4 | #include "factorial.hpp" 5 | 6 | TEST_CASE("test_fixed_values") 7 | { 8 | using polylogarithm::inv_fac; 9 | 10 | CHECK(inv_fac( 0) == 1.0); 11 | CHECK(inv_fac( 1) == 1.0); 12 | CHECK(inv_fac( 2) == 0.5); 13 | CHECK(inv_fac(177) == 2.8547896502574379e-323); 14 | CHECK(inv_fac(178) == 0.0); 15 | } 16 | -------------------------------------------------------------------------------- /test/test_harmonic.cpp: -------------------------------------------------------------------------------- 1 | #define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN 1 2 | 3 | #include "doctest.h" 4 | #include "harmonic.hpp" 5 | #include "test.hpp" 6 | 7 | TEST_CASE("test_fixed_values") 8 | { 9 | using polylogarithm::harmonic; 10 | 11 | const double eps = 1e-15; 12 | 13 | CHECK_CLOSE(harmonic(1), 1.0, eps); 14 | CHECK_CLOSE(harmonic(2), 1.5, eps); 15 | CHECK_CLOSE(harmonic(19), 3.5477396571436819, eps); 16 | CHECK_CLOSE(harmonic(20), 3.5977396571436819, eps); 17 | CHECK_CLOSE(harmonic(100), 5.1873775176396203, eps); 18 | } 19 | -------------------------------------------------------------------------------- /test/test_log.cpp: -------------------------------------------------------------------------------- 1 | #define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN 1 2 | 3 | #include "doctest.h" 4 | #include "log.hpp" 5 | #include "test.hpp" 6 | #include 7 | #include 8 | 9 | // tests log(z) and log1p(1+z) for small complex z 10 | TEST_CASE("test_log_and_log1p") 11 | { 12 | if (!is_ieee754_compliant()) { 13 | return; 14 | } 15 | 16 | using namespace polylogarithm; 17 | 18 | const double eps = std::numeric_limits::epsilon(); 19 | // z = 9007155738389423 / 2^53 - (5069303045819176 / 2^60) I 20 | const std::complex z(0.999995168714454, -0.004396919500211628); 21 | const std::complex cpp_log(std::log(z)); 22 | const std::complex pl_log = pos_log(z); 23 | const std::complex pl_log1p = log1p(z); 24 | 25 | const std::complex expected_log(4.8351532915892516848328240700759518475389916e-6, 0.00439691240793594643979611108925073970426108463713022280825); 26 | const std::complex expected_log1p(0.693147181532726411790714997046464927858457, -0.002198461518912911475356949677977809228317); 27 | 28 | INFO("z = " << std::setprecision(17) << z); 29 | INFO("std::log(z) = " << cpp_log); 30 | INFO("pos_log(z) = " << std::complex(pl_log)); 31 | INFO("exp. log(z) = " << expected_log); 32 | INFO("log1p(z) = " << std::complex(pl_log1p)); 33 | INFO("exp. log1p(z) = " << expected_log1p); 34 | 35 | #ifndef __APPLE__ 36 | CHECK_CLOSE_REL(std::real(cpp_log), std::real(expected_log), eps); 37 | CHECK_CLOSE_REL(std::real(pl_log), std::real(expected_log), eps); 38 | #endif 39 | CHECK_CLOSE_REL(std::real(pl_log1p), std::real(expected_log1p), eps); 40 | } 41 | -------------------------------------------------------------------------------- /test/test_version.cpp: -------------------------------------------------------------------------------- 1 | #define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN 1 2 | 3 | #include "doctest.h" 4 | #include "version.h" 5 | #include 6 | 7 | TEST_CASE("test_version_string") 8 | { 9 | std::cout << "Polylogarithm version: " << POLYLOGARITHM_MAJOR << "." 10 | << POLYLOGARITHM_MINOR << "." << POLYLOGARITHM_PATCH << std::endl; 11 | CHECK(true); 12 | } 13 | -------------------------------------------------------------------------------- /test/test_zeta.cpp: -------------------------------------------------------------------------------- 1 | #define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN 1 2 | 3 | #include "doctest.h" 4 | #include "test.hpp" 5 | #include "zeta.hpp" 6 | #include 7 | 8 | TEST_CASE("test_fixed_values") 9 | { 10 | using polylogarithm::zeta; 11 | 12 | if (has_inf()) { 13 | CHECK(std::isinf(zeta(-263))); 14 | } 15 | CHECK(zeta(-262) == 0.0); 16 | if (has_inf()) { 17 | CHECK(std::isinf(zeta(-261))); 18 | } 19 | CHECK(zeta(-259) == 8.7601563446229215e306); 20 | CHECK(zeta(-257) == -5.1754977470366798e303); 21 | CHECK(zeta(-255) == 3.1055517596048927e300); 22 | CHECK(zeta(-4) == 0.0); 23 | CHECK(zeta(-3) == 1.0/120.0); 24 | CHECK(zeta(-2) == 0.0); 25 | CHECK(zeta(-1) == -1.0/12.0); 26 | CHECK(zeta(0) == -0.5); 27 | if (has_inf()) { 28 | CHECK(std::isinf(zeta(1))); 29 | } 30 | CHECK(zeta(2) == M_PI*M_PI/6.0); 31 | CHECK(zeta(32) == 1.0000000002328312); 32 | CHECK(zeta(33) == 1.0000000001164155); 33 | CHECK(zeta(34) == 1.0000000000582077); 34 | CHECK(zeta(35) == 1.0000000000291039); 35 | } 36 | --------------------------------------------------------------------------------