Opened 5 years ago

Last modified 5 years ago

#13360 new Bugs

std::numeric_limits<multiprecision::float128> methods fail to compile in C++11 mode

Reported by: b7.10110111@… Owned by: John Maddock
Milestone: To Be Determined Component: multiprecision
Version: Boost 1.66.0 Severity: Regression
Keywords: Cc: b7.10110111@…

Description

The following code compiles fine in C++03 mode, but fails in C++11 mode. This happens in boost 1.66.0, but didn't happen in 1.63.0.

#include <boost/multiprecision/float128.hpp>
int main()
{
    std::numeric_limits<boost::multiprecision::float128>::min();
}

Similar problem with some other methods — those which return without explicit construction of number_type.

I'm compiling with g++ using the following command line:

g++ -std=c++11 boost-test.cpp -o boost-test -fext-numeric-literals -lquadmath

The compiler prints the following error:

In file included from boost-test.cpp:1:0:
/usr/include/boost/multiprecision/float128.hpp: In instantiation of ‘static std::numeric_limits<boost::multiprecision::number<boost::multiprecision::backends::float128_backend, ExpressionTemplates> >::number_type std::numeric_limits<boost::multiprecision::number<boost::multiprecision::backends::float128_backend, ExpressionTemplates> >::min() [with boost::multiprecision::expression_template_option ExpressionTemplates = (boost::multiprecision::expression_template_option)0u; std::numeric_limits<boost::multiprecision::number<boost::multiprecision::backends::float128_backend, ExpressionTemplates> >::number_type = boost::multiprecision::number<boost::multiprecision::backends::float128_backend, (boost::multiprecision::expression_template_option)0u>]’:
boost-test.cpp:4:59:   required from here
/usr/include/boost/multiprecision/float128.hpp:645:55: error: could not convert ‘3.3621031431120935062626778173217526e-4932’ from ‘__float128’ to ‘std::numeric_limits<boost::multiprecision::number<boost::multiprecision::backends::float128_backend, (boost::multiprecision::expression_template_option)0u> >::number_type {aka boost::multiprecision::number<boost::multiprecision::backends::float128_backend, (boost::multiprecision::expression_template_option)0u>}’
    static number_type (min)() BOOST_NOEXCEPT { return 3.36210314311209350626267781732175260e-4932Q; }
                                                       ^

Change History (4)

comment:1 by John Maddock, 5 years ago

This is the by-product of fixing other issues, and I don't think we can fix it, except to say that using -std=gnu++11 works just fine.

The issue is that float128 literals are disabled with -std=c++11 but not -std=c++03 or -std=gnu++11. We can detect the -std=gnu++11 case and enable float128 support in that situation, but we can't detect that -fext-numeric-literals has been used with std=c++11 so float128 support is disabled in the library.

I'll look into trying to support this case with more config macros, but it might be easier to just issue better error messages when including the header in this situation.

Merry Christmas!

comment:2 by b7.10110111@…, 5 years ago

Not sure if this is the core problem, but what if we use the following constructs instead of quad literals?

using ldlims=std::numeric_limits<long double>;

constexpr auto max=__float128(ldlims::max())+
                       __float128(0x1.ffffffffffffp+16383L)*0x1.p-64;
constexpr auto min=__float128(ldlims::min());
constexpr auto denorm_min=__float128(ldlims::denorm_min())*0x1.p-49;
constexpr auto epsilon=__float128(ldlims::epsilon())*0x1.p-49;

These compile and work perfectly well with GCC (one of them, denorm_min, wasn't even implemented in boost, but is also doable, as shown above).

comment:3 by Ruslan Kabatsayev <b7.10110111@…>, 5 years ago

Cc: b7.10110111@… added

comment:4 by b7.10110111@…, 5 years ago

Actually, if we want to remain compatible to non-x87 FPUs, supporting IEEE754 binary64 as double, then we can do it this way:

    constexpr auto max=(__float128(0x1.fffffffffffffp+1023)
                        + 0x1.ffffffffffffp+970 + 0x1.ffcp+921)
                       * 0x1p+1023 * 0x1p+1023 * 0x1p+1023 * 0x1p+1023
                       * 0x1p+1023 * 0x1p+1023 * 0x1p+1023 * 0x1p+1023
                       * 0x1p+1023 * 0x1p+1023 * 0x1p+1023 * 0x1p+1023
                       * 0x1p+1023 * 0x1p+1023 * 0x1p+1023 * 0x1p+15;
    constexpr auto min=__float128(0x1p-1022) * 0x1p-1022
                       * 0x1p-1022 * 0x1p-1022 * 0x1p-1022
                       * 0x1p-1022 * 0x1p-1022 * 0x1p-1022
                       * 0x1p-1022 * 0x1p-1022 * 0x1p-1022
                       * 0x1p-1022 * 0x1p-1022 * 0x1p-1022
                       * 0x1p-1022 * 0x1p-1022 * 0x1p-30;
    constexpr auto denorm_min=__float128(0x1p-1022) * 0x1p-1022
                              * 0x1p-1022 * 0x1p-1022 * 0x1p-1022
                              * 0x1p-1022 * 0x1p-1022 * 0x1p-1022
                              * 0x1p-1022 * 0x1p-1022 * 0x1p-1022
                              * 0x1p-1022 * 0x1p-1022 * 0x1p-1022
                              * 0x1p-1022 * 0x1p-1022 * 0x1p-142;
    constexpr auto epsilon=__float128(0x1p-112);

    assert(max==std::numeric_limits<boost::multiprecision::float128>::max());
    assert(min==std::numeric_limits<boost::multiprecision::float128>::min());
    assert(epsilon==std::numeric_limits<boost::multiprecision::float128>::epsilon());
Note: See TracTickets for help on using tickets.