Mercurial > octave-nkf
diff src/DLD-FUNCTIONS/str2double.cc @ 10356:1d7930b77ab9
implement compiled str2double
author | Jaroslav Hajek <highegg@gmail.com> |
---|---|
date | Wed, 24 Feb 2010 21:42:22 +0100 |
parents | |
children | 7658cd4bdcf2 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/DLD-FUNCTIONS/str2double.cc Wed Feb 24 21:42:22 2010 +0100 @@ -0,0 +1,212 @@ +/* + +Copyright (C) 2010 Jaroslav Hajek +Copyright (C) 2010 VZLU Prague + +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 +<http://www.gnu.org/licenses/>. + +*/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <string> +#include <cctype> +#include <sstream> +#include <algorithm> + +#include "lo-ieee.h" + +#include "Cell.h" +#include "ov.h" +#include "defun-dld.h" +#include "gripes.h" +#include "utils.h" + +static inline bool +is_imag_unit (int c) +{ return c == 'i' || c == 'j' || c == 'I' || c == 'J'; } + +static std::istringstream& +extract_num (std::istringstream& is, double& num, bool& imag, bool& have_sign) +{ + if (is.eof ()) + return is; + have_sign = imag = false; + + char c = is.peek (); + bool negative = false; + + // Accept leading sign. + if (c == '+' || c == '-') + { + negative = c == '-'; + is.get (); + c = is.peek (); + have_sign = true; + } + + if (is_imag_unit (c)) + { + is.get (); + // It's i*num or just i. + imag = true; + if (is.peek () == '*') + { + // Multiplier follows, we extract it as a number. + is.get (); + is >> num; + } + else + num = 1.0; + } + else + { + is >> num; + if (is.good ()) + { + c = is.peek (); + if (c == '*') + { + is.get (); + c = is.get (); + if (is_imag_unit (c)) + imag = true; + else + is.setstate (std::ios::failbit); // indicate that read has failed. + } + else if (is_imag_unit (c)) + imag = true; + } + } + + if (negative) + num = -num; + + return is; +} + +static Complex +str2double1 (std::string str) +{ + Complex val (0.0, 0.0); + std::string::iterator se = str.end (); + // Remove commas (thousand separators) and spaces. + se = std::remove (str.begin (), se, ','); + se = std::remove (str.begin (), se, ' '); + str.erase (se, str.end ()); + + std::istringstream is (str); + double num; + bool i1, i2, s1, s2; + + if (! extract_num (is, num, i1, s1)) + val = octave_NaN; + else + { + if (i1) + val.imag () = num; + else + val.real () = num; + + if (! is.eof ()) + { + if (! extract_num (is, num, i2, s2) || i1 == i2 || ! s2) + val = octave_NaN; + else + { + if (i2) + val.imag () = num; + else + val.real () = num; + } + } + } + + return val; +} + +DEFUN_DLD (str2double, args, , + "-*- texinfo -*-\n\ +@deftypefn {Built-in Function} {} str2double (@var{s})\n\ +Converts a string to real or complex number.\n\ +A complex number should be in one of the formats:\n\ +\n\ +@itemize\n\ +@item a + bi\n\ +@item a + b*i\n\ +@item a + i*b\n\ +@item bi + a\n\ +@item b*i + a\n\ +@item i*b + a\n\ +@end itemize\n\ +\n\ +It is also possible to use @code{j} instead of @code{i}, or write just\n\ +@code{i} instead of @code{1*i}.\n\ +@code{a} and @code{b} should be real numbers\n\ +in a standard format.\n\ +@var{s} can also be a character matrix, in which case the conversion is repeated\n\ +for each row, or a cell array of strings, in which case each element is converted\n\ +and an array of the same dimensions is returned.\n\ +@end deftypefn") +{ + octave_value retval; + + if (args.length () == 1) + { + if (args(0).is_string ()) + { + if (args(0).rows () == 1 && args(0).ndims () == 2) + { + retval = str2double1 (args(0).string_value ()); + } + else + { + const string_vector sv = args(0).all_strings (); + if (! error_state) + retval = sv.map<Complex> (str2double1); + } + } + else if (args(0).is_cellstr ()) + { + Array<std::string> sa = args(0).cellstr_value (); + retval = sa.map<Complex> (str2double1); + } + else + gripe_wrong_type_arg ("str2double", args(0)); + } + else + print_usage (); + + return retval; +} + +/* + +%!assert (str2double ("1"), 1) +%!assert (str2double ("-.1e-5"), -1e-6) +%!assert (str2double ("1,222.5"), 1222.5) +%!assert (str2double ("i"), i) +%!assert (str2double ("2 + j"), 2+j) +%!assert (str2double ("i*2 + 3"), 3+2i) +%!assert (str2double (".5*i + 3.5"), 3.5+0.5i) +%!assert (str2double ("1e-3 + i*.25"), 1e-3 + i*.25) +%!assert (str2double (["2 + j";"1.25e-3";"-05"]), [2+i; 1.25e-3; -05]) +%!assert (str2double ({"2 + j","1.25e-3","-05"}), [2+i, 1.25e-3, -05]) + +*/