Substitute a <ieee754.h> on hosts lacking it

* .gitignore: Add lib/ieee754.h.
* admin/merge-gnulib (GNULIB_MODULES): Add ieee754-h.
* configure.ac: Remove ieee754.h check, as Gnulib now does that.
* etc/NEWS: Mention this.
* lib/gnulib.mk.in, m4/gnulib-comp.m4: Regenerate.
* lib/ieee754.in.h, m4/ieee754-h.m4: New files, from Gnulib.
* src/lisp.h (IEEE_FLOATING_POINT): Now a macro so that it
can be used in #if.
* src/lread.c, src/print.c: Include <ieee754.h> if
IEEE_FLOATING_POINT, not if HAVE_IEEE754_H.
* src/lread.c (string_to_number):
* src/print.c (float_to_string):
Process NaNs only on IEEE hosts, and assume <ieee754.h>
in that case.
This commit is contained in:
Paul Eggert 2018-08-01 18:53:31 -07:00
parent 2f37ecaefc
commit d216d7d248
11 changed files with 291 additions and 40 deletions

1
.gitignore vendored
View file

@ -57,6 +57,7 @@ lib/execinfo.h
lib/fcntl.h
lib/getopt.h
lib/getopt-cdefs.h
lib/ieee754.h
lib/inttypes.h
lib/libgnu.a
lib/limits.h

View file

@ -35,7 +35,7 @@ GNULIB_MODULES='
fcntl fcntl-h fdatasync fdopendir
filemode filevercmp flexmember fpieee fstatat fsusage fsync
getloadavg getopt-gnu gettime gettimeofday gitlog-to-changelog
ignore-value intprops largefile lstat
ieee754-h ignore-value intprops largefile lstat
manywarnings memrchr minmax mkostemp mktime nstrftime
pipe2 pselect pthread_sigmask putenv qcopy-acl readlink readlinkat
sig2str socklen stat-time std-gnu11 stdalign stddef stdio

View file

