# HG changeset patch # User John W. Eaton # Date 1393948171 18000 # Node ID 89bd70fae066c90426e587fc5364906d373fc58e # Parent 4cf930a64fad701ac706c6160346209494c0a6b4 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. diff -r 4cf930a64fad -r 89bd70fae066 configure.ac --- a/configure.ac Sat Mar 01 22:10:36 2014 -0800 +++ b/configure.ac Tue Mar 04 10:49:31 2014 -0500 @@ -2222,6 +2222,7 @@ OCTAVE_CHECK_FUNC_CMATH(isnan) OCTAVE_CHECK_FUNC_CMATH(isinf) OCTAVE_CHECK_FUNC_CMATH(isfinite) +OCTAVE_CHECK_FUNC_CMATH(signbit) ## Check for Inf and NaN functions diff -r 4cf930a64fad -r 89bd70fae066 liboctave/util/lo-cieee.c --- a/liboctave/util/lo-cieee.c Sat Mar 01 22:10:36 2014 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,279 +0,0 @@ -/* - -Copyright (C) 2002-2013 John W. Eaton - -This file is part of Octave. - -Octave 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. - -Octave 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 Octave; see the file COPYING. If not, see -. - -*/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include - -#if defined (HAVE_FLOATINGPOINT_H) -#include -#endif - -#if defined (HAVE_IEEEFP_H) -#include -#endif - -#include "lo-ieee.h" -#include "lo-math.h" - -#if ! defined (HAVE_ISNAN) && defined (HAVE__ISNAN) -#define isnan _isnan -#define HAVE_ISNAN 1 -#endif - -#if ! defined (HAVE_FINITE) && defined (HAVE__FINITE) -#define finite _finite -#define HAVE_FINITE 1 -#endif - -#if defined (_AIX) && defined (__GNUG__) -#undef finite -#define finite(x) ((x) < DBL_MAX && (x) > -DBL_MAX) -#endif - -/* Octave's idea of infinity. */ -double octave_Inf; -float octave_Float_Inf; - -/* Octave's idea of a missing value. */ -double octave_NA; -float octave_Float_NA; - -/* Octave's idea of not a number. */ -double octave_NaN; -float octave_Float_NaN; - -int lo_ieee_hw; -int lo_ieee_lw; - -int -__lo_ieee_isnan (double x) -{ -#if defined (HAVE_ISNAN) - return isnan (x); -#else - return 0; -#endif -} - -int -__lo_ieee_finite (double x) -{ -#if defined (HAVE_FINITE) - return finite (x) != 0 && ! __lo_ieee_isnan (x); -#elif defined (HAVE_ISINF) - return (! isinf (x) && ! __lo_ieee_isnan (x)); -#else - return ! __lo_ieee_isnan (x); -#endif -} - -int -__lo_ieee_isinf (double x) -{ -#if defined (HAVE_ISINF) - return isinf (x); -#elif defined (HAVE_FINITE) - return (! (finite (x) || __lo_ieee_isnan (x))); -#else - return 0; -#endif -} - -int -__lo_ieee_is_NA (double x) -{ -#if defined (HAVE_ISNAN) - lo_ieee_double t; - t.value = x; - return (isnan (x) && t.word[lo_ieee_hw] == LO_IEEE_NA_HW - && t.word[lo_ieee_lw] == LO_IEEE_NA_LW) ? 1 : 0; -#else - return 0; -#endif -} - -int -__lo_ieee_is_old_NA (double x) -{ -#if defined (HAVE_ISNAN) - lo_ieee_double t; - t.value = x; - return (isnan (x) && t.word[lo_ieee_lw] == LO_IEEE_NA_LW_OLD - && t.word[lo_ieee_hw] == LO_IEEE_NA_HW_OLD) ? 1 : 0; -#else - return 0; -#endif -} - -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) -{ - return octave_Inf; -} - -double -lo_ieee_na_value (void) -{ - return octave_NA; -} - -double -lo_ieee_nan_value (void) -{ - return octave_NaN; -} - -#if ! (defined (signbit) || defined (HAVE_DECL_SIGNBIT)) && defined (HAVE_SIGNBIT) -extern int signbit (double); -#endif - -int -__lo_ieee_signbit (double x) -{ - /* In the following definitions, only check x < 0 explicitly to avoid - a function call when it looks like signbit or copysign are actually - functions. */ - -#if defined (signbit) - return signbit (x); -#elif defined (HAVE_SIGNBIT) - return (x < 0 || signbit (x)); -#elif defined (copysign) - return (copysign (1.0, x) < 0); -#elif defined (HAVE_COPYSIGN) - return (x < 0 || copysign (1.0, x) < 0); -#else - return x < 0; -#endif -} - -int -__lo_ieee_float_isnan (float x) -{ -#if defined (HAVE_ISNAN) - return isnan (x); -#else - return 0; -#endif -} - -int -__lo_ieee_float_finite (float x) -{ -#if defined (HAVE_FINITE) - return finite (x) != 0 && ! __lo_ieee_float_isnan (x); -#elif defined (HAVE_ISINF) - return (! isinf (x) && ! __lo_ieee_float_isnan (x)); -#else - return ! __lo_ieee_float_isnan (x); -#endif -} - -int -__lo_ieee_float_isinf (float x) -{ -#if defined (HAVE_ISINF) - return isinf (x); -#elif defined (HAVE_FINITE) - return (! (finite (x) || __lo_ieee_float_isnan (x))); -#else - return 0; -#endif -} - -int -__lo_ieee_float_is_NA (float x) -{ -#if defined (HAVE_ISNAN) - lo_ieee_float t; - t.value = x; - return (isnan (x) && (t.word == LO_IEEE_NA_FLOAT)) ? 1 : 0; -#else - return 0; -#endif -} - -int -__lo_ieee_float_is_NaN_or_NA (float x) -{ - return __lo_ieee_float_isnan (x); -} - -float -lo_ieee_float_inf_value (void) -{ - return octave_Float_Inf; -} - -float -lo_ieee_float_na_value (void) -{ - return octave_Float_NA; -} - -float -lo_ieee_float_nan_value (void) -{ - return octave_Float_NaN; -} - -#if ! (defined (signbit) || defined (HAVE_DECL_SIGNBIT)) && defined (HAVE_SIGNBIT) -extern int signbit (float); -#endif - -int -__lo_ieee_float_signbit (float x) -{ - /* In the following definitions, only check x < 0 explicitly to avoid - a function call when it looks like signbit or copysign are actually - functions. */ - -#if defined (signbit) - return signbit (x); -#elif defined (HAVE_SIGNBIT) - return (x < 0 || signbit (x)); -#elif defined (copysign) - return (copysign (1.0, x) < 0); -#elif defined (HAVE_COPYSIGN) - return (x < 0 || copysign (1.0, x) < 0); -#else - return x < 0; -#endif -} diff -r 4cf930a64fad -r 89bd70fae066 liboctave/util/lo-ieee.cc --- a/liboctave/util/lo-ieee.cc Sat Mar 01 22:10:36 2014 -0800 +++ b/liboctave/util/lo-ieee.cc Tue Mar 04 10:49:31 2014 -0500 @@ -24,63 +24,268 @@ #include #endif +#include +#include #include #include +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::quiet_NaN (); - octave_Inf = std::numeric_limits::infinity (); + bool initialized = false; - octave_Float_NaN = std::numeric_limits::quiet_NaN (); - octave_Float_Inf = std::numeric_limits::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::quiet_NaN (); + lo_inf = std::numeric_limits::infinity (); + + lo_float_nan = std::numeric_limits::quiet_NaN (); + lo_float_inf = std::numeric_limits::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; } } diff -r 4cf930a64fad -r 89bd70fae066 liboctave/util/lo-ieee.h --- a/liboctave/util/lo-ieee.h Sat Mar 01 22:10:36 2014 -0800 +++ b/liboctave/util/lo-ieee.h Tue Mar 04 10:49:31 2014 -0500 @@ -28,29 +28,26 @@ #endif /* Octave's idea of infinity. */ -extern OCTAVE_API double octave_Inf; +#define octave_Inf (lo_ieee_inf_value ()) /* Octave's idea of a missing value. */ -extern OCTAVE_API double octave_NA; +#define octave_NA (lo_ieee_na_value ()) /* Octave's idea of not a number. */ -extern OCTAVE_API double octave_NaN; +#define octave_NaN (lo_ieee_nan_value ()) /* Octave's idea of infinity. */ -extern OCTAVE_API float octave_Float_Inf; +#define octave_Float_Inf (lo_ieee_float_inf_value ()) /* Octave's idea of a missing value. */ -extern OCTAVE_API float octave_Float_NA; +#define octave_Float_NA (lo_ieee_float_na_value ()) /* Octave's idea of not a number. */ -extern OCTAVE_API float octave_Float_NaN; +#define octave_Float_NaN (lo_ieee_float_nan_value ()) /* FIXME -- this code assumes that a double has twice the number of bits as an int */ -extern OCTAVE_API int lo_ieee_hw; -extern OCTAVE_API int lo_ieee_lw; - typedef union { double value; diff -r 4cf930a64fad -r 89bd70fae066 liboctave/util/module.mk --- a/liboctave/util/module.mk Sat Mar 01 22:10:36 2014 -0800 +++ b/liboctave/util/module.mk Tue Mar 04 10:49:31 2014 -0500 @@ -47,7 +47,6 @@ UTIL_C_SRC = \ util/f2c-main.c \ - util/lo-cieee.c \ util/lo-cutils.c \ util/oct-rl-edit.c \ util/oct-rl-hist.c