From 759523d9848581fdc0961696dda20c269377e7ec Mon Sep 17 00:00:00 2001
From: Simon Praetorius <simon.praetorius@tu-dresden.de>
Date: Fri, 8 Jun 2018 00:54:11 +0200
Subject: [PATCH] wrapper for quad precision floating point type

---
 cmake/modules/DuneCommonMacros.cmake |   1 +
 cmake/modules/FindQuadMath.cmake     |  54 +++++
 config.h.cmake                       |   4 +
 dune/common/CMakeLists.txt           |   1 +
 dune/common/float_cmp.cc             |  15 +-
 dune/common/fvector.hh               |   4 +
 dune/common/quadmath.hh              | 348 +++++++++++++++++++++++++++
 dune/common/test/CMakeLists.txt      |   4 +
 dune/common/test/fmatrixtest.cc      |  12 +
 dune/common/test/fvectortest.cc      |   2 +
 dune/common/test/quadmathtest.cc     |  64 +++++
 11 files changed, 506 insertions(+), 3 deletions(-)
 create mode 100644 cmake/modules/FindQuadMath.cmake
 create mode 100644 dune/common/quadmath.hh
 create mode 100644 dune/common/test/quadmathtest.cc

diff --git a/cmake/modules/DuneCommonMacros.cmake b/cmake/modules/DuneCommonMacros.cmake
index da58528ed..495610fa5 100644
--- a/cmake/modules/DuneCommonMacros.cmake
+++ b/cmake/modules/DuneCommonMacros.cmake
@@ -28,6 +28,7 @@ set_package_properties("LAPACK" PROPERTIES
 
 find_package(GMP)
 include(AddGMPFlags)
+find_package(QuadMath)
 find_package(Inkscape)
 include(UseInkscape)
 include(FindMProtect)
diff --git a/cmake/modules/FindQuadMath.cmake b/cmake/modules/FindQuadMath.cmake
new file mode 100644
index 000000000..fedb7a86c
--- /dev/null
+++ b/cmake/modules/FindQuadMath.cmake
@@ -0,0 +1,54 @@
+# .. cmake_module::
+#
+#    Find the GCC Quad-Precision library
+#
+#    Sets the following variables:
+#
+#    :code:`QUADMATH_FOUND`
+#       True if the Quad-Precision library was found.
+#
+#
+
+
+# search for the header quadmath.h
+include(CheckIncludeFile)
+check_include_file(quadmath.h QUADMATH_HEADER)
+
+include(CheckCSourceCompiles)
+include(CMakePushCheckState)
+
+cmake_push_check_state() # Save variables
+set(CMAKE_REQUIRED_LIBRARIES quadmath)
+check_c_source_compiles("
+#include <quadmath.h>
+
+int main ()
+{
+  __float128 r = 1.0q;
+  r = strtoflt128(\"1.2345678\", NULL);
+  return 0;
+}" QUADMATH_COMPILES)
+cmake_pop_check_state()
+
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(
+  "QuadMath"
+  DEFAULT_MSG
+  QUADMATH_HEADER
+  QUADMATH_COMPILES
+)
+
+# text for feature summary
+set_package_properties("QuadMath" PROPERTIES
+  DESCRIPTION "GCC Quad-Precision library")
+
+# set HAVE_QUADMATH for config.h
+set(HAVE_QUADMATH ${QUADMATH_FOUND})
+
+# register all QuadMath related flags
+if(HAVE_QUADMATH)
+  dune_register_package_flags(COMPILE_DEFINITIONS "ENABLE_QUADMATH=1" "_GLIBCXX_USE_FLOAT128=1"
+                              COMPILE_OPTIONS "-fext-numeric-literals"
+                              LIBRARIES "quadmath")
+endif()
diff --git a/config.h.cmake b/config.h.cmake
index e06c65b73..09dd40fb9 100644
--- a/config.h.cmake
+++ b/config.h.cmake
@@ -78,6 +78,10 @@
    to facilitate activating and deactivating GMP using compile flags. */
 #cmakedefine HAVE_GMP ENABLE_GMP
 
+/* Define if you have the GCC Quad-Precision library. The value should be ENABLE_QUADMATH
+   to facilitate activating and deactivating QuadMath using compile flags. */
+#cmakedefine HAVE_QUADMATH ENABLE_QUADMATH
+
 /* Define if you have the Vc library. The value should be ENABLE_VC
    to facilitate activating and deactivating Vc using compile flags. */
 #cmakedefine HAVE_VC ENABLE_VC
diff --git a/dune/common/CMakeLists.txt b/dune/common/CMakeLists.txt
index 2a8884210..521ff5f1b 100644
--- a/dune/common/CMakeLists.txt
+++ b/dune/common/CMakeLists.txt
@@ -92,6 +92,7 @@ install(FILES
         propertymap.hh
         promotiontraits.hh
         proxymemberaccess.hh
+        quadmath.hh
         rangeutilities.hh
         reservedvector.hh
         shared_ptr.hh
diff --git a/dune/common/float_cmp.cc b/dune/common/float_cmp.cc
index 582da7225..1dc18a89b 100644
--- a/dune/common/float_cmp.cc
+++ b/dune/common/float_cmp.cc
@@ -71,21 +71,30 @@ namespace Dune {
         static bool eq(const T &first,
                        const T &second,
                        typename EpsilonType<T>::Type epsilon = DefaultEpsilon<T>::value())
-        { return std::abs(first - second) <= epsilon*std::max(std::abs(first), std::abs(second)); }
+        {
+          using std::abs;
+          return abs(first - second) <= epsilon*std::max(abs(first), abs(second));
+        }
       };
       template<class T>
       struct eq_t<T, relativeStrong> {
         static bool eq(const T &first,
                        const T &second,
                        typename EpsilonType<T>::Type epsilon = DefaultEpsilon<T>::value())
-        { return std::abs(first - second) <= epsilon*std::min(std::abs(first), std::abs(second)); }
+        {
+          using std::abs;
+          return abs(first - second) <= epsilon*std::min(abs(first), abs(second));
+        }
       };
       template<class T>
       struct eq_t<T, absolute> {
         static bool eq(const T &first,
                        const T &second,
                        typename EpsilonType<T>::Type epsilon = DefaultEpsilon<T>::value())
-        { return std::abs(first-second) <= epsilon; }
+        {
+          using std::abs;
+          return abs(first-second) <= epsilon;
+        }
       };
       template<class T, CmpStyle cstyle>
       struct eq_t_std_vec {
diff --git a/dune/common/fvector.hh b/dune/common/fvector.hh
index d614cf8b3..579eaa6f9 100644
--- a/dune/common/fvector.hh
+++ b/dune/common/fvector.hh
@@ -339,6 +339,10 @@ namespace Dune {
 
     /** \brief Const conversion operator */
     operator const K& () const { return _data; }
+
+    template <class T,
+      std::enable_if_t<std::is_convertible<K,T>::value && std::is_arithmetic<T>::value, int> = 0>
+    operator T () const { return _data; }
   };
 
   /* ----- FV / FV ----- */
diff --git a/dune/common/quadmath.hh b/dune/common/quadmath.hh
new file mode 100644
index 000000000..fc18bc664
--- /dev/null
+++ b/dune/common/quadmath.hh
@@ -0,0 +1,348 @@
+// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+// vi: set et ts=4 sw=2 sts=2:
+#ifndef DUNE_FLOAT128_HH
+#define DUNE_FLOAT128_HH
+
+#if HAVE_QUADMATH
+#include <cmath>
+#include <cstddef>
+#include <cstdint>
+#include <cstdlib> // abs
+#include <istream>
+#include <ostream>
+#include <type_traits>
+#include <utility>
+#include <quadmath.h>
+
+#include <dune/common/typetraits.hh>
+
+namespace Dune
+{
+  namespace Impl
+  {
+    // forward declaration
+    class Float128;
+
+  } // end namespace Impl
+
+  using Impl::Float128;
+
+  // The purpose of this namespace is to move the `<cmath>` function overloads
+  // out of namespace `Dune`, see AlignedNumber in debugalign.hh.
+  namespace Impl
+  {
+    /// Wrapper for quad-precision type __float128
+    class Float128
+    {
+      __float128 value_ = 0.q;
+
+    public:
+      Float128() = default;
+      Float128(const __float128& value)
+        : value_(value)
+      {}
+
+      // constructor from any floating-point or integer type
+      template <class T,
+        std::enable_if_t<std::is_arithmetic<T>::value, int> = 0>
+      Float128(const T& number)
+        : value_(number)
+      {}
+
+      // accessors
+      operator __float128() const { return value_; }
+
+      __float128 const& value() const { return value_; }
+      __float128&       value()       { return value_; }
+
+      // I/O
+      template<class CharT, class Traits>
+      friend std::basic_istream<CharT, Traits>&
+      operator>>(std::basic_istream<CharT, Traits>& in, Float128& x)
+      {
+        std::string buf;
+        buf.reserve(128);
+        in >> buf;
+        x.value() = strtoflt128(buf.c_str(), NULL);
+        return in;
+      }
+
+      template<class CharT, class Traits>
+      friend std::basic_ostream<CharT, Traits>&
+      operator<<(std::basic_ostream<CharT, Traits>& out, const Float128& x)
+      {
+        const std::size_t bufSize = 128;
+        CharT buf[128];
+
+        std::string format = "%." + std::to_string(out.precision()) + "Q" +
+                              ((out.flags() | std::ios_base::scientific) ? "e" : "f");
+        const int numChars = quadmath_snprintf(buf, bufSize, format.c_str(), x.value());
+        if (std::size_t(numChars) >= bufSize) {
+          DUNE_THROW(Dune::RangeError, "Failed to print Float128 value: buffer overflow");
+        }
+        out << buf;
+        return out;
+      }
+
+      // Increment, decrement
+      Float128& operator++() { ++value_; return *this; }
+      Float128& operator--() { --value_; return *this; }
+
+      Float128 operator++(int) { Float128 tmp{*this}; ++value_; return tmp; }
+      Float128 operator--(int) { Float128 tmp{*this}; --value_; return tmp; }
+
+      // unary operators
+      Float128 operator+() const { return Float128{+value_}; }
+      Float128 operator-() const { return Float128{-value_}; }
+
+      // assignment operators
+#define DUNE_ASSIGN_OP(OP)                                              \
+      Float128& operator OP(const Float128& u)                          \
+      {                                                                 \
+        value_ OP u.value();                                            \
+        return *this;                                                   \
+      }                                                                 \
+      static_assert(true, "Require semicolon to unconfuse editors")
+
+      DUNE_ASSIGN_OP(+=);
+      DUNE_ASSIGN_OP(-=);
+
+      DUNE_ASSIGN_OP(*=);
+      DUNE_ASSIGN_OP(/=);
+#undef DUNE_ASSIGN_OP
+    };
+
+    // binary operators
+#define DUNE_BINARY_OP(OP)                                              \
+    Float128 operator OP(const Float128& t,                             \
+                         const Float128& u)                             \
+    {                                                                   \
+      return Float128{__float128(t) OP __float128(u)};                  \
+    }                                                                   \
+    template <class T,                                                  \
+      std::enable_if_t<std::is_arithmetic<T>::value, int> = 0>          \
+    Float128 operator OP(const T& t,                                    \
+                         const Float128& u)                             \
+    {                                                                   \
+      return Float128{__float128(t) OP __float128(u)};                  \
+    }                                                                   \
+    template <class U,                                                  \
+      std::enable_if_t<std::is_arithmetic<U>::value, int> = 0>          \
+    Float128 operator OP(const Float128& t,                             \
+                         const U& u)                                    \
+    {                                                                   \
+      return Float128{__float128(t) OP __float128(u)};                  \
+    }                                                                   \
+    static_assert(true, "Require semicolon to unconfuse editors")
+
+    DUNE_BINARY_OP(+);
+    DUNE_BINARY_OP(-);
+    DUNE_BINARY_OP(*);
+    DUNE_BINARY_OP(/);
+#undef DUNE_BINARY_OP
+
+#define DUNE_BINARY_BOOL_OP(OP)                                         \
+    bool operator OP(const Float128& t,                                 \
+                     const Float128& u)                                 \
+    {                                                                   \
+      return __float128(t) OP __float128(u);                            \
+    }                                                                   \
+    template <class T,                                                  \
+      std::enable_if_t<std::is_arithmetic<T>::value, int> = 0>          \
+    bool operator OP(const T& t,                                        \
+                     const Float128& u)                                 \
+    {                                                                   \
+      return __float128(t) OP __float128(u);                            \
+    }                                                                   \
+    template <class U,                                                  \
+      std::enable_if_t<std::is_arithmetic<U>::value, int> = 0>          \
+    bool operator OP(const Float128& t,                                 \
+                     const U& u)                                        \
+    {                                                                   \
+      return __float128(t) OP __float128(u);                            \
+    }                                                                   \
+    static_assert(true, "Require semicolon to unconfuse editors")
+
+    DUNE_BINARY_BOOL_OP(==);
+    DUNE_BINARY_BOOL_OP(!=);
+    DUNE_BINARY_BOOL_OP(<);
+    DUNE_BINARY_BOOL_OP(>);
+    DUNE_BINARY_BOOL_OP(<=);
+    DUNE_BINARY_BOOL_OP(>=);
+#undef DUNE_BINARY_BOOL_OP
+
+    // Overloads for the cmath functions
+#define DUNE_UNARY_FUNC(name,func)                                      \
+    Float128 name(const Float128& u)                                    \
+    {                                                                   \
+      return Float128{func(__float128(u))};                             \
+    }                                                                   \
+    static_assert(true, "Require semicolon to unconfuse editors")
+
+#define DUNE_CUSTOM_UNARY_FUNC(type,name,func)                          \
+    type name(const Float128& u)                                        \
+    {                                                                   \
+      return (type)(func(__float128(u)));                               \
+    }                                                                   \
+    static_assert(true, "Require semicolon to unconfuse editors")
+
+#define DUNE_BINARY_FUNC(name,func)                                     \
+    Float128 name(const Float128& t, const Float128& u)                 \
+    {                                                                   \
+      return Float128{func(__float128(t), __float128(u))};              \
+    }                                                                   \
+    static_assert(true, "Require semicolon to unconfuse editors")
+
+#define DUNE_TERTIARY_FUNC(name,func)                                   \
+    Float128 name(const Float128&t, const Float128& u, const Float128& v)  \
+    {                                                                   \
+      return Float128{func(__float128(t),__float128(u),__float128(v))}; \
+    }                                                                   \
+    static_assert(true, "Require semicolon to unconfuse editors")
+
+    DUNE_UNARY_FUNC(abs, fabsq);
+    DUNE_UNARY_FUNC(acos, acosq);
+    DUNE_UNARY_FUNC(acosh, acoshq);
+    DUNE_UNARY_FUNC(asin, asinq);
+    DUNE_UNARY_FUNC(asinh, asinhq);
+    DUNE_UNARY_FUNC(atan, atanq);
+    DUNE_BINARY_FUNC(atan2, atan2q);
+    DUNE_UNARY_FUNC(atanh, atanhq);
+    DUNE_UNARY_FUNC(cbrt, cbrtq);
+    DUNE_UNARY_FUNC(ceil, ceilq);
+    DUNE_BINARY_FUNC(copysign, copysignq);
+    DUNE_UNARY_FUNC(cos, cosq);
+    DUNE_UNARY_FUNC(cosh, coshq);
+    DUNE_UNARY_FUNC(erf, erfq);
+    DUNE_UNARY_FUNC(erfc, erfcq);
+    DUNE_UNARY_FUNC(exp, expq);
+    DUNE_UNARY_FUNC(expm1, expm1q);
+    DUNE_UNARY_FUNC(fabs, fabsq);
+    DUNE_BINARY_FUNC(fdim, fdimq);
+    DUNE_UNARY_FUNC(floor, floorq);
+    DUNE_TERTIARY_FUNC(fma, fmaq);
+    DUNE_BINARY_FUNC(fmax, fmaxq);
+    DUNE_BINARY_FUNC(fmin, fminq);
+    DUNE_BINARY_FUNC(fmod, fmodq);
+    DUNE_BINARY_FUNC(hypot, hypotq);
+    DUNE_CUSTOM_UNARY_FUNC(int, ilogb, ilogbq);
+    DUNE_UNARY_FUNC(lgamma, lgammaq);
+    DUNE_CUSTOM_UNARY_FUNC(long long int, llrint, llrintq);
+    DUNE_CUSTOM_UNARY_FUNC(long long int, llround, llroundq);
+    DUNE_UNARY_FUNC(log, logq);
+    DUNE_UNARY_FUNC(log10, log10q);
+    DUNE_UNARY_FUNC(log1p, log1pq);
+    DUNE_UNARY_FUNC(log2, log2q);
+    DUNE_UNARY_FUNC(logb, logbq);
+    DUNE_CUSTOM_UNARY_FUNC(long int, lrint, lrintq);
+    DUNE_CUSTOM_UNARY_FUNC(long int, lround, lroundq);
+    DUNE_UNARY_FUNC(nearbyint, nearbyintq);
+    DUNE_BINARY_FUNC(nextafter, nextafterq);
+    DUNE_BINARY_FUNC(pow, powq);
+    DUNE_BINARY_FUNC(remainder, remainderq);
+    DUNE_UNARY_FUNC(rint, rintq);
+    DUNE_UNARY_FUNC(round, roundq);
+    DUNE_UNARY_FUNC(sin, sinq);
+    DUNE_UNARY_FUNC(sinh, sinhq);
+    DUNE_UNARY_FUNC(sqrt, sqrtq);
+    DUNE_UNARY_FUNC(tan, tanq);
+    DUNE_UNARY_FUNC(tanh, tanhq);
+    DUNE_UNARY_FUNC(tgamma, tgammaq);
+    DUNE_UNARY_FUNC(trunc, truncq);
+
+    DUNE_CUSTOM_UNARY_FUNC(bool, isfinite, finiteq);
+    DUNE_CUSTOM_UNARY_FUNC(bool, isinf, isinfq);
+    DUNE_CUSTOM_UNARY_FUNC(bool, isnan, isnanq);
+    DUNE_CUSTOM_UNARY_FUNC(bool, signbit, signbitq);
+
+#undef DUNE_UNARY_FUNC
+#undef DUNE_BINARY_FUNC
+#undef DUNE_TERTIARY_FUNC
+#undef DUNE_CUSTOM_UNARY_FUNC
+
+    Float128 frexp(const Float128& u, int* p)
+    {
+      return Float128{frexpq(__float128(u),p)};
+    }
+
+    Float128 ldexp(const Float128& u, int p)
+    {
+      return Float128{ldexpq(__float128(u),p)};
+    }
+
+    Float128 nan(const char* arg)
+    {
+      return Float128{nanq(arg)};
+    }
+
+    Float128 remquo(const Float128& t, const Float128& u, int* quo)
+    {
+      return Float128{remquoq(__float128(t),__float128(u),quo)};
+    }
+
+    Float128 scalbln(const Float128& u, long int exp)
+    {
+      return Float128{scalblnq(__float128(u),exp)};
+    }
+
+    Float128 scalbn(const Float128& u, int exp)
+    {
+      return Float128{scalbnq(__float128(u),exp)};
+    }
+
+  } // end namespace Impl
+
+  template <>
+  struct IsNumber<Impl::Float128>
+      : public std::true_type {};
+
+} // namespace Dune
+
+namespace std
+{
+#ifndef NO_STD_NUMERIC_LIMITS_SPECIALIZATION
+  template <>
+  class numeric_limits<Dune::Impl::Float128>
+  {
+    using Float128 = Dune::Impl::Float128;
+
+  public:
+    static const bool is_specialized = true;
+    static Float128 min() { return FLT128_MIN; }
+    static Float128 max() { return FLT128_MAX; }
+    static Float128 lowest() { return -FLT128_MAX; }
+    static const int digits = FLT128_MANT_DIG;
+    static const int digits10 = FLT128_DIG;
+    static const int max_digits10 = 0;
+    static const bool is_signed = true;
+    static const bool is_integer = false;
+    static const bool is_exact = true;
+    static const int radix = 2;
+    static Float128 epsilon() { return FLT128_EPSILON; }
+    static Float128 round_error() { return __float128{0.5}; }
+    static const int min_exponent = FLT128_MIN_EXP;
+    static const int min_exponent10 = FLT128_MIN_10_EXP;
+    static const int max_exponent = FLT128_MAX_EXP;
+    static const int max_exponent10 = FLT128_MAX_10_EXP;
+    static const bool has_infinity = false;
+    static const bool has_quiet_NaN = true;
+    static const bool has_signaling_NaN = false;
+    static const float_denorm_style has_denorm = denorm_present;
+    static const bool has_denorm_loss = false;
+    static Float128 infinity() { return __float128{}; }
+    static Float128 quiet_NaN() { return nanq(""); }
+    static Float128 signaling_NaN() { return __float128{}; }
+    static Float128 denorm_min() { return FLT128_DENORM_MIN; }
+    static const bool is_iec559 = false;
+    static const bool is_bounded = false;
+    static const bool is_modulo = false;
+    static const bool traps = false;
+    static const bool tinyness_before = false;
+    static const float_round_style round_style = round_toward_zero;
+  };
+#endif
+} // end namespace std
+
+
+#endif // HAVE_QUADMATH
+#endif // DUNE_FLOAT128_HH
diff --git a/dune/common/test/CMakeLists.txt b/dune/common/test/CMakeLists.txt
index 0f39de56c..b95fbecc1 100644
--- a/dune/common/test/CMakeLists.txt
+++ b/dune/common/test/CMakeLists.txt
@@ -246,6 +246,10 @@ dune_add_test(SOURCES pathtest.cc
 dune_add_test(SOURCES poolallocatortest.cc
               LABELS quick)
 
+dune_add_test(SOURCES quadmathtest.cc
+              LINK_LIBRARIES dunecommon
+              CMAKE_GUARD HAVE_QUADMATH)
+
 dune_add_test(SOURCES rangeutilitiestest.cc
               LINK_LIBRARIES dunecommon
               LABELS quick)
diff --git a/dune/common/test/fmatrixtest.cc b/dune/common/test/fmatrixtest.cc
index f62f53323..648907f4f 100644
--- a/dune/common/test/fmatrixtest.cc
+++ b/dune/common/test/fmatrixtest.cc
@@ -18,6 +18,7 @@
 #include <dune/common/classname.hh>
 #include <dune/common/fmatrix.hh>
 #include <dune/common/ftraits.hh>
+#include <dune/common/quadmath.hh>
 #include <dune/common/rangeutilities.hh>
 #include <dune/common/simd/loop.hh>
 #include <dune/common/simd/simd.hh>
@@ -760,14 +761,25 @@ int main()
     ScalarOperatorTest<float>();
     test_matrix<double, double, double, 1, 1>();
     ScalarOperatorTest<double>();
+#if HAVE_QUADMATH
+    test_matrix<Dune::Float128, Dune::Float128, Dune::Float128, 1, 1>();
+    ScalarOperatorTest<Dune::Float128>();
+#endif
     // test n x m matrices
     test_interface<int, int, 10, 5>();
     test_matrix<int, int, int, 10, 5>();
     test_matrix<double, double, double, 5, 10>();
     test_interface<double, double, 5, 10>();
+#if HAVE_QUADMATH
+    test_matrix<Dune::Float128, Dune::Float128, Dune::Float128, 5, 10>();
+    test_interface<Dune::Float128, Dune::Float128, 5, 10>();
+#endif
     // mixed precision
     test_interface<float, float, 5, 10>();
     test_matrix<float, double, float, 5, 10>();
+#if HAVE_QUADMATH
+    test_matrix<float, double, Dune::Float128, 5, 10>();
+#endif
     // test complex matrices
     test_matrix<std::complex<float>, std::complex<float>, std::complex<float>, 1, 1>();
     test_matrix<std::complex<double>, std::complex<double>, std::complex<double>, 5, 10>();
diff --git a/dune/common/test/fvectortest.cc b/dune/common/test/fvectortest.cc
index f7680901d..f1476fc1e 100644
--- a/dune/common/test/fvectortest.cc
+++ b/dune/common/test/fvectortest.cc
@@ -14,6 +14,7 @@
 #include <dune/common/exceptions.hh>
 #include <dune/common/fvector.hh>
 #include <dune/common/gmpfield.hh>
+#include <dune/common/quadmath.hh>
 #include <dune/common/typetraits.hh>
 
 using Dune::FieldVector;
@@ -544,6 +545,7 @@ int main()
     FieldVectorTest<float, 3>();
     FieldVectorTest<double, 3>();
     FieldVectorTest<long double, 3>();
+    FieldVectorTest<Dune::Float128, 3>();
 #if HAVE_GMP
     // we skip the complex test and the int test, as these will be very hard to implement with GMPField
     typedef Dune::GMPField<128u> ft;
diff --git a/dune/common/test/quadmathtest.cc b/dune/common/test/quadmathtest.cc
new file mode 100644
index 000000000..973e66f63
--- /dev/null
+++ b/dune/common/test/quadmathtest.cc
@@ -0,0 +1,64 @@
+// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+// vi: set et ts=4 sw=2 sts=2:
+
+#include "config.h"
+
+#include <cassert>
+#include <iostream>
+
+#include <dune/common/fvector.hh>
+#include <dune/common/fmatrix.hh>
+#include <dune/common/float_cmp.hh>
+#include <dune/common/quadmath.hh>
+#include <dune/common/test/testsuite.hh>
+
+using namespace Dune;
+
+template <class T>
+struct Comparator
+{
+  bool operator()(T const& x, T const& y) { return Dune::FloatCmp::eq(x, y); }
+};
+
+
+int main()
+{
+  // check vector and matrix type with Float128 field type
+  TestSuite test{};
+  Comparator<Float128> cmp{};
+
+  FieldVector<Float128,3> v{1,2,3}, x;
+  FieldMatrix<Float128,3,3> M{ {1,2,3}, {2,3,4}, {3,4,6} }, A;
+  FieldMatrix<Float128,3,3> M2{ {1,2,3}, {2,3,4}, {3,4,7} };
+
+  auto y1 = v.one_norm();
+  test.check(cmp(y1, 6.q), "vec.one_norm()");
+
+  auto y2 = v.two_norm();
+  test.check(cmp(y2, sqrtq(14.q)), "vec.two_norm()");
+
+  auto y3 = v.infinity_norm();
+  test.check(cmp(y3, 3.q), "vec.infinity_norm()");
+
+  M.mv(v, x);   // x = M*v
+  M.mtv(v, x);  // x = M^T*v
+  M.umv(v, x);  // x+= M*v
+  M.umtv(v, x); // x+= M^T*v
+  M.mmv(v, x);  // x-= M*v
+  M.mmtv(v, x); // x-= M^T*v
+
+  auto w1 = M.infinity_norm();
+  test.check(cmp(w1, 13.q), "mat.infinity_norm()");
+
+  auto w2 = M.determinant();
+  test.check(cmp(w2, -1.q), "mat.determinant()");
+
+  M.solve(v, x);  // x = M^(-1)*v
+
+  auto M3 = M.leftmultiplyany(M2);
+  auto M4 = M.rightmultiplyany(M2);
+
+  using namespace FMatrixHelp;
+
+  invertMatrix(M,A);
+}
-- 
GitLab