/// Greatest common divisor
template<typename _Mn, typename _Nn>
constexpr common_type_t<_Mn, _Nn>
- gcd(_Mn __m, _Nn __n)
+ gcd(_Mn __m, _Nn __n) noexcept
{
- static_assert(is_integral_v<_Mn>, "gcd arguments are integers");
- static_assert(is_integral_v<_Nn>, "gcd arguments are integers");
- static_assert(!is_same_v<remove_cv_t<_Mn>, bool>,
- "gcd arguments are not bools");
- static_assert(!is_same_v<remove_cv_t<_Nn>, bool>,
- "gcd arguments are not bools");
- return std::__detail::__gcd(__m, __n);
+ static_assert(is_integral_v<_Mn>,
+ "std::experimental::gcd arguments must be integers");
+ static_assert(is_integral_v<_Nn>,
+ "std::experimental::gcd arguments must be integers");
+ static_assert(_Mn(2) != _Mn(1),
+ "std::experimental::gcd arguments must not be bool");
+ static_assert(_Nn(2) != _Nn(1),
+ "std::experimental::gcd arguments must not be bool");
+ using _Up = make_unsigned_t<common_type_t<_Mn, _Nn>>;
+ return std::__detail::__gcd(std::__detail::__absu<_Up>(__m),
+ std::__detail::__absu<_Up>(__n));
}
/// Least common multiple
constexpr common_type_t<_Mn, _Nn>
lcm(_Mn __m, _Nn __n)
{
- static_assert(is_integral_v<_Mn>, "lcm arguments are integers");
- static_assert(is_integral_v<_Nn>, "lcm arguments are integers");
- static_assert(!is_same_v<remove_cv_t<_Mn>, bool>,
- "lcm arguments are not bools");
- static_assert(!is_same_v<remove_cv_t<_Nn>, bool>,
- "lcm arguments are not bools");
- return std::__detail::__lcm(__m, __n);
+ static_assert(is_integral_v<_Mn>,
+ "std::experimental::lcm arguments must be integers");
+ static_assert(is_integral_v<_Nn>,
+ "std::experimental::lcm arguments must be integers");
+ static_assert(_Mn(2) != _Mn(1),
+ "std::experimental::lcm arguments must not be bool");
+ static_assert(_Nn(2) != _Nn(1),
+ "std::experimental::lcm arguments must not be bool");
+ using _Up = make_unsigned_t<common_type_t<_Mn, _Nn>>;
+ return std::__detail::__lcm(std::__detail::__absu<_Up>(__m),
+ std::__detail::__absu<_Up>(__n));
}
} // namespace fundamentals_v2
} // namespace experimental
#include <bits/c++config.h>
#include <bits/stl_iterator_base_types.h>
#include <bits/stl_numeric.h>
+#include <ext/numeric_traits.h>
#ifdef _GLIBCXX_PARALLEL
# include <parallel/numeric>
namespace __detail
{
- // std::abs is not constexpr and doesn't support unsigned integers.
- template<typename _Tp>
- constexpr
- enable_if_t<__and_<is_integral<_Tp>, is_signed<_Tp>>::value, _Tp>
- __abs_integral(_Tp __val)
- { return __val < 0 ? -__val : __val; }
-
- template<typename _Tp>
- constexpr
- enable_if_t<__and_<is_integral<_Tp>, is_unsigned<_Tp>>::value, _Tp>
- __abs_integral(_Tp __val)
- { return __val; }
+ // std::abs is not constexpr, doesn't support unsigned integers,
+ // and std::abs(std::numeric_limits<T>::min()) is undefined.
+ template<typename _Up, typename _Tp>
+ constexpr _Up
+ __absu(_Tp __val)
+ {
+ static_assert(is_unsigned<_Up>::value, "result type must be unsigned");
+ static_assert(sizeof(_Up) >= sizeof(_Tp),
+ "result type must be at least as wide as the input type");
+ return __val < 0 ? -(_Up)__val : (_Up)__val;
+ }
- void __abs_integral(bool) = delete;
+ void __absu(bool) = delete;
- template<typename _Mn, typename _Nn>
- constexpr common_type_t<_Mn, _Nn>
- __gcd(_Mn __m, _Nn __n)
+ // GCD implementation
+ template<typename _Tp>
+ constexpr _Tp
+ __gcd(_Tp __m, _Tp __n)
{
- return __m == 0 ? __detail::__abs_integral(__n)
- : __n == 0 ? __detail::__abs_integral(__m)
- : __detail::__gcd(__n, __m % __n);
+ static_assert(is_unsigned<_Tp>::value, "type must be unsigned");
+ return __m == 0 ? __n
+ : __n == 0 ? __m
+ : __detail::__gcd(__n, _Tp(__m % __n));
}
- /// Least common multiple
- template<typename _Mn, typename _Nn>
- constexpr common_type_t<_Mn, _Nn>
- __lcm(_Mn __m, _Nn __n)
+ // LCM implementation
+ template<typename _Tp>
+ constexpr _Tp
+ __lcm(_Tp __m, _Tp __n)
{
return (__m != 0 && __n != 0)
- ? (__detail::__abs_integral(__m) / __detail::__gcd(__m, __n))
- * __detail::__abs_integral(__n)
+ ? (__m / __detail::__gcd(__m, __n)) * __n
: 0;
}
} // namespace __detail
/// Greatest common divisor
template<typename _Mn, typename _Nn>
constexpr common_type_t<_Mn, _Nn>
- gcd(_Mn __m, _Nn __n)
+ gcd(_Mn __m, _Nn __n) noexcept
{
- static_assert(is_integral_v<_Mn>, "gcd arguments are integers");
- static_assert(is_integral_v<_Nn>, "gcd arguments are integers");
- static_assert(!is_same_v<remove_cv_t<_Mn>, bool>,
- "gcd arguments are not bools");
- static_assert(!is_same_v<remove_cv_t<_Nn>, bool>,
- "gcd arguments are not bools");
- return __detail::__gcd(__m, __n);
+ static_assert(is_integral_v<_Mn>, "std::gcd arguments must be integers");
+ static_assert(is_integral_v<_Nn>, "std::gcd arguments must be integers");
+ static_assert(_Mn(2) != _Mn(1), "std::gcd arguments must not be bool");
+ static_assert(_Nn(2) != _Nn(1), "std::gcd arguments must not be bool");
+ using _Up = make_unsigned_t<common_type_t<_Mn, _Nn>>;
+ return __detail::__gcd(__detail::__absu<_Up>(__m),
+ __detail::__absu<_Up>(__n));
}
/// Least common multiple
template<typename _Mn, typename _Nn>
constexpr common_type_t<_Mn, _Nn>
- lcm(_Mn __m, _Nn __n)
+ lcm(_Mn __m, _Nn __n) noexcept
{
- static_assert(is_integral_v<_Mn>, "lcm arguments are integers");
- static_assert(is_integral_v<_Nn>, "lcm arguments are integers");
- static_assert(!is_same_v<remove_cv_t<_Mn>, bool>,
- "lcm arguments are not bools");
- static_assert(!is_same_v<remove_cv_t<_Nn>, bool>,
- "lcm arguments are not bools");
- return __detail::__lcm(__m, __n);
+ static_assert(is_integral_v<_Mn>, "std::lcm arguments must be integers");
+ static_assert(is_integral_v<_Nn>, "std::lcm arguments must be integers");
+ static_assert(_Mn(2) == 2, "std::lcm arguments must not be bool");
+ static_assert(_Nn(2) == 2, "std::lcm arguments must not be bool");
+ using _Up = make_unsigned_t<common_type_t<_Mn, _Nn>>;
+ return __detail::__lcm(__detail::__absu<_Up>(__m),
+ __detail::__absu<_Up>(__n));
}
#endif // C++17
--- /dev/null
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-do compile { target c++17 } }
+
+#include <numeric>
+#include <limits.h>
+
+void
+test01()
+{
+ // PR libstdc++/92978
+ static_assert( std::gcd(-120, 10U) == 10 );
+ static_assert( std::gcd(120U, -10) == 10 );
+}
+
+void
+test02()
+{
+ // |INT_MIN| should not be undefined, as long as it fits in the result type.
+ static_assert( std::gcd(INT_MIN, 0LL) == 1LL+INT_MAX );
+ static_assert( std::gcd(0LL, INT_MIN) == 1LL+INT_MAX );
+ static_assert( std::gcd(INT_MIN, 0LL + INT_MIN) == 1LL + INT_MAX );
+ static_assert( std::gcd(INT_MIN, 1LL + INT_MAX) == 1LL + INT_MAX );
+ static_assert( std::gcd(SHRT_MIN, 1U + SHRT_MAX) == 1U + SHRT_MAX );
+}
std::gcd<const int&, const int&>(0.1, 0.1); // { dg-error "from here" }
}
-// { dg-error "integers" "" { target *-*-* } 133 }
-// { dg-error "integers" "" { target *-*-* } 134 }
-// { dg-error "not bools" "" { target *-*-* } 135 }
-// { dg-error "not bools" "" { target *-*-* } 137 }
-// { dg-prune-output "deleted function" }
-// { dg-prune-output "invalid operands" }
+// { dg-error "must be integers" "" { target *-*-* } 134 }
+// { dg-error "must be integers" "" { target *-*-* } 135 }
+// { dg-error "must not be bool" "" { target *-*-* } 136 }
+// { dg-error "must not be bool" "" { target *-*-* } 137 }
+// { dg-prune-output "incomplete type .*make_unsigned" }
--- /dev/null
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-do compile { target c++17 } }
+
+#include <numeric>
+
+void
+test01()
+{
+ // PR libstdc++/92978
+ static_assert( std::lcm(-42, 21U) == 42U );
+}
std::lcm<const int&, const int&>(0.1, 0.1); // { dg-error "from here" }
}
-// { dg-error "integers" "" { target *-*-* } 147 }
-// { dg-error "integers" "" { target *-*-* } 148 }
-// { dg-error "not bools" "" { target *-*-* } 149 }
-// { dg-error "not bools" "" { target *-*-* } 151 }
-// { dg-prune-output "deleted function" }
-// { dg-prune-output "invalid operands" }
+// { dg-error "must be integers" "" { target *-*-* } 148 }
+// { dg-error "must be integers" "" { target *-*-* } 149 }
+// { dg-error "must not be bool" "" { target *-*-* } 150 }
+// { dg-error "must not be bool" "" { target *-*-* } 151 }
+// { dg-prune-output "incomplete type .*make_unsigned" }
--- /dev/null
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-do compile { target c++14 } }
+
+#include <experimental/numeric>
+#include <limits.h>
+
+void
+test01()
+{
+ // PR libstdc++/92978
+ static_assert( std::experimental::gcd(-120, 10U) == 10,
+ "mixed signed/unsigned" );
+ static_assert( std::experimental::gcd(120U, -10) == 10,
+ "mixed signed/unsigned" );
+
+ static_assert( std::lcm(-42, 21U) == 42U );
+}
+
+void
+test02()
+{
+ static_assert( std::experimental::gcd(INT_MIN, 0LL) == 1LL+INT_MAX,
+ "|INT_MIN| should not be undefined as long as it fits in the result" );
+ static_assert( std::experimental::gcd(0LL, INT_MIN) == 1LL+INT_MAX,
+ "|INT_MIN| should not be undefined" );
+ static_assert( std::experimental::gcd(INT_MIN, 0LL + INT_MIN) == 1LL + INT_MAX,
+ "|INT_MIN| should not be undefined" );
+ static_assert( std::experimental::gcd(INT_MIN, 1LL + INT_MAX) == 1LL + INT_MAX,
+ "|INT_MIN| should not be undefined" );
+ static_assert( std::experimental::gcd(SHRT_MIN, 1U + SHRT_MAX) == 1U + SHRT_MAX,
+ "|SHRT_MIN| should not be undefined" );
+}