All representations of floating-point numbers in types with IEC 60559
binary exchange format are canonical. On the other hand, types with IEC
60559 extended formats, such as those implemented under ldbl-96 and
ldbl-128ibm, contain representations that are not canonical.
TS 18661-1 introduced the type-generic macro iscanonical, which returns
whether a floating-point value is canonical or not. In Glibc, this
type-generic macro is implemented using the macro __MATH_TG, which, when
support for float128 is enabled, relies on __builtin_types_compatible_p
to select between floating-point types. However, this use of
iscanonical breaks C++ applications, because the builtin is only
available in C mode.
This patch provides a C++ implementation of iscanonical that relies on
function overloading, rather than builtins, to select between
floating-point types.
Unlike the C++ implementations for iszero and issignaling, this
implementation ignores __NO_LONG_DOUBLE_MATH. The double type always
matches IEC 60559 double format, which is always canonical. Thus, when
double and long double are the same (__NO_LONG_DOUBLE_MATH), iscanonical
always returns 1 and is not implemented with __MATH_TG.
Tested for powerpc64, powerpc64le and x86_64.
[BZ #22235]
* math/math.h: Trivial fix for unbalanced parentheses in comment.
* math/Makefile [CXX] (tests): Add test-math-iscanonical.cc.
(CFLAGS-test-math-iscanonical.cc): New variable.
* math/test-math-iscanonical.cc: New file.
* sysdeps/ieee754/ldbl-96/bits/iscanonical.h (iscanonical):
Provide a C++ implementation based on function overloading,
rather than using __MATH_TG, which uses C-only builtins.
* sysdeps/ieee754/ldbl-128ibm/bits/iscanonical.h (iscanonical):
Likewise.
* sysdeps/powerpc/powerpc64le/Makefile
(CFLAGS-test-math-iscanonical.cc): New variable.
(cherry picked from commit
aa0235dfdebffe9b338deba51f3ba563ee9b433d)
+2017-10-03 Gabriel F. T. Gomes <gabriel@inconstante.eti.br>
+
+ [BZ #22235]
+ * math/math.h: Trivial fix for unbalanced parentheses in comment.
+ * math/Makefile [CXX] (tests): Add test-math-iscanonical.cc.
+ (CFLAGS-test-math-iscanonical.cc): New variable.
+ * math/test-math-iscanonical.cc: New file.
+ * sysdeps/ieee754/ldbl-96/bits/iscanonical.h (iscanonical):
+ Provide a C++ implementation based on function overloading,
+ rather than using __MATH_TG, which uses C-only builtins.
+ * sysdeps/ieee754/ldbl-128ibm/bits/iscanonical.h (iscanonical):
+ Likewise.
+ * sysdeps/powerpc/powerpc64le/Makefile
+ (CFLAGS-test-math-iscanonical.cc): New variable.
+
2017-08-22 Joseph Myers <joseph@codesourcery.com>
[BZ #21987]
[22096] resolv: __resolv_conf_attach must not free passed conf object
[22146] Let fpclassify use the builtin when optimizing for size in C++ mode
[22225] math: nearbyint arithmetic moved before feholdexcept
+ [22235] Add C++ versions of iscanonical for ldbl-96 and ldbl-128ibm
\f
Version 2.26
test-signgam-ullong-static test-signgam-ullong-init-static
ifneq (,$(CXX))
-tests += test-math-isinff test-math-iszero test-math-issignaling
+tests += test-math-isinff test-math-iszero test-math-issignaling \
+ test-math-iscanonical
endif
ifneq (no,$(PERL))
CFLAGS-test-math-isinff.cc = -std=gnu++11
CFLAGS-test-math-iszero.cc = -std=gnu++11
CFLAGS-test-math-issignaling.cc = -std=gnu++11
+CFLAGS-test-math-iscanonical.cc = -std=gnu++11
CFLAGS-test-iszero-excess-precision.c = -fexcess-precision=standard
CFLAGS-test-iseqsig-excess-precision.c = -fexcess-precision=standard
other hand, overloading provides the means to distinguish between
the floating-point types. The overloading resolution will match
the correct parameter (regardless of type qualifiers (i.e.: const
- and volatile). */
+ and volatile)). */
extern "C++" {
inline int issignaling (float __val) { return __issignalingf (__val); }
inline int issignaling (double __val) { return __issignaling (__val); }
--- /dev/null
+/* Test for the C++ implementation of iscanonical.
+ Copyright (C) 2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#define _GNU_SOURCE 1
+#include <math.h>
+#include <stdio.h>
+
+static bool errors;
+
+template <class T>
+static void
+check_type ()
+{
+ T val = 0;
+
+ /* Check if iscanonical is available in C++ mode (bug 22235). */
+ if (iscanonical (val) == 0)
+ errors++;
+}
+
+static int
+do_test (void)
+{
+ check_type<float> ();
+ check_type<double> ();
+ check_type<long double> ();
+#if __HAVE_DISTINCT_FLOAT128
+ check_type<_Float128> ();
+#endif
+ return errors;
+}
+
+#include <support/test-driver.c>
conversion, before being discarded; in IBM long double, there are
encodings that are not consistently handled as corresponding to any
particular value of the type, and we return 0 for those. */
-# define iscanonical(x) __MATH_TG ((x), __iscanonical, (x))
-#endif
+# ifndef __cplusplus
+# define iscanonical(x) __MATH_TG ((x), __iscanonical, (x))
+# else
+/* In C++ mode, __MATH_TG cannot be used, because it relies on
+ __builtin_types_compatible_p, which is a C-only builtin. On the
+ other hand, overloading provides the means to distinguish between
+ the floating-point types. The overloading resolution will match
+ the correct parameter (regardless of type qualifiers (i.e.: const
+ and volatile)). */
+extern "C++" {
+inline int iscanonical (float __val) { return __iscanonicalf (__val); }
+inline int iscanonical (double __val) { return __iscanonical (__val); }
+inline int iscanonical (long double __val) { return __iscanonicall (__val); }
+# if __HAVE_DISTINCT_FLOAT128
+inline int iscanonical (_Float128 __val) { return __iscanonicalf128 (__val); }
+# endif
+}
+# endif /* __cplusplus */
+#endif /* __NO_LONG_DOUBLE_MATH */
conversion, before being discarded; in extended precision, there
are encodings that are not consistently handled as corresponding to
any particular value of the type, and we return 0 for those. */
-#define iscanonical(x) __MATH_TG ((x), __iscanonical, (x))
+#ifndef __cplusplus
+# define iscanonical(x) __MATH_TG ((x), __iscanonical, (x))
+#else
+/* In C++ mode, __MATH_TG cannot be used, because it relies on
+ __builtin_types_compatible_p, which is a C-only builtin. On the
+ other hand, overloading provides the means to distinguish between
+ the floating-point types. The overloading resolution will match
+ the correct parameter (regardless of type qualifiers (i.e.: const
+ and volatile)). */
+extern "C++" {
+inline int iscanonical (float __val) { return __iscanonicalf (__val); }
+inline int iscanonical (double __val) { return __iscanonical (__val); }
+inline int iscanonical (long double __val) { return __iscanonicall (__val); }
+# if __HAVE_DISTINCT_FLOAT128
+inline int iscanonical (_Float128 __val) { return __iscanonicalf128 (__val); }
+# endif
+}
+#endif /* __cplusplus */
$(foreach suf,$(all-object-suffixes),$(objpfx)test-float128%$(suf)): CFLAGS += -mfloat128
$(foreach suf,$(all-object-suffixes),$(objpfx)test-ifloat128%$(suf)): CFLAGS += -mfloat128
CFLAGS-libm-test-support-float128.c += -mfloat128
+CFLAGS-test-math-iscanonical.cc += -mfloat128
CFLAGS-test-math-issignaling.cc += -mfloat128
CFLAGS-test-math-iszero.cc += -mfloat128
$(objpfx)test-float128% $(objpfx)test-ifloat128% $(objpfx)test-math-iszero: \