Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions include/boost/multiprecision/float128.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include <cfloat>
#include <tuple>
#include <cstring>
#include <complex>
#include <boost/multiprecision/detail/standalone_config.hpp>
#include <boost/multiprecision/number.hpp>
#include <boost/multiprecision/detail/hash.hpp>
Expand Down Expand Up @@ -710,6 +711,29 @@ inline boost::multiprecision::number<float128_backend, ExpressionTemplates> rsqr
return res;
}

// The default std::abs(std::complex<>) implementation normalizes by max(|re|, |im|),
// which yields NaN when an input is infinite (inf/inf).
// Per IEEE 754, the result must be +infinity if either component is infinite, even if the other is NaN.
template <boost::multiprecision::expression_template_option ExpressionTemplates>
inline boost::multiprecision::number<float128_backend, ExpressionTemplates>
abs BOOST_PREVENT_MACRO_SUBSTITUTION(const std::complex<boost::multiprecision::number<float128_backend, ExpressionTemplates>>& z)
{
using number_type = boost::multiprecision::number<float128_backend, ExpressionTemplates>;
const float128_type re_v = z.real().backend().value();
const float128_type im_v = z.imag().backend().value();
#ifdef BOOST_MP_USE_FLOAT128
return number_type(::hypotq(re_v, im_v));
#else
if (isinfq(re_v) || isinfq(im_v))
{
return std::numeric_limits<number_type>::infinity();
}
const float128_type re_abs = re_v < 0 ? -re_v : re_v;
const float128_type im_abs = im_v < 0 ? -im_v : im_v;
return number_type(sqrtq(re_abs * re_abs + im_abs * im_abs));
#endif
}

#ifndef BOOST_MP_USE_QUAD
template <multiprecision::expression_template_option ExpressionTemplates>
inline boost::multiprecision::number<boost::multiprecision::backends::float128_backend, ExpressionTemplates> copysign BOOST_PREVENT_MACRO_SUBSTITUTION(const boost::multiprecision::number<boost::multiprecision::backends::float128_backend, ExpressionTemplates>& a, const boost::multiprecision::number<boost::multiprecision::backends::float128_backend, ExpressionTemplates>& b)
Expand Down
1 change: 1 addition & 0 deletions test/Jamfile.v2
Original file line number Diff line number Diff line change
Expand Up @@ -1281,6 +1281,7 @@ test-suite misc :
[ run git_issue_636.cpp : : : [ check-target-builds ../config//has_float128 : <source>quadmath : <build>no ] ]
[ run git_issue_652.cpp ]
[ run git_issue_734.cpp ]
[ run git_issue_759.cpp : : : [ check-target-builds ../config//has_float128 : <source>quadmath : <build>no ] ]
[ compile git_issue_98.cpp :
[ check-target-builds ../config//has_float128 : <define>TEST_FLOAT128 <source>quadmath : ]
[ check-target-builds ../config//has_gmp : <define>TEST_GMP <source>gmp : ]
Expand Down
68 changes: 68 additions & 0 deletions test/git_issue_759.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright 2026 Matt Borland. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See: https://github.com/boostorg/multiprecision/issues/759

#include <complex>
#include <iostream>
#include <limits>
#include <boost/multiprecision/float128.hpp>
#include "test.hpp"

int main()
{
using REAL = boost::multiprecision::float128;

const REAL inf_v = std::numeric_limits<REAL>::infinity();

{
using std::abs;
const REAL r = abs(inf_v);
BOOST_CHECK((boost::multiprecision::isinf)(r));
}

{
using std::abs;
const std::complex<REAL> z{inf_v, REAL(0)};
const REAL r = abs(z);
BOOST_CHECK((boost::multiprecision::isinf)(r));
BOOST_CHECK(!(boost::multiprecision::isnan)(r));
}

{
using std::abs;
const std::complex<REAL> z{REAL(0), inf_v};
const REAL r = abs(z);
BOOST_CHECK((boost::multiprecision::isinf)(r));
BOOST_CHECK(!(boost::multiprecision::isnan)(r));
}

{
using std::abs;
const std::complex<REAL> z{-inf_v, REAL(3)};
const REAL r = abs(z);
BOOST_CHECK((boost::multiprecision::isinf)(r));
BOOST_CHECK(!(boost::multiprecision::isnan)(r));
}

{
// Per IEEE 754: hypot(inf, NaN) = inf.
using std::abs;
const REAL nan_v = std::numeric_limits<REAL>::quiet_NaN();
const std::complex<REAL> z{inf_v, nan_v};
const REAL r = abs(z);
BOOST_CHECK((boost::multiprecision::isinf)(r));
}

{
// Sanity check on a finite value: abs(3 + 4i) == 5.
using std::abs;
const std::complex<REAL> z{REAL(3), REAL(4)};
const REAL r = abs(z);
BOOST_CHECK_EQUAL(r, REAL(5));
}

return boost::report_errors();
}
Loading