libstdc++: Make std::from_chars always round to nearest
Also fix the tests that fail on targets without uselocale. libstdc++-v3/ChangeLog: * src/c++17/floating_from_chars.cc (from_chars_impl): Ensure that FE_NEAREST is used. * testsuite/20_util/from_chars/4.cc: Do not use if constexpr in a { target c++14 } test. [!_GLIBCXX_HAVE_USELOCALE]: Disable all tests. * testsuite/20_util/from_chars/5.cc [!_GLIBCXX_HAVE_USELOCALE]: Likewise. * testsuite/20_util/from_chars/6.cc: New test.
This commit is contained in:
parent
7355a9408b
commit
2251b4a542
@ -30,6 +30,7 @@
|
||||
#include <charconv>
|
||||
#include <string>
|
||||
#include <memory_resource>
|
||||
#include <cfenv>
|
||||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
@ -289,6 +290,12 @@ namespace
|
||||
{
|
||||
locale_t orig = ::uselocale(loc);
|
||||
|
||||
#if _GLIBCXX_USE_C99_FENV_TR1
|
||||
const int rounding = std::fegetround();
|
||||
if (rounding != FE_TONEAREST)
|
||||
std::fesetround(FE_TONEAREST);
|
||||
#endif
|
||||
|
||||
const int save_errno = errno;
|
||||
errno = 0;
|
||||
char* endptr;
|
||||
@ -301,6 +308,11 @@ namespace
|
||||
tmpval = std::strtold(str, &endptr);
|
||||
const int conv_errno = std::__exchange(errno, save_errno);
|
||||
|
||||
#if _GLIBCXX_USE_C99_FENV_TR1
|
||||
if (rounding != FE_TONEAREST)
|
||||
std::fesetround(rounding);
|
||||
#endif
|
||||
|
||||
::uselocale(orig);
|
||||
::freelocale(loc);
|
||||
|
||||
|
@ -27,6 +27,9 @@
|
||||
|
||||
// Test std::from_chars floating-point conversions.
|
||||
|
||||
// As of July 2020 __cpp_lib_to_chars is not defined, but std::from_chars
|
||||
// works for floating-point types when _GLIBCXX_HAVE_USELOCALE is defined.
|
||||
#if __cpp_lib_to_chars >= 201611L || _GLIBCXX_HAVE_USELOCALE
|
||||
void
|
||||
test01()
|
||||
{
|
||||
@ -296,8 +299,7 @@ test_max_mantissa()
|
||||
using Float_limits = std::numeric_limits<FloatT>;
|
||||
using UInt_limits = std::numeric_limits<UIntT>;
|
||||
|
||||
if constexpr (Float_limits::is_iec559
|
||||
&& Float_limits::digits < UInt_limits::digits)
|
||||
if (Float_limits::is_iec559 && Float_limits::digits < UInt_limits::digits)
|
||||
{
|
||||
std::printf("Testing %d-bit float, using %zu-bit integer\n",
|
||||
Float_limits::digits + (int)std::log2(Float_limits::max_exponent) + 1,
|
||||
@ -355,14 +357,17 @@ test06()
|
||||
test_max_mantissa<long double, unsigned __GLIBCXX_TYPE_INT_N_0>();
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
#if __cpp_lib_to_chars >= 201611L || _GLIBCXX_HAVE_USELOCALE
|
||||
test01();
|
||||
test02();
|
||||
test03();
|
||||
test04();
|
||||
test05();
|
||||
test06();
|
||||
#endif
|
||||
}
|
||||
|
@ -25,6 +25,9 @@
|
||||
|
||||
// Test std::from_chars error handling.
|
||||
|
||||
// As of July 2020 __cpp_lib_to_chars is not defined, but std::from_chars
|
||||
// works for floating-point types when _GLIBCXX_HAVE_USELOCALE is defined.
|
||||
#if __cpp_lib_to_chars >= 201611L || _GLIBCXX_HAVE_USELOCALE
|
||||
void
|
||||
test01()
|
||||
{
|
||||
@ -152,12 +155,15 @@ test04()
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
#if __cpp_lib_to_chars >= 201611L || _GLIBCXX_HAVE_USELOCALE
|
||||
test01();
|
||||
test02();
|
||||
test03();
|
||||
test04();
|
||||
#endif
|
||||
}
|
||||
|
49
libstdc++-v3/testsuite/20_util/from_chars/6.cc
Normal file
49
libstdc++-v3/testsuite/20_util/from_chars/6.cc
Normal file
@ -0,0 +1,49 @@
|
||||
// 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/>.
|
||||
|
||||
// <charconv> is supported in C++14 as a GNU extension
|
||||
// { dg-do run { target c++14 } }
|
||||
// { dg-add-options ieee }
|
||||
|
||||
#include <charconv>
|
||||
#include <string>
|
||||
#include <cfenv>
|
||||
#include <testsuite_hooks.h>
|
||||
|
||||
void
|
||||
test01()
|
||||
{
|
||||
#if __cpp_lib_to_chars >= 201611L || _GLIBCXX_HAVE_USELOCALE
|
||||
#if _GLIBCXX_USE_C99_FENV_TR1
|
||||
double d;
|
||||
std::fesetround(FE_DOWNWARD);
|
||||
const std::string s = "0.099999999999999999999999999";
|
||||
auto res = std::from_chars(s.data(), s.data() + s.length(), d);
|
||||
VERIFY( res.ec == std::errc{} );
|
||||
VERIFY( res.ptr == s.data() + s.length() );
|
||||
// std::from_chars should ignore the current rounding mode
|
||||
// and always round to nearest.
|
||||
VERIFY( d == 0.1 );
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
test01();
|
||||
}
|
Loading…
Reference in New Issue
Block a user