@ -1668,7 +1668,6 @@ fi
dnl checks for header files
AC_CHECK_HEADERS_ONCE(
ieee754.h
linux/fs.h
malloc.h
sys/systeminfo.h

View file

@ -880,9 +880,9 @@ Formerly, some of these functions ignored signs and significands of
NaNs. Now, all these functions treat NaN signs and significands as
significant. For example, (eql 0.0e+NaN -0.0e+NaN) now returns nil
because the two NaNs have different signs; formerly it returned t.
Also, on platforms that have <ieee754.h> Emacs now reads and prints
NaN significands; e.g., if X is a NaN, (format "%s" X) now returns
"0.0e+NaN", "1.0e+NaN", etc., depending on X's significand.
Also, Emacs now reads and prints NaN significands; e.g., if X is a
NaN, (format "%s" X) now returns "0.0e+NaN", "1.0e+NaN", etc.,
depending on X's significand.
+++
** The function 'make-string' accepts an additional optional argument.

View file

@ -95,6 +95,7 @@
# gettime \
# gettimeofday \
# gitlog-to-changelog \
# ieee754-h \
# ignore-value \
# intprops \
# largefile \
@ -220,6 +221,7 @@ GL_GENERATE_ALLOCA_H = @GL_GENERATE_ALLOCA_H@
GL_GENERATE_BYTESWAP_H = @GL_GENERATE_BYTESWAP_H@
GL_GENERATE_ERRNO_H = @GL_GENERATE_ERRNO_H@
GL_GENERATE_EXECINFO_H = @GL_GENERATE_EXECINFO_H@
GL_GENERATE_IEEE754_H = @GL_GENERATE_IEEE754_H@
GL_GENERATE_LIMITS_H = @GL_GENERATE_LIMITS_H@
GL_GENERATE_STDALIGN_H = @GL_GENERATE_STDALIGN_H@
GL_GENERATE_STDDEF_H = @GL_GENERATE_STDDEF_H@
@ -646,6 +648,7 @@ HAVE_WINSOCK2_H = @HAVE_WINSOCK2_H@
HAVE_XSERVER = @HAVE_XSERVER@
HAVE__EXIT = @HAVE__EXIT@
HYBRID_MALLOC = @HYBRID_MALLOC@
IEEE754_H = @IEEE754_H@
IMAGEMAGICK_CFLAGS = @IMAGEMAGICK_CFLAGS@
IMAGEMAGICK_LIBS = @IMAGEMAGICK_LIBS@
INCLUDE_NEXT = @INCLUDE_NEXT@
@ -1787,6 +1790,32 @@ EXTRA_libgnu_a_SOURCES += group-member.c
endif
## end gnulib module group-member
## begin gnulib module ieee754-h
ifeq (,$(OMIT_GNULIB_MODULE_ieee754-h))
BUILT_SOURCES += $(IEEE754_H)
# We need the following in order to create <ieee754.h> when the system
# doesn't have one that works with the given compiler.
ifneq (,$(GL_GENERATE_IEEE754_H))
ieee754.h: ieee754.in.h $(top_builddir)/config.status
$(AM_V_GEN)rm -f $@-t && \
{ echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */'; \
sed -e 's/ifndef _GL_GNULIB_HEADER/if 0/g' \
$(srcdir)/ieee754.in.h; \
} > $@-t && \
mv -f $@-t $@
else
ieee754.h: $(top_builddir)/config.status
rm -f $@
endif
MOSTLYCLEANFILES += ieee754.h ieee754.h-t
EXTRA_DIST += ieee754.in.h
endif
## end gnulib module ieee754-h
## begin gnulib module ignore-value
ifeq (,$(OMIT_GNULIB_MODULE_ignore-value))

222
lib/ieee754.in.h Normal file
View file

@ -0,0 +1,222 @@
/* Copyright (C) 1992-2018 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 General Public
License as published by the Free Software Foundation; either
version 3 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
General Public License for more details.
You should have received a copy of the GNU General Public
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
#ifndef _IEEE754_H
#define _IEEE754_H 1
#ifndef _GL_GNULIB_HEADER
/* Ordinary glibc usage. */
# include <features.h>
# include <endian.h>
#else
/* Gnulib usage. */
# ifndef __BEGIN_DECLS
# ifdef __cplusplus
# define __BEGIN_DECLS extern "C" {
# define __END_DECLS }
# else
# define __BEGIN_DECLS
# define __END_DECLS
# endif
# endif
# ifndef __FLOAT_WORD_ORDER
# define __LITTLE_ENDIAN 1234
# define __BIG_ENDIAN 4321
# ifdef WORDS_BIGENDIAN
# define __BYTE_ORDER __BIG_ENDIAN
# else
# define __BYTE_ORDER __LITTLE_ENDIAN
# endif
# define __FLOAT_WORD_ORDER __BYTE_ORDER
# endif
#endif
__BEGIN_DECLS
union ieee754_float
{
float f;
/* This is the IEEE 754 single-precision format. */
struct
{
#if __BYTE_ORDER == __BIG_ENDIAN
unsigned int negative:1;
unsigned int exponent:8;
unsigned int mantissa:23;
#endif /* Big endian. */
#if __BYTE_ORDER == __LITTLE_ENDIAN
unsigned int mantissa:23;
unsigned int exponent:8;
unsigned int negative:1;
#endif /* Little endian. */
} ieee;
/* This format makes it easier to see if a NaN is a signalling NaN. */
struct
{
#if __BYTE_ORDER == __BIG_ENDIAN
unsigned int negative:1;
unsigned int exponent:8;
unsigned int quiet_nan:1;
unsigned int mantissa:22;
#endif /* Big endian. */
#if __BYTE_ORDER == __LITTLE_ENDIAN
unsigned int mantissa:22;
unsigned int quiet_nan:1;
unsigned int exponent:8;
unsigned int negative:1;
#endif /* Little endian. */
} ieee_nan;
};
#define IEEE754_FLOAT_BIAS 0x7f /* Added to exponent. */
union ieee754_double
{
double d;
/* This is the IEEE 754 double-precision format. */
struct
{
#if __BYTE_ORDER == __BIG_ENDIAN
unsigned int negative:1;
unsigned int exponent:11;
/* Together these comprise the mantissa. */
unsigned int mantissa0:20;
unsigned int mantissa1:32;
#endif /* Big endian. */
#if __BYTE_ORDER == __LITTLE_ENDIAN
# if __FLOAT_WORD_ORDER == __BIG_ENDIAN
unsigned int mantissa0:20;
unsigned int exponent:11;
unsigned int negative:1;
unsigned int mantissa1:32;
# else
/* Together these comprise the mantissa. */
unsigned int mantissa1:32;
unsigned int mantissa0:20;
unsigned int exponent:11;
unsigned int negative:1;
# endif
#endif /* Little endian. */
} ieee;
/* This format makes it easier to see if a NaN is a signalling NaN. */
struct
{
#if __BYTE_ORDER == __BIG_ENDIAN
unsigned int negative:1;
unsigned int exponent:11;
unsigned int quiet_nan:1;
/* Together these comprise the mantissa. */
unsigned int mantissa0:19;
unsigned int mantissa1:32;
#else
# if __FLOAT_WORD_ORDER == __BIG_ENDIAN
unsigned int mantissa0:19;
unsigned int quiet_nan:1;
unsigned int exponent:11;
unsigned int negative:1;
unsigned int mantissa1:32;
# else
/* Together these comprise the mantissa. */
unsigned int mantissa1:32;
unsigned int mantissa0:19;
unsigned int quiet_nan:1;
unsigned int exponent:11;
unsigned int negative:1;
# endif
#endif
} ieee_nan;
};
#define IEEE754_DOUBLE_BIAS 0x3ff /* Added to exponent. */
union ieee854_long_double
{
long double d;
/* This is the IEEE 854 double-extended-precision format. */
struct
{
#if __BYTE_ORDER == __BIG_ENDIAN
unsigned int negative:1;
unsigned int exponent:15;
unsigned int empty:16;
unsigned int mantissa0:32;
unsigned int mantissa1:32;
#endif
#if __BYTE_ORDER == __LITTLE_ENDIAN
# if __FLOAT_WORD_ORDER == __BIG_ENDIAN
unsigned int exponent:15;
unsigned int negative:1;
unsigned int empty:16;
unsigned int mantissa0:32;
unsigned int mantissa1:32;
# else
unsigned int mantissa1:32;
unsigned int mantissa0:32;
unsigned int exponent:15;
unsigned int negative:1;
unsigned int empty:16;
# endif
#endif
} ieee;
/* This is for NaNs in the IEEE 854 double-extended-precision format. */
struct
{
#if __BYTE_ORDER == __BIG_ENDIAN
unsigned int negative:1;
unsigned int exponent:15;
unsigned int empty:16;
unsigned int one:1;
unsigned int quiet_nan:1;
unsigned int mantissa0:30;
unsigned int mantissa1:32;
#endif
#if __BYTE_ORDER == __LITTLE_ENDIAN
# if __FLOAT_WORD_ORDER == __BIG_ENDIAN
unsigned int exponent:15;
unsigned int negative:1;
unsigned int empty:16;
unsigned int mantissa0:30;
unsigned int quiet_nan:1;
unsigned int one:1;
unsigned int mantissa1:32;
# else
unsigned int mantissa1:32;
unsigned int mantissa0:30;
unsigned int quiet_nan:1;
unsigned int one:1;
unsigned int exponent:15;
unsigned int negative:1;
unsigned int empty:16;
# endif
#endif
} ieee_nan;
};
#define IEEE854_LONG_DOUBLE_BIAS 0x3fff
__END_DECLS
#endif /* ieee754.h */

View file

@ -101,6 +101,7 @@ AC_DEFUN([gl_EARLY],
# Code from module gettimeofday:
# Code from module gitlog-to-changelog:
# Code from module group-member:
# Code from module ieee754-h:
# Code from module ignore-value:
# Code from module include_next:
# Code from module intprops:
@ -295,6 +296,7 @@ AC_DEFUN([gl_INIT],
gl_PREREQ_GETTIMEOFDAY
fi
gl_SYS_TIME_MODULE_INDICATOR([gettimeofday])
gl_IEEE754_H
gl_INTTYPES_INCOMPLETE
AC_REQUIRE([gl_LARGEFILE])
gl_LIMITS_H
@ -895,6 +897,7 @@ AC_DEFUN([gl_FILE_LIST], [
lib/gettimeofday.c
lib/gl_openssl.h
lib/group-member.c
lib/ieee754.in.h
lib/ignore-value.h
lib/intprops.h
lib/inttypes.in.h
@ -1017,6 +1020,7 @@ AC_DEFUN([gl_FILE_LIST], [
m4/gl-openssl.m4
m4/gnulib-common.m4
m4/group-member.m4
m4/ieee754-h.m4
m4/include_next.m4
m4/inttypes.m4
m4/largefile.m4

21
m4/ieee754-h.m4 Normal file
View file

@ -0,0 +1,21 @@
# Configure ieee754-h module
dnl Copyright 2018 Free Software Foundation, Inc.
dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it,
dnl with or without modifications, as long as this notice is preserved.
AC_DEFUN([gl_IEEE754_H],
[
AC_REQUIRE([AC_C_BIGENDIAN])
AC_CHECK_HEADERS_ONCE([ieee754.h])
if test $ac_cv_header_ieee754_h = yes; then
IEEE754_H=
else
IEEE754_H=ieee754.h
AC_DEFINE([_GL_REPLACE_IEEE754_H], 1,
[Define to 1 if <ieee754.h> is missing.])
fi
AC_SUBST([IEEE754_H])
AM_CONDITIONAL([GL_GENERATE_IEEE754_H], [test -n "$IEEE754_H"])
])

View file

@ -2670,17 +2670,14 @@ XFLOAT_DATA (Lisp_Object f)
/* Most hosts nowadays use IEEE floating point, so they use IEC 60559
representations, have infinities and NaNs, and do not trap on
exceptions. Define IEEE_FLOATING_POINT if this host is one of the
exceptions. Define IEEE_FLOATING_POINT to 1 if this host is one of the
typical ones. The C11 macro __STDC_IEC_559__ is close to what is
wanted here, but is not quite right because Emacs does not require
all the features of C11 Annex F (and does not require C11 at all,
for that matter). */
enum
{
IEEE_FLOATING_POINT
= (FLT_RADIX == 2 && FLT_MANT_DIG == 24
&& FLT_MIN_EXP == -125 && FLT_MAX_EXP == 128)
};
#define IEEE_FLOATING_POINT (FLT_RADIX == 2 && FLT_MANT_DIG == 24 \
&& FLT_MIN_EXP == -125 && FLT_MAX_EXP == 128)
/* A character, declared with the following typedef, is a member
of some character set associated with the current buffer. */

View file

@ -72,7 +72,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
#define file_tell ftell
#endif
#if HAVE_IEEE754_H
#if IEEE_FLOATING_POINT
# include <ieee754.h>
#endif
@ -3756,21 +3756,18 @@ string_to_number (char const *string, int base, int flags)
cp += 3;
value = INFINITY;
}
#if IEEE_FLOATING_POINT
else if (cp[-1] == '+'
&& cp[0] == 'N' && cp[1] == 'a' && cp[2] == 'N')
{
state |= E_EXP;
cp += 3;
#if HAVE_IEEE754_H
union ieee754_double u
= { .ieee_nan = { .exponent = -1, .quiet_nan = 1,
.mantissa0 = n >> 31 >> 1, .mantissa1 = n }};
value = u.d;
#else
/* NAN is a "positive" NaN on all known Emacs hosts. */
value = NAN;
#endif
}
#endif
else
cp = ecp;
}

View file

@ -40,7 +40,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
#include <ftoastr.h>
#include <math.h>
#if HAVE_IEEE754_H
#if IEEE_FLOATING_POINT
# include <ieee754.h>
#endif
@ -1013,34 +1013,15 @@ float_to_string (char *buf, double data)
strcpy (buf, minus_infinity_string + positive);
return sizeof minus_infinity_string - 1 - positive;
}
#if IEEE_FLOATING_POINT
if (isnan (data))
{
#if HAVE_IEEE754_H
union ieee754_double u = { .d = data };
uprintmax_t hi = u.ieee_nan.mantissa0;
return sprintf (buf, &"-%"pMu".0e+NaN"[!u.ieee_nan.negative],
(hi << 31 << 1) + u.ieee_nan.mantissa1);
#else
/* Prepend "-" if the NaN's sign bit is negative.
The sign bit of a double is the bit that is 1 in -0.0. */
static char const NaN_string[] = "0.0e+NaN";
int i;
union { double d; char c[sizeof (double)]; } u_data, u_minus_zero;
bool negative = 0;
u_data.d = data;
u_minus_zero.d = - 0.0;
for (i = 0; i < sizeof (double); i++)
if (u_data.c[i] & u_minus_zero.c[i])
{
*buf = '-';
negative = 1;
break;
}
strcpy (buf + negative, NaN_string);
return negative + sizeof NaN_string - 1;
#endif
}
#endif
if (NILP (Vfloat_output_format)
|| !STRINGP (Vfloat_output_format))