Boost C++ Libraries

...one of the most highly regarded and expertly designed C++ library projects in the world. Herb Sutter and Andrei Alexandrescu, C++ Coding Standards

float128
PrevUpHomeNext

#include <boost/multiprecision/float128.hpp>

namespace boost{ namespace multiprecision{

class float128_backend;

typedef number<float128_backend, et_off>    float128;

}} // namespaces

The float128 number type is a very thin wrapper around GCC's __float128 or Intel's _Quad data types and provides an real-number type that is a drop-in replacement for the native C++ floating-point types, but with a 113 bit mantissa, and compatible with FORTRAN's 128-bit QUAD real.

All the usual standard library and std::numeric_limits support are available, performance should be equivalent to the underlying native types: for example the LINPACK benchmarks for GCC's __float128 and boost::multiprecision::float128 both achieved 5.6 MFLOPS[3].

As well as the usual conversions from arithmetic and string types, instances of float128 are copy constructible and assignable from GCC's __float128 and Intel's _Quad data types.

It's also possible to access the underlying __float128 or _Quad type via the data() member function of float128_backend.

Things you should know when using this type:

  • Default constructed float128s have the value zero.
  • This backend supports rvalue-references and is move-aware, making instantiations of number on this backend move aware.
  • This type is fully constexpr aware - basic constexpr arithmetic is supported from C++14 and onwards, comparisons, plus the functions fabs, abs, fpclassify, isnormal, isfinite, isinf and isnan are also supported if either the compiler implements C++20's std::is_constant_evaluated(), or if the compiler is GCC.
  • It is not possible to round-trip objects of this type to and from a string and get back exactly the same value when compiled with Intel's C++ compiler and using _Quad as the underlying type: this is a current limitation of our code. Round tripping when using __float128 as the underlying type is possible (both for GCC and Intel).
  • Conversion from a string results in a std::runtime_error being thrown if the string can not be interpreted as a valid floating-point number.
  • Division by zero results in an infinity being produced.
  • Type float128 can be used as a literal type (constexpr support).
  • Type float128 can be used for full constexpr arithmetic from C++14 and later with GCC. The functions abs, fabs, fpclassify, isnan, isinf, isfinite and isnormal are also constexpr, but the transcendental functions are not.
  • When using the Intel compiler, the underlying type defaults to __float128 if it's available and _Quad if not. You can override the default by defining either BOOST_MP_USE_FLOAT128 or BOOST_MP_USE_QUAD.
  • When the underlying type is Intel's _Quad type, the code must be compiled with the compiler option -Qoption,cpp,--extended_float_type.
  • When compiling with gcc, you need to use the flag --std=gnu++11/14/17, as the suffix 'Q' is a GNU extension. Compilation fails with the flag --std=c++11/14/17 unless you also use -fext-numeric-literals.
  • You will need to link to libquadmath.dll with the link command -lquadmath and ensure that the DLL is visible by the linker. If you are using the B2/bjam build system then commands<linkflags>-lQUADMATH and <linkflags>-L"path/to/lib" will be needed.
  • The values shown by std::numeric_limits<float128> and extremely close but not identical to those from the equivalent precision and range multiprecision types std::numeric_limits<cpp_bin_float_quad> and std::numeric_limits<cpp_dec_float_quad>.
float128 example:
#include <boost/type_index.hpp>
#include <boost/multiprecision/float128.hpp>
#include <boost/math/special_functions/gamma.hpp>
#include <iostream>

int main()
{
   using namespace boost::multiprecision; // Potential to cause name collisions?
   // using boost::multiprecision::float128; // is safer.

The type float128 provides operations at 128-bit precision with Quadruple-precision floating-point format and have full std::numeric_limits support:

float128 b = 2;

There are 15 bits of (biased) binary exponent and 113-bits of significand precision

std::cout << std::numeric_limits<float128>::digits << std::endl;

or 33 decimal places:

std::cout << std::numeric_limits<float128>::digits10 << std::endl;

We can use any C++ std library function, so let's show all the at-most 36 potentially significant digits, and any trailing zeros, as well:

 std::cout.setf(std::ios_base::showpoint); // Include any trailing zeros.
std::cout << std::setprecision(std::numeric_limits<float128>::max_digits10)
   << log(b) << std::endl; // Shows log(2) = 0.693147180559945309417232121458176575

We can also use any function from Boost.Math, for example, the 'true gamma' function tgamma:

std::cout << boost::math::tgamma(b) << std::endl;

And since we have an extended exponent range, we can generate some really large numbers here (4.02387260077093773543702433923004111e+2564):

std::cout << boost::math::tgamma(float128(1000)) << std::endl;

We can declare constants using GCC or Intel's native types, and literals with the Q suffix, and these can be declared constexpr if required:

// std::numeric_limits<float128>::max_digits10 = 36
constexpr float128 pi = 3.14159265358979323846264338327950288Q;
std::cout.precision(std::numeric_limits<float128>::max_digits10);
std::cout << "pi = " << pi << std::endl; //pi = 3.14159265358979323846264338327950280

Values for std::numeric_limits<float128> are:

GCC 14.1.0

Type name: boost::multiprecision::float128
Full name: boost::multiprecision::number<boost::multiprecision::backends::float128_backend, (boost::multiprecision::expression_template_option)0>

std::is_fundamental<> = false
boost::multiprecision::detail::is_signed<> = false
boost::multiprecision::detail::is_unsigned<> = false
boost::multiprecision::detail::is_integral<> = false
boost::multiprecision::detail::is_arithmetic<> = false
std::is_const<> = false
std::is_trivial<> = false
std::is_trivially_copyable<> = true
std::is_standard_layout<> = true
std::is_pod<> = false
std::numeric_limits<>::is_exact = false
std::numeric_limits<>::is_bounded = true
std::numeric_limits<>::is_modulo = false
std::numeric_limits<>::is_iec559 = true
std::numeric_limits<>::traps = false
std::numeric_limits<>::tinyness_before = false
std::numeric_limits<>::max() = 1.18973149535723176508575932662800702e+4932
std::numeric_limits<>::min() = 3.3621031431120935062626778173217526e-4932
std::numeric_limits<>::lowest() = -1.18973149535723176508575932662800702e+4932
std::numeric_limits<>::min_exponent = -16381
std::numeric_limits<>::max_exponent = 16384
std::numeric_limits<>::epsilon() = 1.92592994438723585305597794258492732e-34
std::numeric_limits<>::radix = 2
std::numeric_limits<>::digits = 113
std::numeric_limits<>::max_digits10 = 36
std::numeric_limits<>::has_denorm = 1
std::numeric_limits<>::denorm_min() = 6.47517511943802511092443895822764655e-4966
std::numeric_limits<>::has_denorm_loss = true
std::numeric_limits<>::has_signaling_NaN = false
std::numeric_limits<>::quiet_NaN() = nan
std::numeric_limits<>::infinity() = inf


[3] On 64-bit Ubuntu 11.10, GCC-4.8.0, Intel Core 2 Duo T5800.


PrevUpHomeNext