signbitl.c 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465
  1. /* signbit() macro: Determine the sign bit of a floating-point number.
  2. Copyright (C) 2007, 2009-2022 Free Software Foundation, Inc.
  3. This file is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU Lesser General Public License as
  5. published by the Free Software Foundation; either version 2.1 of the
  6. License, or (at your option) any later version.
  7. This file is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU Lesser General Public License for more details.
  11. You should have received a copy of the GNU Lesser General Public License
  12. along with this program. If not, see <https://www.gnu.org/licenses/>. */
  13. #include <config.h>
  14. /* Specification. */
  15. #include <math.h>
  16. #include <string.h>
  17. #include "isnanl-nolibm.h"
  18. #include "float+.h"
  19. #ifdef gl_signbitl_OPTIMIZED_MACRO
  20. # undef gl_signbitl
  21. #endif
  22. int
  23. gl_signbitl (long double arg)
  24. {
  25. #if defined LDBL_SIGNBIT_WORD && defined LDBL_SIGNBIT_BIT
  26. /* The use of a union to extract the bits of the representation of a
  27. 'long double' is safe in practice, despite of the "aliasing rules" of
  28. C99, because the GCC docs say
  29. "Even with '-fstrict-aliasing', type-punning is allowed, provided the
  30. memory is accessed through the union type."
  31. and similarly for other compilers. */
  32. # define NWORDS \
  33. ((sizeof (long double) + sizeof (unsigned int) - 1) / sizeof (unsigned int))
  34. union { long double value; unsigned int word[NWORDS]; } m;
  35. m.value = arg;
  36. return (m.word[LDBL_SIGNBIT_WORD] >> LDBL_SIGNBIT_BIT) & 1;
  37. #elif HAVE_COPYSIGNL_IN_LIBC
  38. return copysignl (1.0L, arg) < 0;
  39. #else
  40. /* This does not do the right thing for NaN, but this is irrelevant for
  41. most use cases. */
  42. if (isnanl (arg))
  43. return 0;
  44. if (arg < 0.0L)
  45. return 1;
  46. else if (arg == 0.0L)
  47. {
  48. /* Distinguish 0.0L and -0.0L. */
  49. static long double plus_zero = 0.0L;
  50. long double arg_mem = arg;
  51. return (memcmp (&plus_zero, &arg_mem, SIZEOF_LDBL) != 0);
  52. }
  53. else
  54. return 0;
  55. #endif
  56. }