Skip to content

ckormanyos/extended_complex

Repository files navigation

extended_complex

Build Status Boost Software License 1.0

ckormanyos/extended_complex creates an extended complex-number adaption class. The project is written in header-only C++14, and compatible through C++14, 17, 20, 23 and beyond.

The extended_complex::complex template class can be used with both built-in floating-point types as well as user-defined numeric types.

The complete template signature of the complex class is shown below.

namespace extended_complex {

// Forward declaration of the complex template class.

template<typename T, typename EnableType = void>
class complex;

} // namespace extended_complex

The template parameter T is is intended to be a built-in floating-point type or a user-defined numeric type. The EnableType should not be changed. It is used internally to distinguish built-in floating-point types from user-defined numeric types.

Potential Use Cases

There are numerous potential use cases for ckormanyos/extended_complex. These include (but are not limited to) the following and more.

  • Instantiate complex-valued types for user-defined types including multiple-precision types or hardware-emulated types.
  • Perform complex-valued calculations with standard built-in types if STL support for <complex> is missing, as may be the case for certain tiny embedded systems.
  • Verify other complex-valued implementations.

Example

The following straightforward example takes a user-defined, multiple-precision floating-point type from Boost.Multiprecision. It computes a complex-valued square root with ${\sim}~100$ decimal digits of precision.

The square root value computed is

$$ \sqrt { \frac{12}{10} + \frac{34}{10}i } $$

$$ {\approx}1.550088912847258141616{\ldots}{+}~1.096711282759503047577{\ldots}~i{\text{.}} $$

The example code is listed in its entirety below. It is also available live at Godbolt.

#include <extended_complex.h>

#include <boost/multiprecision/cpp_dec_float.hpp>

#include <iomanip>
#include <iostream>

namespace local
{
  template<typename NumericType>
  auto is_close_fraction(const NumericType& a,
                         const NumericType& b,
                         const NumericType& tol = std::numeric_limits<NumericType>::epsilon() * 64) noexcept -> bool
  {
    using std::fabs;

    return (fabs(1 - (a / b)) < tol);
  }
} // namespace local

auto main() -> int
{
  using complex_type = extended_complex::complex<boost::multiprecision::number<boost::multiprecision::cpp_dec_float<100>, boost::multiprecision::et_off>>;

  using real_type = typename complex_type::value_type;

  const complex_type val_z1(real_type(12U) / 10U, real_type(34U) / 10U);

  const complex_type sqrt_result { sqrt(val_z1) };

  const real_type ctrl_real { "+1.5500889128472581416161256546038815669761567486848749301860666965618993040312647033986371788677357208" };
  const real_type ctrl_imag { "+1.096711282759503047577277387056220643003106823143745046422869808875853261131777962620301480493467395" };

  const auto result_is_ok = (   local::is_close_fraction(sqrt_result.real(), ctrl_real)
                             && local::is_close_fraction(sqrt_result.imag(), ctrl_imag));

  // Visualize if the result is OK.
  std::stringstream strm { };

  strm << std::setprecision(static_cast<std::streamsize>(std::numeric_limits<real_type>::digits10))
       << sqrt_result;

  // Print the result-OK indication.
  strm << "\nresult_is_ok: " << std::boolalpha << result_is_ok;

  std::cout << strm.str() << std::endl;
}

In-Depth Example

Complex-Valued Riemann-Zeta Function

Consider the Riemann-Zeta function. It is defined as

$$ {\zeta}\left( s \right)=\sum_{n=1}^{\infty}\frac{1}{n^s}{\text{.}} $$

An in-depth, non-trivial example provides a header-only, multiprecision implementation of the complex-valued Riemann-Zeta function. The complex-valued Riemann-zeta function has one simple pole at $1$.

The program handles arguments in a relatively large (yet limited) unit disc of radius ${\sim}~{10}^{6}$ in ${\mathbb{C}}$. This example uses the algorithm described and found in the e_float code and paper. See also [1] in the references below.

The zeta-function calculation for a single complex-valued point having $101$ decimal digits of precision can also be seen here.

In particular, the value of

$$ {\zeta}{\Bigl(}\frac{11}{10} + \frac{23}{10}i{\Bigr)} $$

$$ {\approx}0.632109498389343535342{\ldots}{-}~0.265505793636743413620{\ldots}~i $$

is calculated.

Number Theory and Zeros on the Critical Line

The complex-valued Riemann-Zeta function plays a central role in number theory.

The so-called critical strip refers to the region in the complex plane for which the argument $z$ of the complex-valued Riemann-Zeta function ${\zeta}(z)$ is

$$ z={\sigma}~+~it{\mbox{,}} $$

where $0~&lt;{\sigma}~&lt;1$.

It is believed that there are infinitely many non-trivial roots (zeros) of the complex-valued Riemann-Zeta function. It is, in fact, thought that the critical strip contains all of these non-trivial zeros. Note that negative, even integer zeros are considered trivial.

This characteristic of the Riemann-Zeta function forges deep connections to both prime numbers as well as analytical and theoretical number theory.

