Mercurial > hg > octave-nkf
diff liboctave/util/lo-ieee.cc @ 18608:89bd70fae066 gui-release
fix initialization problem for Inf, NaN, and NA values (bug #41667)
* lo-cieee.c: Move function definitions to lo-ieee.cc and delete file.
* liboctave/util/module.mk (UTIL_C_SRC): Remove lo-cieee.c from the
list.
* lo-ieee.h (octave_Inf, octave_Float_Inf, octave_NA, octave_Float_NA,
octave_NaN, octave_Float_NaN): Define as macros that expand to
function calls instead of using global variables.
* lo-ieee.cc (lo_inf, lo_nan, lo_na, lo_float_inf, lo_float_nan,
lo_float_na): New static variables.
(octave_ieee_init): Set internal static variables here.
(__lo_ieee_isnan, __lo_ieee_finite, __lo_ieee_isinf,
__lo_ieee_signbit, __lo_ieee_float_isnan, __lo_ieee_float_finite,
__lo_ieee_float_isinf, __lo_ieee_float_signbit):
Use std:: functions if possible, otherwise rely on gnulib.
(lo_ieee_inf_value, lo_ieee_na_value, lo_ieee_nan_value,
lo_ieee_float_inf_value, lo_ieee_float_na_value,
lo_ieee_float_nan_value): Call init function.
author | John W. Eaton <jwe@octave.org> |
---|---|
date | Tue, 04 Mar 2014 10:49:31 -0500 |
parents | d63878346099 |
children | 5b263e517c95 |
line wrap: on
line diff
--- a/liboctave/util/lo-ieee.cc +++ b/liboctave/util/lo-ieee.cc @@ -24,63 +24,268 @@ #include <config.h> #endif +#include <cfloat> +#include <cmath> #include <cstdlib> #include <limits> +static double lo_inf; +static double lo_nan; +static double lo_na; + +static float lo_float_inf; +static float lo_float_nan; +static float lo_float_na; + +static int lo_ieee_hw; +static int lo_ieee_lw; + #include "lo-error.h" #include "lo-ieee.h" +#include "lo-math.h" #include "mach-info.h" +int +__lo_ieee_isnan (double x) +{ +#if defined (HAVE_CMATH_ISNAN) + return std::isnan (x); +#else + // Gnulib provides. + return isnan (x); +#endif +} + +int +__lo_ieee_finite (double x) +{ +#if defined (HAVE_CMATH_ISFINITE) + return std::isfinite (x); +#else + // Gnulib provides. + return finite (x); +#endif +} + +int +__lo_ieee_isinf (double x) +{ +#if defined (HAVE_CMATH_ISINF) + return std::isinf (x); +#else + // Gnulib provides. + return isinf (x); +#endif +} + +int +__lo_ieee_is_NA (double x) +{ + lo_ieee_double t; + t.value = x; + return (__lo_ieee_isnan (x) && t.word[lo_ieee_hw] == LO_IEEE_NA_HW + && t.word[lo_ieee_lw] == LO_IEEE_NA_LW) ? 1 : 0; +} + +int +__lo_ieee_is_old_NA (double x) +{ + lo_ieee_double t; + t.value = x; + return (__lo_ieee_isnan (x) && t.word[lo_ieee_lw] == LO_IEEE_NA_LW_OLD + && t.word[lo_ieee_hw] == LO_IEEE_NA_HW_OLD) ? 1 : 0; +} + +double +__lo_ieee_replace_old_NA (double x) +{ + if (__lo_ieee_is_old_NA (x)) + return lo_ieee_na_value (); + else + return x; +} + +int +__lo_ieee_is_NaN_or_NA (double x) +{ + return __lo_ieee_isnan (x); +} + +double +lo_ieee_inf_value (void) +{ + octave_ieee_init (); + + return lo_inf; +} + +double +lo_ieee_na_value (void) +{ + octave_ieee_init (); + + return lo_na; +} + +double +lo_ieee_nan_value (void) +{ + octave_ieee_init (); + + return lo_nan; +} + +int +__lo_ieee_signbit (double x) +{ +#if defined (HAVE_CMATH_SIGNBIT) + return std::signbit (x); +#else + // Gnulib provides. + return signbit (x); +#endif +} + +int +__lo_ieee_float_isnan (float x) +{ +#if defined (HAVE_CMATH_ISNAN) + return std::isnan (x); +#else + // Gnulib provides. + return isnan (x); +#endif +} + +int +__lo_ieee_float_finite (float x) +{ +#if defined (HAVE_CMATH_ISFINITE) + return std::isfinite (x) != 0 && ! __lo_ieee_float_isnan (x); +#else + // Gnulib provides. + return finite (x); +#endif +} + +int +__lo_ieee_float_isinf (float x) +{ +#if defined (HAVE_CMATH_ISINF) + return std::isinf (x); +#else + // Gnulib provides. + return isinf (x); +#endif +} + +int +__lo_ieee_float_is_NA (float x) +{ + lo_ieee_float t; + t.value = x; + return (__lo_ieee_float_isnan (x) && (t.word == LO_IEEE_NA_FLOAT)) ? 1 : 0; +} + +int +__lo_ieee_float_is_NaN_or_NA (float x) +{ + return __lo_ieee_float_isnan (x); +} + +float +lo_ieee_float_inf_value (void) +{ + octave_ieee_init (); + + return lo_float_inf; +} + +float +lo_ieee_float_na_value (void) +{ + octave_ieee_init (); + + return lo_float_na; +} + +float +lo_ieee_float_nan_value (void) +{ + octave_ieee_init (); + + return lo_float_nan; +} + +int +__lo_ieee_float_signbit (float x) +{ +#if defined (HAVE_CMATH_SIGNBIT) + return std::signbit (x); +#else + // Gnulib provides. + return signbit (x); +#endif +} + void octave_ieee_init (void) { - oct_mach_info::float_format ff = oct_mach_info::native_float_format (); - - switch (ff) - { - case oct_mach_info::flt_fmt_ieee_big_endian: - case oct_mach_info::flt_fmt_ieee_little_endian: - { - octave_NaN = std::numeric_limits<double>::quiet_NaN (); - octave_Inf = std::numeric_limits<double>::infinity (); + bool initialized = false; - octave_Float_NaN = std::numeric_limits<float>::quiet_NaN (); - octave_Float_Inf = std::numeric_limits<float>::infinity (); - - // The following is patterned after code in R. + if (! initialized) + { + oct_mach_info::float_format ff = oct_mach_info::native_float_format (); - if (ff == oct_mach_info::flt_fmt_ieee_big_endian) - { - lo_ieee_hw = 0; - lo_ieee_lw = 1; - } - else + switch (ff) + { + case oct_mach_info::flt_fmt_ieee_big_endian: + case oct_mach_info::flt_fmt_ieee_little_endian: { - lo_ieee_hw = 1; - lo_ieee_lw = 0; - } + lo_nan = std::numeric_limits<double>::quiet_NaN (); + lo_inf = std::numeric_limits<double>::infinity (); + + lo_float_nan = std::numeric_limits<float>::quiet_NaN (); + lo_float_inf = std::numeric_limits<float>::infinity (); + + // The following is patterned after code in R. - lo_ieee_double t; - t.word[lo_ieee_hw] = LO_IEEE_NA_HW; - t.word[lo_ieee_lw] = LO_IEEE_NA_LW; - - octave_NA = t.value; + if (ff == oct_mach_info::flt_fmt_ieee_big_endian) + { + lo_ieee_hw = 0; + lo_ieee_lw = 1; + } + else + { + lo_ieee_hw = 1; + lo_ieee_lw = 0; + } - lo_ieee_float tf; - tf.word = LO_IEEE_NA_FLOAT; - octave_Float_NA = tf.value; - } - break; + lo_ieee_double t; + t.word[lo_ieee_hw] = LO_IEEE_NA_HW; + t.word[lo_ieee_lw] = LO_IEEE_NA_LW; + + lo_na = t.value; + + lo_ieee_float tf; + tf.word = LO_IEEE_NA_FLOAT; + + lo_float_na = tf.value; + } + break; - default: - // If the format is unknown, then you will probably not have a - // useful system, so we will abort here. Anyone wishing to - // experiment with building Octave on a system without IEEE - // floating point should be capable of removing this check and - // the configure test. - (*current_liboctave_error_handler) - ("lo_ieee_init: floating point format is not IEEE! Maybe DLAMCH is miscompiled, or you are using some strange system without IEEE floating point math?"); - abort (); + default: + // If the format is unknown, then you will probably not have a + // useful system, so we will abort here. Anyone wishing to + // experiment with building Octave on a system without IEEE + // floating point should be capable of removing this check and + // the configure test. + (*current_liboctave_error_handler) + ("lo_ieee_init: floating point format is not IEEE! Maybe DLAMCH is miscompiled, or you are using some strange system without IEEE floating point math?"); + abort (); + } + + initialized = true; } }