abs(long long)

Submitted by Marc Glisse on Oct. 2, 2012, 8:45 a.m.

Details

Message ID alpine.DEB.2.02.1210021018570.5523@stedding.saclay.inria.fr
State New
Headers show

Commit Message

Marc Glisse Oct. 2, 2012, 8:45 a.m.
Hello,

here is the patch from PR54686. Several notes:

* I'll have to ask experts if std::abs(unsigned) (yes, a weird thing to 
do, but still) is meant to return a double...
* I still don't like the configure-time _GLIBCXX_USE_INT128, I think it 
should use defined(__SIZEOF_INT128__), which would help other compilers.
* newlib has llabs, according to the doc. It would be good to know what 
newlib is missing for libstdc++ to detect it as C99-ready.

I tested a previous version (without __STRICT_ANSI__) on x86_64-linux-gnu 
and Oleg Endo did a basic check on sh/newlib. I'll do a last check after 
the review (no point if the patch needs changing again).

2012-10-02  Marc Glisse  <marc.glisse@inria.fr>

 	PR libstdc++/54686
 	* include/c_std/cstdlib (abs(long long)): Define fallback whenever
 	we have long long but possibly not llabs.
 	(abs(long long)): Use llabs when available.
 	(abs(__int128)): Define when we have __int128.
 	(div(long long, long long)): Use lldiv.
 	* testsuite/26_numerics/headers/cstdlib/54686.c: New file.

Patch hide | download patch | download mbox

Index: include/c_std/cstdlib
===================================================================
--- include/c_std/cstdlib	(revision 191941)
+++ include/c_std/cstdlib	(working copy)
@@ -130,20 +130,32 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
   using ::strtoul;
   using ::system;
 #ifdef _GLIBCXX_USE_WCHAR_T
   using ::wcstombs;
   using ::wctomb;
 #endif // _GLIBCXX_USE_WCHAR_T
 
   inline long
   abs(long __i) { return labs(__i); }
 
+#if defined (_GLIBCXX_USE_LONG_LONG) \
+    && (!_GLIBCXX_USE_C99 || _GLIBCXX_USE_C99_LONG_LONG_DYNAMIC)
+  // Fallback version if we don't have llabs but still allow long long.
+  inline long long
+  abs(long long __x) { return __x >= 0 ? __x : -__x; }
+#endif
+
+#if !defined(__STRICT_ANSI__) && defined(_GLIBCXX_USE_INT128)
+  inline __int128
+  abs(__int128 __x) { return __x >= 0 ? __x : -__x; }
+#endif
+
   inline ldiv_t
   div(long __i, long __j) { return ldiv(__i, __j); }
 
 _GLIBCXX_END_NAMESPACE_VERSION
 } // namespace
 
 #if _GLIBCXX_USE_C99
 
 #undef _Exit
 #undef llabs
@@ -161,29 +173,29 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 #if !_GLIBCXX_USE_C99_LONG_LONG_DYNAMIC
   using ::lldiv_t;
 #endif
 #if _GLIBCXX_USE_C99_CHECK || _GLIBCXX_USE_C99_DYNAMIC
   extern "C" void (_Exit)(int) throw () _GLIBCXX_NORETURN;
 #endif
 #if !_GLIBCXX_USE_C99_DYNAMIC
   using ::_Exit;
 #endif
 
+#if !_GLIBCXX_USE_C99_LONG_LONG_DYNAMIC
   inline long long
-  abs(long long __x) { return __x >= 0 ? __x : -__x; }
+  abs(long long __x) { return ::llabs (__x); }
 
-#if !_GLIBCXX_USE_C99_LONG_LONG_DYNAMIC
   using ::llabs;
 
   inline lldiv_t
   div(long long __n, long long __d)
-  { lldiv_t __q; __q.quot = __n / __d; __q.rem = __n % __d; return __q; }
+  { return ::lldiv (__n, __d); }
 
   using ::lldiv;
 #endif
 
 #if _GLIBCXX_USE_C99_LONG_LONG_CHECK || _GLIBCXX_USE_C99_LONG_LONG_DYNAMIC
   extern "C" long long int (atoll)(const char *) throw ();
   extern "C" long long int
     (strtoll)(const char * __restrict, char ** __restrict, int) throw ();
   extern "C" unsigned long long int
     (strtoull)(const char * __restrict, char ** __restrict, int) throw ();
@@ -198,22 +210,22 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
 _GLIBCXX_END_NAMESPACE_VERSION
 } // namespace __gnu_cxx
 
 namespace std
 {
 #if !_GLIBCXX_USE_C99_LONG_LONG_DYNAMIC
   using ::__gnu_cxx::lldiv_t;
 #endif
   using ::__gnu_cxx::_Exit;
-  using ::__gnu_cxx::abs;
 #if !_GLIBCXX_USE_C99_LONG_LONG_DYNAMIC
+  using ::__gnu_cxx::abs;
   using ::__gnu_cxx::llabs;
   using ::__gnu_cxx::div;
   using ::__gnu_cxx::lldiv;
 #endif
   using ::__gnu_cxx::atoll;
   using ::__gnu_cxx::strtof;
   using ::__gnu_cxx::strtoll;
   using ::__gnu_cxx::strtoull;
   using ::__gnu_cxx::strtold;
 } // namespace std
Index: testsuite/26_numerics/headers/cstdlib/54686.c
===================================================================
--- testsuite/26_numerics/headers/cstdlib/54686.c	(revision 0)
+++ testsuite/26_numerics/headers/cstdlib/54686.c	(revision 0)
@@ -0,0 +1,32 @@ 
+// { dg-do compile }
+// { dg-options "-std=c++11" }
+
+// Copyright (C) 2012 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/>.
+
+#include <cmath>
+#include <cstdlib>
+#include <type_traits>
+#include <utility>
+
+#ifdef _GLIBCXX_USE_LONG_LONG
+void test01()
+{
+  static_assert (std::is_same<decltype (std::abs (std::declval<long long> ())),
+			      long long>::value, "Missing abs(long long)");
+}
+#endif