The Riemann Hypothesis, for instance, states that all non-trivial zeros of the Riemann zeta function are localized even further and lie on the critical line at ${\sigma}~=~1/2$. The statement of the Riemann Hypothesis is profoudly significant due to its inate implicative and symbiotic relation to prime numbers and the distribution of prime numbers.

The bold conjecture of the Riemann Hypothesis remains unproven despite significant efforts by mathematicians to prove it.

The graph below visualizes the absolute value of the complex-valued Riemann-Zeta function on a small segment of the critical line. The first $7$ non-trivial zeros are visible.

This image showing $\vert\zeta(z)\vert$ on a small segment of the critical line has been obtained from WolframAlpha(R) using the following command.

Plot[Abs[Zeta[(1/2) + (I t)]], {t, 1, 42}]

In example023a_riemann_zeta_zeros.cpp, the first $7$ non-trivial zeros of the complex-valued Riemann-Zeta function on the critical line are calculated to ${\sim}~501$ decimal digits of precision. Root finding uses the implementation of Algorithm 748 found in Boost.Math. See also [2] in the references below.

The results found are:

$$ t_{0}~{\approx}~14.134725141734693790457251983562470270784257115699{\ldots} $$

$$ t_{1}~{\approx}~21.022039638771554992628479593896902777334340524902{\ldots} $$

$$ t_{2}~{\approx}~25.010857580145688763213790992562821818659549672557{\ldots} $$

$$ t_{3}~{\approx}~30.424876125859513210311897530584091320181560023715{\ldots} $$

$$ t_{4}~{\approx}~32.935061587739189690662368964074903488812715603517{\ldots} $$

$$ t_{5}~{\approx}~37.586178158825671257217763480705332821405597350830{\ldots} $$

$$ t_{6}~{\approx}~40.918719012147495187398126914633254395726165962777{\ldots} $$

Not Number-Theory-Ready

The range and domain of the Riemann-Zeta calculations in the particular examples described above are designed for high-precision investigations within the above-mentioned unit-disc of radius ${\sim}~{10}^{6}$ in ${\mathbb{C}}$.

These are not intended for finding record-breaking, relatively low-precision counts of zero-crossings on the critical line at ${\sigma}=1/2$. These are valuable for providing empirical evidence for prime number investigations in number-theory. Other algorithms are needed for this type of number-theoretical research. See also [3] for a summary of these methods and a recent record-breaking calculation.

Testing

A small test program exercises a variety of non-trivial algebraic and elementary-function values. The test program verifies the extended-complex class for both built-in floating point types float, double and long double as well as a $100$-decimal digit type from Boost.Multiprecision. The above-mentioned in-depth Riemann-Zeta examples are also executed and verified in the tests.

These in-depth, combined test suites are used in CI to verify the expected functionality. They are also employed to obtain code coverage results.

Continuous Integration

Continuous integration runs on Ubuntu and MacOS with both GCC/clang and also runs on Windows with MSVC. GCC's run-time sanitizers are also used in CI in order to help assure dynamic quality. CI uses the develop branch of modular-boost, when needed, for multiprecision types and root-finding.

Additional details

ckormanyos/extended_complex has been tested with numerous compilers, including target systems ranging from eight to sixty-four bits. The library is specifically designed for dualistic efficiency and portability.

Configuration macros (compile-time)

Various configuration features can optionally be enabled or disabled at compile time with compiler switches. These are described in the following paragraphs.

#define EXTENDED_COMPLEX_DISABLE_IOSTREAM

When working with even the most tiny microcontroller systems, I/O-streaming can optionally be disabled with the compiler switch EXTENDED_COMPLEX_DISABLE_IOSTREAM. The default setting is EXTENDED_COMPLEX_DISABLE_IOSTREAM not set and I/O streaming operations are enabled.

#define EXTENDED_COMPLEX_CONSTEXPR constexpr

The macro EXTENDED_COMPLEX_CONSTEXPR is default-defined to be equal to the word constexpr. This macro was previously used (for old compilers no longer supported) to either use or un-use the word constexpr. This was back when constexpr was relatively new. At this time, simply leave this macro unchanged. It is default-set to the word constexpr.

References

[1] C.M. Kormanyos, Algorithm 910: A Portable C++ Multiple-Precision System for Special-Function Calculations, ACM Transactions on Mathematical Software, Vol. 37, Issue 4, pp 1-27 (01 February 2011), https://doi.org/10.1145/1916461.1916469.

[2] G.E. Alefeld, F.A. Potra, Yixun Shi, Algorithm 748: enclosing zeros of continuous functions, ACM Transactions on Mathematical Software, Vol. 21, Issue 3, pp 327-344 (01 September 1995), https://doi.org/10.1145/210089.210111.

[3] D. Platt and T. Trudgian, The Riemann hypothesis is true up to ${\mbox{\textit{3}}}{\cdot}{\mbox{\textit{10}}}^{\mbox{\textit{\small{12}}}}$, arXiv:2004.09765.

About

Extended-complex adaption-class in modern C++

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages