From bug-request at octave dot org Fri Apr 7 01:06:59 2006 Subject: Incompatibility of 'nan' to Matlab From: "John W. Eaton" To: Michael Hanke Cc: bug at octave dot org Date: Fri, 7 Apr 2006 02:06:33 -0400 On 21-Mar-2006, Michael Hanke wrote: | Bug report for Octave 2.1.72 configured for i486-pc-linux-gnu | | Description: | ----------- | | * While trying to port some Matlab code to Octave I discovered | a different (or missing) behavior of 'nan' in Octave. In | Octave 'nan' seems to be only a variable, whereas in Matlab 'nan' | can build a matrix of NaNs of arbitrary size (and dimensions) -- | much like the zeros() command. | I could not find this in the bugs archive, but I'm not completely | sure whether incompatibilities to Matlab count as real bugs. Well, I think it is a relatively new feature of Matlab. It is a sort of bug, and fixing it fits in with my goal of converting built-in variables and constants to functions, so please try the following patch. It also makes a similar change for the other similar functions: Inf, e, eps, pi, realmax, realmin, I, NA, false, and true. It would be nice if people could try this and report problems. I've not done much testing. If anyone is looking for a project, it would be nice to have some tests for these functions included in the sources. Thanks, jwe src/ChangeLog: 2006-04-07 John W. Eaton * data.cc (fill_matrix): Create separate versions for int, bool, and double, and Complex values. (FInf, FNaN, Fe, Feps, Fpi, Frealmax, Frealmin, FI, FNA, Ffalse, Ftrue): New functions to replace DEFCONST and DEFCONSTX macros in symbols_of_data. Provide i, J, and j aliases for I. Provide nan alias for NaN. Provide inf alias for Inf. (symbols_of_data): Delete. 2006-04-06 John W. Eaton * parse.y (parse_and_execute, parse_fcn_file): Index: src/data.cc =================================================================== RCS file: /cvs/octave/src/data.cc,v retrieving revision 1.155 diff -u -r1.155 data.cc --- src/data.cc 4 Apr 2006 18:29:13 -0000 1.155 +++ src/data.cc 7 Apr 2006 06:01:14 -0000 at @ -1426,7 +1426,7 @@ } static octave_value -fill_matrix (const octave_value_list& args, double val, const char *fcn) +fill_matrix (const octave_value_list& args, int val, const char *fcn) { octave_value retval; at @ -1542,6 +1542,213 @@ return retval; } +static octave_value +fill_matrix (const octave_value_list& args, double val, const char *fcn) +{ + octave_value retval; + + int nargin = args.length (); + + oct_data_conv::data_type dt = oct_data_conv::dt_double; + + dim_vector dims (1, 1); + + if (nargin > 0 && args(nargin-1).is_string ()) + { + std::string nm = args(nargin-1).string_value (); + nargin--; + + dt = oct_data_conv::string_to_data_type (nm); + + if (error_state) + return retval; + } + + switch (nargin) + { + case 0: + break; + + case 1: + get_dimensions (args(0), fcn, dims); + break; + + default: + { + dims.resize (nargin); + + for (int i = 0; i < nargin; i++) + { + dims(i) = args(i).is_empty () ? 0 : args(i).int_value (); + + if (error_state) + { + error ("%s: expecting scalar integer arguments", fcn); + break; + } + } + } + break; + } + + if (! error_state) + { + dims.chop_trailing_singletons (); + + check_dimensions (dims, fcn); + + // Note that automatic narrowing will handle conversion from + // NDArray to scalar. + + if (! error_state) + { + switch (dt) + { + case oct_data_conv::dt_single: // XXX FIXME XXX + case oct_data_conv::dt_double: + retval = NDArray (dims, val); + break; + + default: + error ("%s: invalid class name", fcn); + break; + } + } + } + + return retval; +} + +static octave_value +fill_matrix (const octave_value_list& args, const Complex& val, + const char *fcn) +{ + octave_value retval; + + int nargin = args.length (); + + oct_data_conv::data_type dt = oct_data_conv::dt_double; + + dim_vector dims (1, 1); + + if (nargin > 0 && args(nargin-1).is_string ()) + { + std::string nm = args(nargin-1).string_value (); + nargin--; + + dt = oct_data_conv::string_to_data_type (nm); + + if (error_state) + return retval; + } + + switch (nargin) + { + case 0: + break; + + case 1: + get_dimensions (args(0), fcn, dims); + break; + + default: + { + dims.resize (nargin); + + for (int i = 0; i < nargin; i++) + { + dims(i) = args(i).is_empty () ? 0 : args(i).int_value (); + + if (error_state) + { + error ("%s: expecting scalar integer arguments", fcn); + break; + } + } + } + break; + } + + if (! error_state) + { + dims.chop_trailing_singletons (); + + check_dimensions (dims, fcn); + + // Note that automatic narrowing will handle conversion from + // NDArray to scalar. + + if (! error_state) + { + switch (dt) + { + case oct_data_conv::dt_single: // XXX FIXME XXX + case oct_data_conv::dt_double: + retval = ComplexNDArray (dims, val); + break; + + default: + error ("%s: invalid class name", fcn); + break; + } + } + } + + return retval; +} + +static octave_value +fill_matrix (const octave_value_list& args, bool val, const char *fcn) +{ + octave_value retval; + + int nargin = args.length (); + + dim_vector dims (1, 1); + + switch (nargin) + { + case 0: + break; + + case 1: + get_dimensions (args(0), fcn, dims); + break; + + default: + { + dims.resize (nargin); + + for (int i = 0; i < nargin; i++) + { + dims(i) = args(i).is_empty () ? 0 : args(i).int_value (); + + if (error_state) + { + error ("%s: expecting scalar integer arguments", fcn); + break; + } + } + } + break; + } + + if (! error_state) + { + dims.chop_trailing_singletons (); + + check_dimensions (dims, fcn); + + // Note that automatic narrowing will handle conversion from + // NDArray to scalar. + + if (! error_state) + retval = boolNDArray (dims, val); + } + + return retval; +} + DEFUN (ones, args, , "-*- texinfo -*-\n\ at deftypefn {Built-in Function} {} ones (@var{x})\n\ at @ -1559,14 +1766,14 @@ at end example\n\ \n\ The optional argument at var{class}, allows @code{ones} to return an array of\n\ -the specified type, like\n\ +the specified type, for example\n\ \n\ at example\n\ val = ones (n,m, \"uint8\")\n\ at end example\n\ at end deftypefn") { - return fill_matrix (args, 1.0, "ones"); + return fill_matrix (args, 1, "ones"); } DEFUN (zeros, args, , at @ -1579,14 +1786,256 @@ The arguments are handled the same as the arguments for at code{eye} dot \n\ \n\ The optional argument at var{class}, allows @code{zeros} to return an array of\n\ -the specified type, like\n\ +the specified type, for example\n\ \n\ at example\n\ val = zeros (n,m, \"uint8\")\n\ at end example\n\ at end deftypefn") { - return fill_matrix (args, 0.0, "zeros"); + return fill_matrix (args, 0, "zeros"); +} + +DEFUN (Inf, args, , + "-*- texinfo -*-\n\ + at deftypefn {Built-in Function} {} Inf (@var{x})\n\ + at deftypefnx {Built-in Function} {} Inf (@var{n}, @var{m})\n\ + at deftypefnx {Built-in Function} {} Inf (@var{n}, @var{m}, @var{k}, @dots{})\n\ + at deftypefnx {Built-in Function} {} Inf (@dots{}, @var{class})\n\ +Return a matrix or N-dimensional array whose elements are all Infinity.\n\ +The arguments are handled the same as the arguments for at code{eye} dot \n\ +The optional argument at var{class} may be either @samp{\"single\"} or\n\ + at samp{\"double\"} The default is @samp{\"double\"}.\n\ + at end deftypefn") +{ + return fill_matrix (args, lo_ieee_inf_value (), "Inf"); +} + +DEFALIAS (inf, Inf); + +DEFUN (NaN, args, , + "-*- texinfo -*-\n\ + at deftypefn {Built-in Function} {} NaN (@var{x})\n\ + at deftypefnx {Built-in Function} {} NaN (@var{n}, @var{m})\n\ + at deftypefnx {Built-in Function} {} NaN (@var{n}, @var{m}, @var{k}, @dots{})\n\ + at deftypefnx {Built-in Function} {} NaN (@dots{}, @var{class})\n\ +Return a matrix or N-dimensional array whose elements are all NaN\n\ +(Not a Number). The value NaN is the result of an operation like\n\ + at iftex\n\ + at tex\n\ +$0/0$, or $\\infty - \\infty$,\n\ + at end tex\n\ + at end iftex\n\ + at ifinfo\n\ +0/0, or at samp{Inf - Inf},\n\ + at end ifinfo\n\ +or any operation with a NaN.\n\ +\n\ +Note that NaN always compares not equal to NaN. This behavior is\n\ +specified by the IEEE standard for floating point arithmetic. To\n\ +find NaN values, you must use the at code{isnan} function.\n\ +\n\ +The arguments are handled the same as the arguments for at code{eye} dot \n\ +The optional argument at var{class} may be either @samp{\"single\"} or\n\ + at samp{\"double\"} The default is @samp{\"double\"}.\n\ + at end deftypefn") +{ + return fill_matrix (args, lo_ieee_nan_value (), "NaN"); +} + +DEFALIAS (nan, NaN); + +DEFUN (e, args, , + "-*- texinfo -*-\n\ + at deftypefn {Built-in Function} {} e (@var{x})\n\ + at deftypefnx {Built-in Function} {} e (@var{n}, @var{m})\n\ + at deftypefnx {Built-in Function} {} e (@var{n}, @var{m}, @var{k}, @dots{})\n\ + at deftypefnx {Built-in Function} {} e (@dots{}, @var{class})\n\ +Return a matrix or N-dimensional array whose elements are all equal\n\ +to the base of natural logarithms. The constant\n\ + at iftex\n\ + at tex\n\ + $e$\n\ + at end tex\n\ + at end iftex\n\ + at ifinfo\n\ + at var{e}\n\ + at end ifinfo\n\ + satisfies the equation\n\ + at iftex\n\ + at tex\n\ + $\\log (e) = 1$.\n\ + at end tex\n\ + at end iftex\n\ + at ifinfo\n\ + at code{log} (@var{e}) = 1.\n\ + at end ifinfo\n\ + at end deftypefn") +{ +#if defined (M_E) + double e_val = M_E; +#else + double e_val = exp (1.0); +#endif + + return fill_matrix (args, e_val, "e"); +} + +DEFUN (eps, args, , + "-*- texinfo -*-\n\ + at deftypefn {Built-in Function} {} eps (@var{x})\n\ + at deftypefnx {Built-in Function} {} eps (@var{n}, @var{m})\n\ + at deftypefnx {Built-in Function} {} eps (@var{n}, @var{m}, @var{k}, @dots{})\n\ + at deftypefnx {Built-in Function} {} eps (@dots{}, @var{class})\n\ +Return a matrix or N-dimensional array whose elements are all eps,\n\ +the machine precision. More precisely, at code{eps} is the largest\n\ +relative spacing between any two adjacent numbers in the machine's\n\ +floating point system. This number is obviously system-dependent. On\n\ +machines that support 64 bit IEEE floating point arithmetic, at code{eps}\n\ +is approximately\n\ + at ifinfo\n\ + 2.2204e-16.\n\ + at end ifinfo\n\ + at iftex\n\ + at tex\n\ + $2.2204\\times10^{-16}$.\n\ + at end tex\n\ + at end iftex\n\ + at end deftypefn") +{ + return fill_matrix (args, DBL_EPSILON, "eps"); +} + +DEFUN (pi, args, , + "-*- texinfo -*-\n\ + at deftypefn {Built-in Function} {} pi (@var{x})\n\ + at deftypefnx {Built-in Function} {} pi (@var{n}, @var{m})\n\ + at deftypefnx {Built-in Function} {} pi (@var{n}, @var{m}, @var{k}, @dots{})\n\ + at deftypefnx {Built-in Function} {} pi (@dots{}, @var{class})\n\ +Return a matrix or N-dimensional array whose elements are all equal\n\ +to the ratio of the circumference of a circle to its diameter.\n\ +Internally, at code{pi} is computed as @samp{4.0 * atan (1.0)}.\n\ + at end deftypefn") +{ +#if defined (M_PI) + double pi_val = M_PI; +#else + double pi_val = 4.0 * atan (1.0); +#endif + + return fill_matrix (args, pi_val, "pi"); +} + +DEFUN (realmax, args, , + "-*- texinfo -*-\n\ + at deftypefn {Built-in Function} {} realmax (@var{x})\n\ + at deftypefnx {Built-in Function} {} realmax (@var{n}, @var{m})\n\ + at deftypefnx {Built-in Function} {} realmax (@var{n}, @var{m}, @var{k}, @dots{})\n\ + at deftypefnx {Built-in Function} {} realmax (@dots{}, @var{class})\n\ +Return a matrix or N-dimensional array whose elements are all equal\n\ +to the largest floating point number that is representable. The actual\n\ +value is system-dependent. On machines that support 64-bit IEEE\n\ +floating point arithmetic, at code{realmax} is approximately\n\ + at ifinfo\n\ + 1.7977e+308\n\ + at end ifinfo\n\ + at iftex\n\ + at tex\n\ + $1.7977\\times10^{308}$.\n\ + at end tex\n\ + at end iftex\n\ + at seealso{realmin}\n\ + at end deftypefn") +{ + return fill_matrix (args, DBL_MAX, "realmax"); +} + +DEFUN (realmin, args, , + "-*- texinfo -*-\n\ + at deftypefn {Built-in Function} {} realmin (@var{x})\n\ + at deftypefnx {Built-in Function} {} realmin (@var{n}, @var{m})\n\ + at deftypefnx {Built-in Function} {} realmin (@var{n}, @var{m}, @var{k}, @dots{})\n\ + at deftypefnx {Built-in Function} {} realmin (@dots{}, @var{class})\n\ +Return a matrix or N-dimensional array whose elements are all equal\n\ +to the smallest normalized floating point number that is representable.\n\ +The actual value is system-dependent. On machines that support\n\ +64-bit IEEE floating point arithmetic, at code{realmin} is approximately\n\ + at ifinfo\n\ + 2.2251e-308\n\ + at end ifinfo\n\ + at iftex\n\ + at tex\n\ + $2.2251\\times10^{-308}$.\n\ + at end tex\n\ + at end iftex\n\ + at seealso{realmax}\n\ + at end deftypefn") +{ + return fill_matrix (args, DBL_MIN, "realmin"); +} + +DEFUN (I, args, , + "-*- texinfo -*-\n\ + at deftypefn {Built-in Function} {} I (@var{x})\n\ + at deftypefnx {Built-in Function} {} I (@var{n}, @var{m})\n\ + at deftypefnx {Built-in Function} {} I (@var{n}, @var{m}, @var{k}, @dots{})\n\ + at deftypefnx {Built-in Function} {} I (@dots{}, @var{class})\n\ +Return a matrix or N-dimensional array whose elements are all equal\n\ +to the pure imaginary unit, defined as\n\ + at iftex\n\ + at tex\n\ + $\\sqrt{-1}$.\n\ + at end tex\n\ + at end iftex\n\ + at ifinfo\n\ + at code{sqrt (-1)}.\n\ + at end ifinfo\n\ +Since I (also i, J, and J) is a function, you can use the name(s) for\n\ +other purposes.\n\ + at end deftypefn") +{ + return fill_matrix (args, Complex (0.0, 1.0), "I"); +} + +DEFALIAS (i, I); +DEFALIAS (J, I); +DEFALIAS (j, I); + +DEFUN (NA, args, , + "-*- texinfo -*-\n\ + at deftypefn {Built-in Function} {} NA (@var{x})\n\ + at deftypefnx {Built-in Function} {} NA (@var{n}, @var{m})\n\ + at deftypefnx {Built-in Function} {} NA (@var{n}, @var{m}, @var{k}, @dots{})\n\ + at deftypefnx {Built-in Function} {} NA (@dots{}, @var{class})\n\ +Return a matrix or N-dimensional array whose elements are all equal\n\ +to the special constant used to designate missing values.\n\ + at end deftypefn") +{ + return fill_matrix (args, lo_ieee_na_value (), "NA"); +} + +DEFUN (false, args, , + "-*- texinfo -*-\n\ + at deftypefn {Built-in Function} {} false (@var{x})\n\ + at deftypefnx {Built-in Function} {} false (@var{n}, @var{m})\n\ + at deftypefnx {Built-in Function} {} false (@var{n}, @var{m}, @var{k}, @dots{})\n\ +Return a matrix or N-dimensional array whose elements are all logical 0.\n\ +The arguments are handled the same as the arguments for at code{eye} dot \n\ + at end deftypefn") +{ + return fill_matrix (args, false, "false"); +} + +DEFUN (true, args, , + "-*- texinfo -*-\n\ + at deftypefn {Built-in Function} {} true (@var{x})\n\ + at deftypefnx {Built-in Function} {} true (@var{n}, @var{m})\n\ + at deftypefnx {Built-in Function} {} true (@var{n}, @var{m}, @var{k}, @dots{})\n\ +Return a matrix or N-dimensional array whose elements are all logical 1.\n\ +The arguments are handled the same as the arguments for at code{eye} dot \n\ + at end deftypefn") +{ + return fill_matrix (args, true, "true"); } template at @ -2065,196 +2514,6 @@ return retval; } -void -symbols_of_data (void) -{ - -#define IMAGINARY_DOC_STRING "-*- texinfo -*-\n\ - at defvr {Built-in Constant} I\n\ - at defvrx {Built-in Constant} J\n\ - at defvrx {Built-in Constant} i\n\ - at defvrx {Built-in Constant} j\n\ -A pure imaginary number, defined as\n\ - at iftex\n\ - at tex\n\ - $\\sqrt{-1}$.\n\ - at end tex\n\ - at end iftex\n\ - at ifinfo\n\ - at code{sqrt (-1)}.\n\ - at end ifinfo\n\ -These built-in variables behave like functions so you can use the names\n\ -for other purposes. If you use them as variables and assign values to\n\ -them and then clear them, they once again assume their special predefined\n\ -values at xref{Status of Variables}.\n\ - at end defvr" - -#define INFINITY_DOC_STRING "-*- texinfo -*-\n\ - at defvr {Built-in Constant} Inf\n\ - at defvrx {Built-in Constant} inf\n\ -Infinity. This is the result of an operation like 1/0, or an operation\n\ -that results in a floating point overflow.\n\ - at end defvr" - -#define NAN_DOC_STRING "-*- texinfo -*-\n\ - at defvr {Built-in Constant} NaN\n\ - at defvrx {Built-in Constant} nan\n\ -Not a number. This is the result of an operation like\n\ - at iftex\n\ - at tex\n\ -$0/0$, or $\\infty - \\infty$,\n\ - at end tex\n\ - at end iftex\n\ - at ifinfo\n\ -0/0, or at samp{Inf - Inf},\n\ - at end ifinfo\n\ -or any operation with a NaN.\n\ -\n\ -Note that NaN always compares not equal to NaN. This behavior is\n\ -specified by the IEEE standard for floating point arithmetic. To\n\ -find NaN values, you must use the at code{isnan} function.\n\ - at end defvr" - - DEFCONST (I, Complex (0.0, 1.0), - IMAGINARY_DOC_STRING); - - DEFCONST (Inf, lo_ieee_inf_value (), - INFINITY_DOC_STRING); - - DEFCONST (J, Complex (0.0, 1.0), - IMAGINARY_DOC_STRING); - - DEFCONST (NA, lo_ieee_na_value (), - "-*- texinfo -*-\n\ - at defvr {Built-in Constant} NA\n\ -Missing value.\n\ - at end defvr"); - - DEFCONST (NaN, lo_ieee_nan_value (), - NAN_DOC_STRING); - -#if defined (M_E) - double e_val = M_E; -#else - double e_val = exp (1.0); -#endif - - DEFCONST (e, e_val, - "-*- texinfo -*-\n\ - at defvr {Built-in Constant} e\n\ -The base of natural logarithms. The constant\n\ - at iftex\n\ - at tex\n\ - $e$\n\ - at end tex\n\ - at end iftex\n\ - at ifinfo\n\ - at var{e}\n\ - at end ifinfo\n\ - satisfies the equation\n\ - at iftex\n\ - at tex\n\ - $\\log (e) = 1$.\n\ - at end tex\n\ - at end iftex\n\ - at ifinfo\n\ - at code{log} (@var{e}) = 1.\n\ - at end ifinfo\n\ - at end defvr"); - - DEFCONST (eps, DBL_EPSILON, - "-*- texinfo -*-\n\ - at defvr {Built-in Constant} eps\n\ -The machine precision. More precisely, at code{eps} is the largest\n\ -relative spacing between any two adjacent numbers in the machine's\n\ -floating point system. This number is obviously system-dependent. On\n\ -machines that support 64 bit IEEE floating point arithmetic, at code{eps}\n\ -is approximately\n\ - at ifinfo\n\ - 2.2204e-16.\n\ - at end ifinfo\n\ - at iftex\n\ - at tex\n\ - $2.2204\\times10^{-16}$.\n\ - at end tex\n\ - at end iftex\n\ - at end defvr"); - - DEFCONST (false, false, - "-*- texinfo -*-\n\ - at defvr {Built-in Constant} false\n\ -Logical false value.\n\ - at seealso{true}\n\ - at end defvr"); - - DEFCONST (i, Complex (0.0, 1.0), - IMAGINARY_DOC_STRING); - - DEFCONST (inf, lo_ieee_inf_value (), - INFINITY_DOC_STRING); - - DEFCONST (j, Complex (0.0, 1.0), - IMAGINARY_DOC_STRING); - - DEFCONST (nan, lo_ieee_nan_value (), - NAN_DOC_STRING); - -#if defined (M_PI) - double pi_val = M_PI; -#else - double pi_val = 4.0 * atan (1.0); -#endif - - DEFCONST (pi, pi_val, - "-*- texinfo -*-\n\ - at defvr {Built-in Constant} pi\n\ -The ratio of the circumference of a circle to its diameter.\n\ -Internally, at code{pi} is computed as @samp{4.0 * atan (1.0)}.\n\ - at end defvr"); - - DEFCONST (realmax, DBL_MAX, - "-*- texinfo -*-\n\ - at defvr {Built-in Constant} realmax\n\ -The largest floating point number that is representable. The actual\n\ -value is system-dependent. On machines that support 64-bit IEEE\n\ -floating point arithmetic, at code{realmax} is approximately\n\ - at ifinfo\n\ - 1.7977e+308\n\ - at end ifinfo\n\ - at iftex\n\ - at seealso{realmin}\n\ - at tex\n\ - $1.7977\\times10^{308}$.\n\ - at end tex\n\ - at end iftex\n\ - at end defvr"); - - DEFCONST (realmin, DBL_MIN, - "-*- texinfo -*-\n\ - at defvr {Built-in Constant} realmin\n\ -The smallest normalized floating point number that is representable.\n\ -The actual value is system-dependent. On machines that support\n\ -64-bit IEEE floating point arithmetic, at code{realmin} is approximately\n\ - at ifinfo\n\ - 2.2251e-308\n\ - at end ifinfo\n\ - at iftex\n\ - at tex\n\ - $2.2251\\times10^{-308}$.\n\ - at end tex\n\ - at end iftex\n\ - at seealso{realmax}\n\ - at end defvr"); - - DEFCONST (true, true, - "-*- texinfo -*-\n\ - at defvr {Built-in Constant} true\n\ -Logical true value.\n\ - at seealso{false}\n\ - at end defvr"); - -} - /* ;;; Local Variables: *** ;;; mode: C++ *** ------------------------------------------------------------- Octave is freely available under the terms of the GNU GPL. Octave's home on the web: http://www.octave.org How to fund new projects: http://www.octave.org/funding.html Subscription information: http://www.octave.org/archive.html -------------------------------------------------------------