boostorg / multiprecision

Boost.Multiprecision
Boost Software License 1.0
194 stars 111 forks source link

Compiling float128 failed in g++ 13.2 with the latest boost::multiprecision #569

Open seanxnie opened 10 months ago

seanxnie commented 10 months ago

Dear all. I just encountered an issue when compiling the following code, which is to invoke the boost::math::expm1 function.

#include <boost/multiprecision/float128.hpp>
#include <boost/math/constants/constants.hpp>
#include <boost/math/special_functions/bessel.hpp>
//#include <boost/multiprecision/mpfr.hpp>

using T = boost::multiprecision::float128;
//using T = boost::multiprecision::mpfr_float_50;

int main() {

    T m_pi = boost::math::constants::pi<T>();
    T term = boost::math::expm1(m_pi); // compiling error
}

The command line for compiling code is:

 /usr/bin/g++ -std=c++20 -Iinclude/ -lquadmath -lmpfr -g -Wall expm1test.cpp -o expm1test

The compiler error output is considerable. However, the main issue is max min type conversion:

expm1test.cpp:12:32:   required from here
include/boost/multiprecision/float128.hpp:162:66: error: could not convert ‘boost::multiprecision::quad_constants::quad_max’ from ‘const float128_type’ {aka ‘const __float128’} to ‘std::numeric_limits<boost::multiprecision::number<boost::multiprecision::backends::float128_backend, boost::multiprecision::et_off> >::number_type’ {aka ‘boost::multiprecision::number<boost::multiprecision::backends::float128_backend, boost::multiprecision::et_off>’}
  162 | #define BOOST_MP_QUAD_MAX boost::multiprecision::quad_constants::quad_max
      |                           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~
      |                                                                  |
      |                                                                  const float128_type {aka const __float128}
include/boost/multiprecision/float128.hpp:820:73: notes: in expansion of macro ‘BOOST_MP_QUAD_MAX’
  820 |    static BOOST_MP_CXX14_CONSTEXPR number_type(max)() noexcept { return BOOST_MP_QUAD_MAX; }
      |                                                                         ^~~~~~~~~~~~~~~~~

In above code, this issue will disappear if replacing float128 by mpfr_float_50. The boost::multiprecision I used is the latest development version. The error happens whenever a math function needs to invoke max min of float128. It seems that a bug exists in float128.hpp in boost. I hope the information above is enough to find the issue. Thanks a lot.

Sean

mborland commented 10 months ago

Does the issue persist if you build with -std=gnu++20 instead of -std=c++20?

seanxnie commented 10 months ago

Does the issue persist if you build with -std=gnu++20 instead of -std=c++20?

Yes, the issue is solved. This is to enable gnu extensions in c++20. Thank you!

jzmaddock commented 10 months ago

Just to confirm, that float128.hpp does indeed require gnu++XX not c++-XX, it should be documented somewhere...

seanxnie commented 10 months ago

Just to confirm, that float128.hpp does indeed require gnu++XX not c++-XX, it should be documented somewhere...

As far as my findings from boost.org and pdfs, requiring gnu++XX in float128 is not documented.

jzmaddock commented 10 months ago

I think you're right actually, I dimly remember removing that restriction, hence the use of quad_min/quad_max rather than Q suffixed constants. Will investigate further...

ckormanyos commented 10 months ago

hence the use of quad_min/quad_max rather than Q suffixed constants. Will investigate further...

Ummm, I'm not the expert here, but I think what the -std=gnuXX language extensions do is add numeric_limits support and the quad-suffixes. I'm not sure if anything else is added.

I'm almost certain that the fundamental support of libquadmath is available in c++-standards.

Check it at Godbolt.

ckormanyos commented 10 months ago

Admittedly, __float128 has been a long-time source of confusion for me personally. And I've made a few mistakes down that road with assumptioins...

ckormanyos commented 10 months ago

My example was not nice. Here is a better one.

jzmaddock commented 10 months ago

OK, so here's the issue... we used to rely on Q suffixed constants for numeric_limits support, those were removed so that's all good. The issue here is convertibility... float128 is only explicitly convertible to type number when building with c++XX rather than gnu++XX.... and the reason for that is that float128 is not an arithmetic type (according to ) when building with c++XX.... and we have a general rule in place that "arithmetic types are always implicitly convertible, everything else is only explicitly convertible and only if the backend has a suitable constructor".

So either.... we change the convertibility rules so that float128 is always treated as an arithmetic type, or I just add some explicit casts to the numeric_Limits functions. The former seems more logical, but messes up the enable_if logic if we have to treat float128 as a special case.

I also have a hunch that we're not testing any of this, so the testing logic needs looking at too...

mborland commented 10 months ago

OK, so here's the issue... we used to rely on Q suffixed constants for numeric_limits support, those were removed so that's all good. The issue here is convertibility... float128 is only explicitly convertible to type number when building with c++XX rather than gnu++XX.... and the reason for that is that float128 is not an arithmetic type (according to ) when building with c++XX.... and we have a general rule in place that "arithmetic types are always implicitly convertible, everything else is only explicitly convertible and only if the backend has a suitable constructor".

So either.... we change the convertibility rules so that float128 is always treated as an arithmetic type, or I just add some explicit casts to the numeric_Limits functions. The former seems more logical, but messes up the enable_if logic if we have to treat float128 as a special case.

I also have a hunch that we're not testing any of this, so the testing logic needs looking at too...

As a note the specializations of numeric_limits is changing in GCC 14: https://github.com/boostorg/math/issues/992. I am not sure off hand if that is the case for too.

ckormanyos commented 10 months ago

__float128 is not an arithmetic type

Oh yes. That was one of the other things that is enabled by -std=gnu++XX as opposed to -std=c++XX. The former (GNU) also supports __float128 as a built-in type in the sense of <type_traits>.

We need a list somewhere reminding what does and does not happen to __float128 in GNU/non-GNU.

ckormanyos commented 10 months ago

This program showcases what is available for __float128 when using -std=gnu++XX.