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.
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.
The following straightforward example takes a user-defined,
multiple-precision floating-point type from
Boost.Multiprecision.
It computes a complex-valued square root with
The square root value computed is
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;
}
Consider the Riemann-Zeta function. It is defined as
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
The program handles arguments in a relatively large (yet limited)
unit disc of radius e_float
code and paper. See also [1] in the references below.
The zeta-function calculation for a single complex-valued point having
In particular, the value of
is calculated.
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
where
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
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
This image showing
Plot[Abs[Zeta[(1/2) + (I t)]], {t, 1, 42}]
In example023a_riemann_zeta_zeros.cpp,
the first
The results found are:
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
These are not intended for finding record-breaking,
relatively low-precision counts of zero-crossings
on the critical line at
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
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 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.
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.
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
.
[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