Quadruple-precision float tutorial

The real128 class is a thin wrapper around the __float128 type available in GCC and (more recently) clang. __float128 is an implementation the quadruple-precision IEEE 754 binary floating-point standard, which provides up to 36 decimal digits of precision.

real128 is available in mp++ if the library is configured with the MPPP_WITH_QUADMATH option enabled (see the installation instructions). Note that mp++ needs access to the quadmath library libquadmath.so, which may be installed in a non-standard location. While GCC is typically able to resolve the correct path automatically, clang might need assistance in order to identify the correct location of this library.

As a thin wrapper, real128 adds a few extra features on top of what __float128 already provides. Specifically, real128:

  • can interact with the other mp++ classes,

  • can be constructed from string-like objects,

  • supports the standard C++ iostream facilities.

Like __float128, real128 is a literal type, and thus it can be used for constexpr compile-time computations. Additionally, real128 implements as constexpr constructs a variety of functions which are not constexpr for __float128.

In addition to the features common to all mp++ classes, the real128 API provides a few additional capabilities:

  • construction/conversion from/to __float128:

    real128 r{__float128(42)};                // Construction from a __float128.
    assert(r == 42);
    assert(static_cast<__float128>(r) == 42); // Conversion to __float128.
    
  • direct access to the internal __float128 instance (via the public m_value data member):

    real128 r{1};
    r.m_value += 1;                 // Modify directly the internal __float128 member.
    assert(r == 2);
    
    r.m_value = 0;
    assert(::cosq(r.m_value) == 1); // Call a libquadmath function directly on the internal member.
    
  • a variety of mathematical functions wrapping the libquadmath library routines. Note that the real128 function names drop the suffix q appearing in the names of the libquadmath routines, and, as usual in mp++, they are supposed to be found via ADL. Member function overloads for the unary functions are also available:

    real128 r{42};
    
    // Trigonometry.
    assert(cos(r) == ::cosq(r.m_value));
    assert(sin(r) == ::sinq(r.m_value));
    
    // Logarithms and exponentials.
    assert(exp(r) == ::expq(r.m_value));
    assert(log10(r) == ::log10q(r.m_value));
    
    // Etc.
    assert(lgamma(r) == ::lgammaq(r.m_value));
    assert(erf(r) == ::erfq(r.m_value));
    
    // Member function overloads.
    auto tmp = cos(r);
    assert(r.cos() == tmp); // NOTE: r.cos() will set r to its cosine.
    tmp = sin(r);
    assert(r.sin() == tmp); // NOTE: r.sin() will set r to its sine.
    
  • NaN-friendly hashing and comparison functions, for use in standard algorithms and containers;

  • a specialisation of the std::numeric_limits class template;

  • a selection of quadruple-precision compile-time mathematical constants.

The real128 reference contains the detailed description of all the features provided by real128.

User-defined literal

New in version 0.19.

A user-defined literal is available to construct mppp::real128 instances. The literal is defined within the inline namespace mppp::literals, and it supports decimal and hexadecimal representations:

using namespace mppp::literals;

auto r1 = 123.456_rq;   // r1 contains the quadruple-precision
                        // approximation of 123.456 (that is,
                        // 123.455999999999999999999999999999998).

auto r2 = 4.2e1_rq;     // Scientific notation can be used.

auto r3 = 0x1.12p-1_rq; // Hexadecimal floats are supported too.