?RCS: $Id$
?RCS:
?RCS: Copyright (c) 2015 Jarkko Hietaniemi, H.Merijn Brand
?RCS:
?RCS: You may distribute under the terms of either the GNU General Public
?RCS: License or the Artistic License, as specified in the README file.
?RCS:
?MAKE:longdblinfbytes longdblnanbytes doubleinfbytes doublenanbytes: Inlibc \
	cat Compile run rm_try Setvar echo d_longdbl \
	doublekind doublesize longdblkind longdblsize
?MAKE:	-pick add $@ %<
?S:longdblinfbytes:
?S:	This variable contains comma-separated list of hexadecimal bytes
?S:	for the long double precision infinity.
?S:.
?S:longdblnanbytes:
?S:	This variable contains comma-separated list of hexadecimal bytes
?S:	for the long double precision not-a-number.
?S:.
?S:doubleinfbytes:
?S:	This variable contains comma-separated list of hexadecimal bytes
?S:	for the double precision infinity.
?S:.
?S:doublenanbytes:
?S:	This variable contains comma-separated list of hexadecimal bytes
?S:	for the double precision not-a-number.
?S:.
?C:DOUBLEINFBYTES:
?C:	This symbol, if defined, is a comma-separated list of
?C:	hexadecimal bytes for the double precision infinity.
?C:.
?C:DOUBLENANBYTES:
?C:	This symbol, if defined, is a comma-separated list of
?C:	hexadecimal bytes (0xHH) for the double precision not-a-number.
?C:.
?C:LONGDBLINFBYTES:
?C:	This symbol, if defined, is a comma-separated list of
?C:	hexadecimal bytes for the long double precision infinity.
?C:.
?C:LONGDBLNANBYTES:
?C:	This symbol, if defined, is a comma-separated list of
?C:	hexadecimal bytes (0xHH) for the long double precision not-a-number.
?C:.
?H:#define DOUBLEINFBYTES  $doubleinfbytes		/**/
?H:#define DOUBLENANBYTES  $doublenanbytes		/**/
?H:#define LONGDBLINFBYTES $longdblinfbytes		/**/
?H:#define LONGDBLNANBYTES $longdblnanbytes		/**/
?H:.
?F:!try
: Check what kind of inf/nan your system has
$echo "Checking the kind of infinities and nans you have..." >&4
$echo "(The following tests may crash.  That's okay.)" >&4
$cat >try.c <<EOP
#define DOUBLESIZE $doublesize
#$d_longdbl HAS_LONG_DOUBLE
#ifdef HAS_LONG_DOUBLE
#define LONG_DOUBLESIZE $longdblsize
#define LONG_DOUBLEKIND $longdblkind
#endif
#include <math.h>
#include <string.h>
#include <stdio.h>
/* Note that whether the sign bit is on or off
 * for NaN depends on the CPU/FPU, and possibly
 * can be affected by the build toolchain.
 *
 * For example for older MIPS and HP-PA 2.0 the quiet NaN is:
 * 0x7f, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
 * 0x7f, 0xf4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
 * (respectively) as opposed to the more usual
 * 0x7f, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
 *
 * Pre-IEEE-754 floating point format do not even have inf/nan support
 * at all.  They might have a "max" value (DBL_MAX), which may be deadly
 * to even mention, causing immediate SIGFPE or equivalent: this is
 * the case with VAX floating point, for example.
 */
static void bytes(void *v, unsigned int n) {
  unsigned char *p = (unsigned char *)v;
  int i;
  for (i = 0; i < n; i++) {
    printf("0x%02x%s", p[i], i < n - 1 ? ", " : "\n");
  }
}
int main(int argc, char *argv[]) {
   /* We cannot use 1.0/0.0 and 0.0/0.0 (with L suffixes for long double)
    * because some compilers are 'smart' and not only warn but refuse to
    * compile such 'illegal' values. */
   double dinf = exp(1e9);
   double dnan = sqrt(-1.0);
#ifdef HAS_LONG_DOUBLE
   long double ldinf = (long double)exp(1e9);
   long double ldnan = (long double)sqrt(-1.0);
# if LONG_DOUBLEKIND == 3 || LONG_DOUBLEKIND == 4
/* the 80-bit long doubles might have garbage in their excess bytes */
    memset((char *)&ldinf + 10, '\0', LONG_DOUBLESIZE - 10);
    memset((char *)&ldnan + 10, '\0', LONG_DOUBLESIZE - 10);
# endif
#endif
  if (argc == 2) {
    switch (argv[1][0]) {
    case '1': bytes(&dinf, sizeof(dinf)); break;
    case '2': bytes(&dnan, sizeof(dnan)); break;
#ifdef HAS_LONG_DOUBLE
    case '3': bytes(&ldinf, sizeof(ldinf)); break;
    case '4': bytes(&ldnan, sizeof(ldnan)); break;
#endif
    }
  }
  return 0;
}
EOP
set try
if eval $compile; then
    doubleinfbytes=`$run ./try 1`
    doublenanbytes=`$run ./try 2`
    case "$d_longdbl" in
    $define)
      longdblinfbytes=`$run ./try 3`
      longdblnanbytes=`$run ./try 4`
      ;;
    esac
