1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2025-12-06 06:20:55 -08:00

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/fcntl.h
lib/getopt.h lib/getopt.h
lib/getopt-cdefs.h lib/getopt-cdefs.h
lib/ieee754.h
lib/inttypes.h lib/inttypes.h
lib/libgnu.a lib/libgnu.a
lib/limits.h lib/limits.h

View file

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

View file

@ -1668,7 +1668,6 @@ fi
dnl checks for header files dnl checks for header files
AC_CHECK_HEADERS_ONCE( AC_CHECK_HEADERS_ONCE(
ieee754.h
linux/fs.h linux/fs.h
malloc.h malloc.h
sys/systeminfo.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 NaNs. Now, all these functions treat NaN signs and significands as
significant. For example, (eql 0.0e+NaN -0.0e+NaN) now returns nil significant. For example, (eql 0.0e+NaN -0.0e+NaN) now returns nil
because the two NaNs have different signs; formerly it returned t. because the two NaNs have different signs; formerly it returned t.
Also, on platforms that have <ieee754.h> Emacs now reads and prints Also, Emacs now reads and prints NaN significands; e.g., if X is a
NaN significands; e.g., if X is a NaN, (format "%s" X) now returns NaN, (format "%s" X) now returns "0.0e+NaN", "1.0e+NaN", etc.,
"0.0e+NaN", "1.0e+NaN", etc., depending on X's significand. depending on X's significand.
+++ +++
** The function 'make-string' accepts an additional optional argument. ** The function 'make-string' accepts an additional optional argument.

View file

@ -95,6 +95,7 @@
# gettime \ # gettime \
# gettimeofday \ # gettimeofday \
# gitlog-to-changelog \ # gitlog-to-changelog \
# ieee754-h \
# ignore-value \ # ignore-value \
# intprops \ # intprops \
# largefile \ # largefile \
@ -220,6 +221,7 @@ GL_GENERATE_ALLOCA_H = @GL_GENERATE_ALLOCA_H@
GL_GENERATE_BYTESWAP_H = @GL_GENERATE_BYTESWAP_H@ GL_GENERATE_BYTESWAP_H = @GL_GENERATE_BYTESWAP_H@
GL_GENERATE_ERRNO_H = @GL_GENERATE_ERRNO_H@ GL_GENERATE_ERRNO_H = @GL_GENERATE_ERRNO_H@
GL_GENERATE_EXECINFO_H = @GL_GENERATE_EXECINFO_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_LIMITS_H = @GL_GENERATE_LIMITS_H@
GL_GENERATE_STDALIGN_H = @GL_GENERATE_STDALIGN_H@ GL_GENERATE_STDALIGN_H = @GL_GENERATE_STDALIGN_H@
GL_GENERATE_STDDEF_H = @GL_GENERATE_STDDEF_H@ GL_GENERATE_STDDEF_H = @GL_GENERATE_STDDEF_H@
@ -646,6 +648,7 @@ HAVE_WINSOCK2_H = @HAVE_WINSOCK2_H@
HAVE_XSERVER = @HAVE_XSERVER@ HAVE_XSERVER = @HAVE_XSERVER@
HAVE__EXIT = @HAVE__EXIT@ HAVE__EXIT = @HAVE__EXIT@
HYBRID_MALLOC = @HYBRID_MALLOC@ HYBRID_MALLOC = @HYBRID_MALLOC@
IEEE754_H = @IEEE754_H@
IMAGEMAGICK_CFLAGS = @IMAGEMAGICK_CFLAGS@ IMAGEMAGICK_CFLAGS = @IMAGEMAGICK_CFLAGS@
IMAGEMAGICK_LIBS = @IMAGEMAGICK_LIBS@ IMAGEMAGICK_LIBS = @IMAGEMAGICK_LIBS@
INCLUDE_NEXT = @INCLUDE_NEXT@ INCLUDE_NEXT = @INCLUDE_NEXT@
@ -1787,6 +1790,32 @@ EXTRA_libgnu_a_SOURCES += group-member.c
endif endif
## end gnulib module group-member ## 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 ## begin gnulib module ignore-value
ifeq (,$(OMIT_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 gettimeofday:
# Code from module gitlog-to-changelog: # Code from module gitlog-to-changelog:
# Code from module group-member: # Code from module group-member:
# Code from module ieee754-h:
# Code from module ignore-value: # Code from module ignore-value:
# Code from module include_next: # Code from module include_next:
# Code from module intprops: # Code from module intprops:
@ -295,6 +296,7 @@ AC_DEFUN([gl_INIT],
gl_PREREQ_GETTIMEOFDAY gl_PREREQ_GETTIMEOFDAY
fi fi
gl_SYS_TIME_MODULE_INDICATOR([gettimeofday]) gl_SYS_TIME_MODULE_INDICATOR([gettimeofday])
gl_IEEE754_H
gl_INTTYPES_INCOMPLETE gl_INTTYPES_INCOMPLETE
AC_REQUIRE([gl_LARGEFILE]) AC_REQUIRE([gl_LARGEFILE])
gl_LIMITS_H gl_LIMITS_H
@ -895,6 +897,7 @@ AC_DEFUN([gl_FILE_LIST], [
lib/gettimeofday.c lib/gettimeofday.c
lib/gl_openssl.h lib/gl_openssl.h
lib/group-member.c lib/group-member.c
lib/ieee754.in.h
lib/ignore-value.h lib/ignore-value.h
lib/intprops.h lib/intprops.h
lib/inttypes.in.h lib/inttypes.in.h
@ -1017,6 +1020,7 @@ AC_DEFUN([gl_FILE_LIST], [
m4/gl-openssl.m4 m4/gl-openssl.m4
m4/gnulib-common.m4 m4/gnulib-common.m4
m4/group-member.m4 m4/group-member.m4
m4/ieee754-h.m4
m4/include_next.m4 m4/include_next.m4
m4/inttypes.m4 m4/inttypes.m4
m4/largefile.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 /* Most hosts nowadays use IEEE floating point, so they use IEC 60559
representations, have infinities and NaNs, and do not trap on 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 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 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, all the features of C11 Annex F (and does not require C11 at all,
for that matter). */ for that matter). */
enum
{ #define IEEE_FLOATING_POINT (FLT_RADIX == 2 && FLT_MANT_DIG == 24 \
IEEE_FLOATING_POINT
= (FLT_RADIX == 2 && FLT_MANT_DIG == 24
&& FLT_MIN_EXP == -125 && FLT_MAX_EXP == 128) && FLT_MIN_EXP == -125 && FLT_MAX_EXP == 128)
};
/* A character, declared with the following typedef, is a member /* A character, declared with the following typedef, is a member
of some character set associated with the current buffer. */ 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 #define file_tell ftell
#endif #endif
#if HAVE_IEEE754_H #if IEEE_FLOATING_POINT
# include <ieee754.h> # include <ieee754.h>
#endif #endif
@ -3756,21 +3756,18 @@ string_to_number (char const *string, int base, int flags)
cp += 3; cp += 3;
value = INFINITY; value = INFINITY;
} }
#if IEEE_FLOATING_POINT
else if (cp[-1] == '+' else if (cp[-1] == '+'
&& cp[0] == 'N' && cp[1] == 'a' && cp[2] == 'N') && cp[0] == 'N' && cp[1] == 'a' && cp[2] == 'N')
{ {
state |= E_EXP; state |= E_EXP;
cp += 3; cp += 3;
#if HAVE_IEEE754_H
union ieee754_double u union ieee754_double u
= { .ieee_nan = { .exponent = -1, .quiet_nan = 1, = { .ieee_nan = { .exponent = -1, .quiet_nan = 1,
.mantissa0 = n >> 31 >> 1, .mantissa1 = n }}; .mantissa0 = n >> 31 >> 1, .mantissa1 = n }};
value = u.d; value = u.d;
#else
/* NAN is a "positive" NaN on all known Emacs hosts. */
value = NAN;
#endif
} }
#endif
else else
cp = ecp; cp = ecp;
} }

View file

@ -40,7 +40,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
#include <ftoastr.h> #include <ftoastr.h>
#include <math.h> #include <math.h>
#if HAVE_IEEE754_H #if IEEE_FLOATING_POINT
# include <ieee754.h> # include <ieee754.h>
#endif #endif
@ -1013,34 +1013,15 @@ float_to_string (char *buf, double data)
strcpy (buf, minus_infinity_string + positive); strcpy (buf, minus_infinity_string + positive);
return sizeof minus_infinity_string - 1 - positive; return sizeof minus_infinity_string - 1 - positive;
} }
#if IEEE_FLOATING_POINT
if (isnan (data)) if (isnan (data))
{ {
#if HAVE_IEEE754_H
union ieee754_double u = { .d = data }; union ieee754_double u = { .d = data };
uprintmax_t hi = u.ieee_nan.mantissa0; uprintmax_t hi = u.ieee_nan.mantissa0;
return sprintf (buf, &"-%"pMu".0e+NaN"[!u.ieee_nan.negative], return sprintf (buf, &"-%"pMu".0e+NaN"[!u.ieee_nan.negative],
(hi << 31 << 1) + u.ieee_nan.mantissa1); (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) if (NILP (Vfloat_output_format)
|| !STRINGP (Vfloat_output_format)) || !STRINGP (Vfloat_output_format))