blob: f86799da13587ed7b00b8a74b7e0a0532f0e2d09 [file] [log] [blame]
// computing floating point properties
/***************************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (the License); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*
* Copyright 1999-2007 Rogue Wave Software, Inc.
*
**************************************************************************/
// working around a Compaq C++ headers problem (PR #27459)
#if defined (__PURE_CNAME)
# undef __PURE_CNAME
#endif // __PURE_CNAME
#include "config.h"
enum {
// the enumerators below are expected to be hidden by macros #defined
// in the <float.h> header #included below through "float_defs.h";
// references to macros that are not #defined in the header will
// silently use these enumerators and prevent compilation errors that
// would result otherwise
DBL_DIG = 15, // default
DBL_MANT_DIG = 53,
DBL_MAX_10_EXP = 308,
DBL_MAX_EXP = 1024,
DBL_MIN_10_EXP = -307,
DBL_MIN_EXP = -1021,
FLT_DIG = 6,
FLT_MANT_DIG = 24,
FLT_MAX_10_EXP = 38,
FLT_MAX_EXP = 128,
FLT_MIN_10_EXP = -37,
FLT_MIN_EXP = -125,
FLT_RADIX = 2,
LDBL_DIG = -1,
LDBL_MANT_DIG = -1,
LDBL_MAX_10_EXP = -1,
LDBL_MAX_EXP = -1,
LDBL_MIN_10_EXP = -1,
LDBL_MIN_EXP = -1
};
#include <errno.h> // for ERANGE, errno
#include <stdio.h> // for printf()
#include <stdlib.h> // for strtod()
#include "float_defs.h" // for FLT_XXX, DBL_XXX, LDBL_XXX constants
#ifndef _RWSTD_NO_LIBC_EXCEPTION_SPEC
# define LIBC_THROWS() throw ()
#else
# define LIBC_THROWS() /* empty */
#endif // _RWSTD_NO_LIBC_EXCEPTION_SPEC
extern "C" {
#ifdef _RWSTD_NO_STRTOF
# ifndef _RWSTD_NO_STRTOF_IN_LIBC
# undef _RWSTD_NO_STRTOF
float strtof (const char*, char**) LIBC_THROWS ();
# endif // _RWSTD_NO_STRTOF_IN_LIBC
#endif // _RWSTD_NO_STRTOF
#ifdef _RWSTD_NO_STRTOD
# ifndef _RWSTD_NO_STRTOD_IN_LIBC
# undef _RWSTD_NO_STRTOD
double strtod (const char*, char**) LIBC_THROWS ();
# endif // _RWSTD_NO_STRTOD_IN_LIBC
#endif // _RWSTD_NO_STRTOD
#ifndef _RWSTD_NO_LONG_DOUBLE
# ifdef _RWSTD_NO_STRTOLD
# ifndef _RWSTD_NO_STRTOLD_IN_LIBC
# undef _RWSTD_NO_STRTOLD
long double strtold (const char*, char**) LIBC_THROWS ();
# endif // _RWSTD_NO_STRTOLD_IN_LIBC
# endif // _RWSTD_NO_STRTOLD
#endif // _RWSTD_NO_LONG_DOUBLE
}
#ifndef _RWSTD_NO_HONOR_STD
# ifdef _RWSTD_NO_STD_TERMINATE
# include "terminate.h"
# endif // _RWSTD_NO_STD_TERMINATE
#endif // _RWSTD_NO_HONOR_STD
// print a floating point number, either as a string (if the stringized
// constant is a valid number, and not some complex expression), or as
// a formatted floating point value
template <class FloatT>
void print_float (FloatT x, const char *xstr,
const char *macro_name, const char *fmt, int prec)
{
if ('-' == *xstr || '0' <= *xstr && '9' >= *xstr) {
printf ("#define _RWSTD_%-16s %s", macro_name, xstr);
}
else {
printf ("#define _RWSTD_%-16s ", macro_name);
printf (fmt, prec + 2, x);
}
puts ("");
}
#define DO_STRINGIZE(x) #x
#define STRINGIZE(x) DO_STRINGIZE (x)
#define PRINTINT(macro) \
if (-1 == (macro)) \
printf ("%s", "//"); \
printf ("#define _RWSTD_%-16s %6d\n", #macro, (macro))
#define PRINTFLT(macro, fmt, prec, suffix) \
print_float (macro, STRINGIZE (macro), #macro, "%.*" fmt "e" suffix, prec)
int main ()
{
//////////////////////////////////////////////////////////////////
// compute floating point limits
#undef LDBL_FMT
#ifdef _RWSTD_LDBL_PRINTF_PREFIX
# define LDBL_FMT _RWSTD_LDBL_PRINTF_PREFIX
#else
# define LDBL_FMT "L"
#endif
#if defined (FLT_ROUNDS)
printf ("#define _RWSTD_%-16s %6d /* %s */\n",
"FLT_ROUNDS", FLT_ROUNDS,
0 == FLT_ROUNDS ? "round toward zero"
: 1 == FLT_ROUNDS ? "round to nearest"
: 2 == FLT_ROUNDS ? "round toward infinity"
: 3 == FLT_ROUNDS ? "round toward negative infinity"
: "indeterminable");
#endif // FLT_ROUNDS
PRINTINT (DBL_DIG);
PRINTINT (DBL_MANT_DIG);
PRINTINT (DBL_MAX_10_EXP);
PRINTINT (DBL_MAX_EXP);
PRINTINT (DBL_MIN_10_EXP);
PRINTINT (DBL_MIN_EXP);
PRINTINT (FLT_DIG);
PRINTINT (FLT_MANT_DIG);
PRINTINT (FLT_MAX_10_EXP);
PRINTINT (FLT_MAX_EXP);
PRINTINT (FLT_MIN_10_EXP);
PRINTINT (FLT_MIN_EXP);
PRINTINT (FLT_RADIX);
#ifndef _RWSTD_NO_LONG_DOUBLE
PRINTINT (LDBL_DIG);
PRINTINT (LDBL_MANT_DIG);
PRINTINT (LDBL_MAX_10_EXP);
PRINTINT (LDBL_MAX_EXP);
PRINTINT (LDBL_MIN_10_EXP);
PRINTINT (LDBL_MIN_EXP);
#endif // _RWSTD_NO_LONG_DOUBLE
#if defined (DBL_MAX)
PRINTFLT (DBL_MAX, "l", DBL_DIG, "");
#endif // DBL_MAX
#if defined (FLT_MAX)
PRINTFLT (FLT_MAX, "", FLT_DIG, "F");
#endif // FLT_MAX
#ifndef _RWSTD_NO_LONG_DOUBLE
# if defined (LDBL_MAX)
PRINTFLT (LDBL_MAX, LDBL_FMT, DBL_DIG, "F");
# endif // LDBL_MAX
#endif // _RWSTD_NO_LONG_DOUBLE
#if defined (DBL_EPSILON)
PRINTFLT (DBL_EPSILON, "l", DBL_DIG, "");
#endif // DBL_EPSILON
#if defined (DBL_MIN)
PRINTFLT (DBL_MIN, "l", DBL_DIG, "");
#endif // DBL_MIN
#if defined (FLT_EPSILON)
PRINTFLT (FLT_EPSILON, "", FLT_DIG, "F");
#endif // FLT_EPSILON
#if defined (FLT_MIN)
PRINTFLT (FLT_MIN, "", FLT_DIG, "F");
#endif // FLT_MIN
#ifndef _RWSTD_NO_LONG_DOUBLE
# if defined (LDBL_EPSILON)
PRINTFLT (LDBL_EPSILON, LDBL_FMT, LDBL_DIG, "L");
# endif // LDBL_EPSILON
# if defined (LDBL_MIN)
PRINTFLT (LDBL_MIN, LDBL_FMT, LDBL_DIG, "L");
# endif // LDBL_MIN
#endif // _RWSTD_NO_LONG_DOUBLE
#if !defined (ERANGE)
# define ERANGE -1
#endif // ERANGE
#ifndef _RWSTD_NO_STRTOF
errno = 0;
// determine whether strtof() sets errno on underflow
const float f = strtof ("1.0e-999", (char**)0);
if (f < 0.0 || f > 1.0 || !errno)
printf ("#define _RWSTD_NO_STRTOF_UFLOW\n");
else
printf ("// #define _RWSTD_NO_STRTOF_UFLOW // %d%s\n",
errno, ERANGE == errno ? " (ERANGE)" : "");
#endif // _RWSTD_NO_STRTOF
#ifndef _RWSTD_NO_STRTOD
errno = 0;
// determine whether strtod() sets errno on underflow
const double d = strtod ("1.0e-999", (char**)0);
if (d < 0.0 || d > 1.0 || !errno)
printf ("#define _RWSTD_NO_STRTOD_UFLOW\n");
else
printf ("// #define _RWSTD_NO_STRTOD_UFLOW // %d%s\n",
errno, ERANGE == errno ? " (ERANGE)" : "");
#endif // _RWSTD_NO_STRTOD
#ifndef _RWSTD_NO_LONG_DOUBLE
# ifndef _RWSTD_NO_STRTOLD
errno = 0;
# if !defined (__hpux) || !defined (_LONG_DOUBLE)
// HP-UX strtold() returns struct long_double
// the macro _LONG_DOUBLE is #defined when the struct is defined
// note that gcc's replacement <stdlib.h> may actually define the
// function with the correct signature
// determine whether strtold() sets errno on underflow
const long double ld = strtold ("1.0e-9999", (char**)0);
# else // HP-UX with _LONG_DOUBLE #defined
union {
long double ld;
long_double data;
} ldu;
ldu.data = strtold ("1.0e-9999", (char**)0);
const long double ld = ldu.ld;
# endif // HP-UX, _LONG_DOUBLE
if (ld < 0.0 || ld > 1.0 || !errno)
printf ("#define _RWSTD_NO_STRTOLD_UFLOW\n");
else
printf ("// #define _RWSTD_NO_STRTOLD_UFLOW // %d%s\n",
errno, ERANGE == errno ? " (ERANGE)" : "");
# endif // _RWSTD_NO_STRTOLD
#endif // _RWSTD_NO_LONG_DOUBLE
return 0;
}