else
    # Defaults in case the above test program failed.
    case "$doublekind" in
    1) # IEEE 754 32-bit LE
       doubleinfbytes='0x00, 0x00, 0xf0, 0x7f'
       doublenanbytes='0x00, 0x00, 0xf8, 0x7f'
       ;;
    2) # IEEE 754 32-bit BE
       doubleinfbytes='0x7f, 0xf0, 0x00, 0x00'
       doublenanbytes='0x7f, 0xf8, 0x00, 0x00'
       ;;
    3) # IEEE 754 64-bit LE
       doubleinfbytes='0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x7f'
       doublenanbytes='0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x7f'
       ;;
    4) # IEEE 754 64-bit BE
       doubleinfbytes='0x7f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00'
       doublenanbytes='0x7f, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00'
       ;;
    5) # IEEE 754 128-bit LE
       doubleinfbytes='0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x7f'
       doublenanbytes='0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x7f'
       ;;
    6) # IEEE 754 128-bit BE
       doubleinfbytes='0x7f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00'
       doublenanbytes='0x7f, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00'
       ;;
    7) # IEEE 754 64-bit mixed: 32-bit LEs in BE
       doubleinfbytes='0x00, 0x00, 0xf0, 0x7f, 0x00, 0x00, 0x00, 0x00'
       doublenanbytes='0x00, 0x00, 0xf8, 0x7f, 0x00, 0x00, 0x00, 0x00'
       ;;
    8) # IEEE 754 64-bit mixed: 32-bit BEs in LE
       doubleinfbytes='0x00, 0x00, 0x00, 0x00, 0x7f, 0xf0, 0x00, 0x00'
       doublenanbytes='0x00, 0x00, 0x00, 0x00, 0x7f, 0xf8, 0x00, 0x00'
       ;;
    9|10|11|12|13|14) # VAX/Cray/IBM floating point formats, no inf/nan.
       doubleinfbytes=$undef
       doublenanbytes=$undef
       ;;
    *) # No idea.
       doubleinfbytes=$undef
       doublenanbytes=$undef
       ;;
    esac
    case "$longdblkind" in
    1) # IEEE 754 128-bit LE
       longdblinfbytes='0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x7f'
       longdblnanbytes='0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0x7f'
       ;;
    2) # IEEE 754 128-bit BE
       longdblinfbytes='0x7f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00'
       longdblnanbytes='0x7f, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00'
       ;;
    3) # IEEE 754 80-bit LE, 12 or 16 bytes (x86)
       case "$longdblsize" in
       12) # x86 32-bit (96 bits, or 4 x 32, or 12 x 8)
           longdblinfbytes='0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0x7f, 0x00, 0x00'
           longdblnanbytes='0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0x7f, 0x00, 0x00'
           ;;
       16) # x86_64
           longdblinfbytes='0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00'
           longdblnanbytes='0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00'
           ;;
       *)  # No idea.
           longdblinfbytes=$undef
           longdblnanbytes=$undef
       ;;
       esac
       ;;
    4) # IEEE 754 80-bit BE, 12 or 16 bytes
       case "$longdblsize" in
       12) # 32-bit system
           longdblinfbytes='0x7f, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00'
           longdblnanbytes='0x7f, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00'
           ;;
       16) # 64-bit system
           longdblinfbytes='0x7f, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00'
           longdblnanbytes='0x7f, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00'
           ;;
       *)  # No idea.
           longdblinfbytes=$undef
           longdblnanbytes=$undef
       ;;
       esac
       ;;
    5) # 128-bit LE-LE "double double"
       longdblinfbytes='0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x7f'
       longdblnanbytes='0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x7f'
       ;;
    6) # 128-bit BE-BE "double double"
       longdblinfbytes='0x7f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00'
       longdblnanbytes='0x7f, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00'
       ;;
    7) # 128-bit LE-BE "double double"
       longdblinfbytes='0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00'
       longdblnanbytes='0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00'
       ;;
    8) # 128-bit BE-LE "double double"
       longdblinfbytes='0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00'
       longdblnanbytes='0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00'
       ;;
    9|10|11|12|13|14) # VAX/Cray/IBM floating point formats, no inf/nan.
       longdblinfbytes=$undef
       longdblnanbytes=$undef
       ;;
    *) # No idea.
       longdblinfbytes=$undef
       longdblnanbytes=$undef
       ;;
    esac
fi
# In case the program crashed the values are empty, turn them undef.
case "$doubleinfbytes" in
'') doubleinfbytes=$undef ;;
esac
case "$doublenanbytes" in
'') doublenanbytes=$undef ;;
esac
case "$longdblinfbytes" in
'') longdblinfbytes=$undef ;;
esac
case "$longdblnanbytes" in
'') longdblnanbytes=$undef ;;
esac
$rm_try

