glibc/sysdeps/ieee754/ldbl-96/bits/iscanonical.h
Gabriel F. T. Gomes aa0235dfde Add C++ versions of iscanonical for ldbl-96 and ldbl-128ibm (bug 22235)
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.
2017-10-03 16:01:37 -03:00

55 lines
2.4 KiB
C

/* Define iscanonical macro. ldbl-96 version.
Copyright (C) 2016-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/>. */
#ifndef _MATH_H
# error "Never use <bits/iscanonical.h> directly; include <math.h> instead."
#endif
extern int __iscanonicall (long double __x)
__THROW __attribute__ ((__const__));
#define __iscanonicalf(x) ((void) (__typeof (x)) (x), 1)
#define __iscanonical(x) ((void) (__typeof (x)) (x), 1)
#if __HAVE_DISTINCT_FLOAT128
# define __iscanonicalf128(x) ((void) (__typeof (x)) (x), 1)
#endif
/* Return nonzero value if X is canonical. In IEEE interchange binary
formats, all values are canonical, but the argument must still be
converted to its semantic type for any exceptions arising from the
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. */
#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 */