File: | libinterp/corefcn/str2double.cc |
Location: | line 97, column 3 |
Description: | Undefined or garbage value returned to caller |
1 | /* | |||
2 | ||||
3 | Copyright (C) 2010-2013 Jaroslav Hajek | |||
4 | Copyright (C) 2010 VZLU Prague | |||
5 | ||||
6 | This file is part of Octave. | |||
7 | ||||
8 | Octave is free software; you can redistribute it and/or modify it | |||
9 | under the terms of the GNU General Public License as published by the | |||
10 | Free Software Foundation; either version 3 of the License, or (at your | |||
11 | option) any later version. | |||
12 | ||||
13 | Octave is distributed in the hope that it will be useful, but WITHOUT | |||
14 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |||
15 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |||
16 | for more details. | |||
17 | ||||
18 | You should have received a copy of the GNU General Public License | |||
19 | along with Octave; see the file COPYING. If not, see | |||
20 | <http://www.gnu.org/licenses/>. | |||
21 | ||||
22 | */ | |||
23 | ||||
24 | #ifdef HAVE_CONFIG_H1 | |||
25 | #include <config.h> | |||
26 | #endif | |||
27 | ||||
28 | #include <string> | |||
29 | #include <cctype> | |||
30 | #include <sstream> | |||
31 | #include <algorithm> | |||
32 | ||||
33 | #include "lo-ieee.h" | |||
34 | ||||
35 | #include "Cell.h" | |||
36 | #include "ov.h" | |||
37 | #include "defun.h" | |||
38 | #include "gripes.h" | |||
39 | #include "utils.h" | |||
40 | ||||
41 | static inline bool | |||
42 | is_imag_unit (int c) | |||
43 | { return c == 'i' || c == 'j'; } | |||
44 | ||||
45 | static double | |||
46 | single_num (std::istringstream& is) | |||
47 | { | |||
48 | double num; | |||
49 | ||||
50 | char c = is.peek (); | |||
51 | ||||
52 | // Skip spaces. | |||
53 | while (isspace (c)) | |||
54 | { | |||
55 | is.get (); | |||
56 | c = is.peek (); | |||
57 | } | |||
58 | ||||
59 | if (std::toupper (c) == 'I') | |||
60 | { | |||
61 | // It's infinity. | |||
62 | is.get (); | |||
63 | char c1 = is.get (), c2 = is.get (); | |||
64 | if (std::tolower (c1) == 'n' && std::tolower (c2) == 'f') | |||
65 | { | |||
66 | num = octave_Inf; | |||
67 | is.peek (); // May set EOF bit. | |||
68 | } | |||
69 | else | |||
70 | is.setstate (std::ios::failbit); // indicate that read has failed. | |||
71 | } | |||
72 | else if (c == 'N') | |||
73 | { | |||
74 | // It's NA or NaN | |||
75 | is.get (); | |||
76 | char c1 = is.get (); | |||
77 | if (c1 == 'A') | |||
78 | { | |||
79 | num = octave_NA; | |||
80 | is.peek (); // May set EOF bit. | |||
81 | } | |||
82 | else | |||
83 | { | |||
84 | char c2 = is.get (); | |||
85 | if (c1 == 'a' && c2 == 'N') | |||
86 | { | |||
87 | num = octave_NaN; | |||
88 | is.peek (); // May set EOF bit. | |||
89 | } | |||
90 | else | |||
91 | is.setstate (std::ios::failbit); // indicate that read has failed. | |||
92 | } | |||
93 | } | |||
94 | else | |||
95 | is >> num; | |||
96 | ||||
97 | return num; | |||
| ||||
98 | } | |||
99 | ||||
100 | static std::istringstream& | |||
101 | extract_num (std::istringstream& is, double& num, bool& imag, bool& have_sign) | |||
102 | { | |||
103 | have_sign = imag = false; | |||
104 | ||||
105 | char c = is.peek (); | |||
106 | ||||
107 | // Skip leading spaces. | |||
108 | while (isspace (c)) | |||
| ||||
109 | { | |||
110 | is.get (); | |||
111 | c = is.peek (); | |||
112 | } | |||
113 | ||||
114 | bool negative = false; | |||
115 | ||||
116 | // Accept leading sign. | |||
117 | if (c == '+' || c == '-') | |||
118 | { | |||
119 | have_sign = true; | |||
120 | negative = c == '-'; | |||
121 | is.get (); | |||
122 | c = is.peek (); | |||
123 | } | |||
124 | ||||
125 | // Skip spaces after sign. | |||
126 | while (isspace (c)) | |||
127 | { | |||
128 | is.get (); | |||
129 | c = is.peek (); | |||
130 | } | |||
131 | ||||
132 | // Imaginary number (i*num or just i), or maybe 'inf'. | |||
133 | if (c == 'i') | |||
134 | { | |||
135 | // possible infinity. | |||
136 | is.get (); | |||
137 | c = is.peek (); | |||
138 | ||||
139 | if (is.eof ()) | |||
140 | { | |||
141 | // just 'i' and string is finished. Return immediately. | |||
142 | imag = true; | |||
143 | num = negative ? -1.0 : 1.0; | |||
144 | return is; | |||
145 | } | |||
146 | else | |||
147 | { | |||
148 | if (std::tolower (c) != 'n') | |||
149 | imag = true; | |||
150 | is.unget (); | |||
151 | } | |||
152 | } | |||
153 | else if (c == 'j') | |||
154 | imag = true; | |||
155 | ||||
156 | // It's i*num or just i | |||
157 | if (imag) | |||
158 | { | |||
159 | is.get (); | |||
160 | c = is.peek (); | |||
161 | // Skip spaces after imaginary unit. | |||
162 | while (isspace (c)) | |||
163 | { | |||
164 | is.get (); | |||
165 | c = is.peek (); | |||
166 | } | |||
167 | ||||
168 | if (c == '*') | |||
169 | { | |||
170 | // Multiplier follows, we extract it as a number. | |||
171 | is.get (); | |||
172 | num = single_num (is); | |||
173 | if (is.good ()) | |||
174 | c = is.peek (); | |||
175 | } | |||
176 | else | |||
177 | num = 1.0; | |||
178 | } | |||
179 | else | |||
180 | { | |||
181 | // It's num, num*i, or numi. | |||
182 | num = single_num (is); | |||
183 | if (is.good ()) | |||
184 | { | |||
185 | c = is.peek (); | |||
186 | ||||
187 | // Skip spaces after number. | |||
188 | while (isspace (c)) | |||
189 | { | |||
190 | is.get (); | |||
191 | c = is.peek (); | |||
192 | } | |||
193 | ||||
194 | if (c == '*') | |||
195 | { | |||
196 | is.get (); | |||
197 | c = is.peek (); | |||
198 | ||||
199 | // Skip spaces after operator. | |||
200 | while (isspace (c)) | |||
201 | { | |||
202 | is.get (); | |||
203 | c = is.peek (); | |||
204 | } | |||
205 | ||||
206 | if (is_imag_unit (c)) | |||
207 | { | |||
208 | imag = true; | |||
209 | is.get (); | |||
210 | c = is.peek (); | |||
211 | } | |||
212 | else | |||
213 | is.setstate (std::ios::failbit); // indicate read has failed. | |||
214 | } | |||
215 | else if (is_imag_unit (c)) | |||
216 | { | |||
217 | imag = true; | |||
218 | is.get (); | |||
219 | c = is.peek (); | |||
220 | } | |||
221 | } | |||
222 | } | |||
223 | ||||
224 | if (is.good ()) | |||
225 | { | |||
226 | // Skip trailing spaces. | |||
227 | while (isspace (c)) | |||
228 | { | |||
229 | is.get (); | |||
230 | c = is.peek (); | |||
231 | } | |||
232 | } | |||
233 | ||||
234 | if (negative) | |||
235 | num = -num; | |||
236 | ||||
237 | return is; | |||
238 | } | |||
239 | ||||
240 | static inline void | |||
241 | set_component (Complex& c, double num, bool imag) | |||
242 | { | |||
243 | #if defined (HAVE_CXX_COMPLEX_SETTERS1) | |||
244 | if (imag) | |||
245 | c.imag (num); | |||
246 | else | |||
247 | c.real (num); | |||
248 | #elif defined (HAVE_CXX_COMPLEX_REFERENCE_ACCESSORS1) | |||
249 | if (imag) | |||
250 | c.imag () = num; | |||
251 | else | |||
252 | c.real () = num; | |||
253 | #else | |||
254 | if (imag) | |||
255 | c = Complex (c.real (), num); | |||
256 | else | |||
257 | c = Complex (num, c.imag ()); | |||
258 | #endif | |||
259 | } | |||
260 | ||||
261 | static Complex | |||
262 | str2double1 (const std::string& str_arg) | |||
263 | { | |||
264 | Complex val (0.0, 0.0); | |||
265 | ||||
266 | std::string str = str_arg; | |||
267 | ||||
268 | // FIXME: removing all commas doesn't allow actual parsing. | |||
269 | // Example: "1,23.45" is wrong, but passes Octave. | |||
270 | str.erase (std::remove (str.begin (), str.end(), ','), str.end ()); | |||
271 | std::istringstream is (str); | |||
272 | ||||
273 | double num; | |||
274 | bool i1, i2, s1, s2; | |||
275 | ||||
276 | if (is.eof ()) | |||
277 | val = octave_NaN; | |||
278 | else if (! extract_num (is, num, i1, s1)) | |||
279 | val = octave_NaN; | |||
280 | else | |||
281 | { | |||
282 | set_component (val, num, i1); | |||
283 | ||||
284 | if (! is.eof ()) | |||
285 | { | |||
286 | if (! extract_num (is, num, i2, s2) || i1 == i2 || ! s2) | |||
287 | val = octave_NaN; | |||
288 | else | |||
289 | set_component (val, num, i2); | |||
290 | } | |||
291 | } | |||
292 | ||||
293 | return val; | |||
294 | } | |||
295 | ||||
296 | DEFUN (str2double, args, ,octave_value_list Fstr2double (const octave_value_list& args , int ) | |||
297 | "-*- texinfo -*-\n\octave_value_list Fstr2double (const octave_value_list& args , int ) | |||
298 | @deftypefn {Built-in Function} {} str2double (@var{s})\n\octave_value_list Fstr2double (const octave_value_list& args , int ) | |||
299 | Convert a string to a real or complex number.\n\octave_value_list Fstr2double (const octave_value_list& args , int ) | |||
300 | \n\octave_value_list Fstr2double (const octave_value_list& args , int ) | |||
301 | The string must be in one of the following formats where\n\octave_value_list Fstr2double (const octave_value_list& args , int ) | |||
302 | a and b are real numbers and the complex unit is @qcode{'i'} or @qcode{'j'}:\n\octave_value_list Fstr2double (const octave_value_list& args , int ) | |||
303 | \n\octave_value_list Fstr2double (const octave_value_list& args , int ) | |||
304 | @itemize\n\octave_value_list Fstr2double (const octave_value_list& args , int ) | |||
305 | @item a + bi\n\octave_value_list Fstr2double (const octave_value_list& args , int ) | |||
306 | \n\octave_value_list Fstr2double (const octave_value_list& args , int ) | |||
307 | @item a + b*i\n\octave_value_list Fstr2double (const octave_value_list& args , int ) | |||
308 | \n\octave_value_list Fstr2double (const octave_value_list& args , int ) | |||
309 | @item a + i*b\n\octave_value_list Fstr2double (const octave_value_list& args , int ) | |||
310 | \n\octave_value_list Fstr2double (const octave_value_list& args , int ) | |||
311 | @item bi + a\n\octave_value_list Fstr2double (const octave_value_list& args , int ) | |||
312 | \n\octave_value_list Fstr2double (const octave_value_list& args , int ) | |||
313 | @item b*i + a\n\octave_value_list Fstr2double (const octave_value_list& args , int ) | |||
314 | \n\octave_value_list Fstr2double (const octave_value_list& args , int ) | |||
315 | @item i*b + a\n\octave_value_list Fstr2double (const octave_value_list& args , int ) | |||
316 | @end itemize\n\octave_value_list Fstr2double (const octave_value_list& args , int ) | |||
317 | \n\octave_value_list Fstr2double (const octave_value_list& args , int ) | |||
318 | If present, a and/or b are of the form @nospell{[+-]d[,.]d[[eE][+-]d]} where\n\octave_value_list Fstr2double (const octave_value_list& args , int ) | |||
319 | the brackets indicate optional arguments and @qcode{'d'} indicates zero or\n\octave_value_list Fstr2double (const octave_value_list& args , int ) | |||
320 | more digits. The special input values @code{Inf}, @code{NaN}, and @code{NA}\n\octave_value_list Fstr2double (const octave_value_list& args , int ) | |||
321 | are also accepted.\n\octave_value_list Fstr2double (const octave_value_list& args , int ) | |||
322 | \n\octave_value_list Fstr2double (const octave_value_list& args , int ) | |||
323 | @var{s} may be a character string, character matrix, or cell array.\n\octave_value_list Fstr2double (const octave_value_list& args , int ) | |||
324 | For character arrays the conversion is repeated for every row, and\n\octave_value_list Fstr2double (const octave_value_list& args , int ) | |||
325 | a double or complex array is returned. Empty rows in @var{s} are deleted\n\octave_value_list Fstr2double (const octave_value_list& args , int ) | |||
326 | and not returned in the numeric array. For cell arrays each character\n\octave_value_list Fstr2double (const octave_value_list& args , int ) | |||
327 | string element is processed and a double or complex array of the same\n\octave_value_list Fstr2double (const octave_value_list& args , int ) | |||
328 | dimensions as @var{s} is returned.\n\octave_value_list Fstr2double (const octave_value_list& args , int ) | |||
329 | \n\octave_value_list Fstr2double (const octave_value_list& args , int ) | |||
330 | For unconvertible scalar or character string input @code{str2double} returns\n\octave_value_list Fstr2double (const octave_value_list& args , int ) | |||
331 | a NaN@. Similarly, for character array input @code{str2double} returns a\n\octave_value_list Fstr2double (const octave_value_list& args , int ) | |||
332 | NaN for any row of @var{s} that could not be converted. For a cell array,\n\octave_value_list Fstr2double (const octave_value_list& args , int ) | |||
333 | @code{str2double} returns a NaN for any element of @var{s} for which\n\octave_value_list Fstr2double (const octave_value_list& args , int ) | |||
334 | conversion fails. Note that numeric elements in a mixed string/numeric\n\octave_value_list Fstr2double (const octave_value_list& args , int ) | |||
335 | cell array are not strings and the conversion will fail for these elements\n\octave_value_list Fstr2double (const octave_value_list& args , int ) | |||
336 | and return NaN.\n\octave_value_list Fstr2double (const octave_value_list& args , int ) | |||
337 | \n\octave_value_list Fstr2double (const octave_value_list& args , int ) | |||
338 | @code{str2double} can replace @code{str2num}, and it avoids the security\n\octave_value_list Fstr2double (const octave_value_list& args , int ) | |||
339 | risk of using @code{eval} on unknown data.\n\octave_value_list Fstr2double (const octave_value_list& args , int ) | |||
340 | @seealso{str2num}\n\octave_value_list Fstr2double (const octave_value_list& args , int ) | |||
341 | @end deftypefn")octave_value_list Fstr2double (const octave_value_list& args , int ) | |||
342 | { | |||
343 | octave_value retval; | |||
344 | ||||
345 | if (args.length () != 1) | |||
346 | print_usage (); | |||
347 | else if (args(0).is_string ()) | |||
348 | { | |||
349 | if (args(0).rows () == 0 || args(0).columns () == 0) | |||
350 | { | |||
351 | retval = Matrix (1, 1, octave_NaN); | |||
352 | } | |||
353 | else if (args(0).rows () == 1 && args(0).ndims () == 2) | |||
354 | { | |||
355 | retval = str2double1 (args(0).string_value ()); | |||
356 | } | |||
357 | else | |||
358 | { | |||
359 | const string_vector sv = args(0).all_strings (); | |||
360 | if (! error_state) | |||
361 | retval = sv.map<Complex> (str2double1); | |||
362 | } | |||
363 | } | |||
364 | else if (args(0).is_cell ()) | |||
365 | { | |||
366 | const Cell cell = args(0).cell_value (); | |||
367 | ||||
368 | if (! error_state) | |||
369 | { | |||
370 | ComplexNDArray output (cell.dims (), octave_NaN); | |||
371 | for (octave_idx_type i = 0; i < cell.numel (); i++) | |||
372 | { | |||
373 | if (cell(i).is_string ()) | |||
374 | output(i) = str2double1 (cell(i).string_value ()); | |||
375 | } | |||
376 | retval = output; | |||
377 | } | |||
378 | } | |||
379 | else | |||
380 | retval = Matrix (1, 1, octave_NaN); | |||
381 | ||||
382 | ||||
383 | return retval; | |||
384 | } | |||
385 | ||||
386 | /* | |||
387 | %!assert (str2double ("1"), 1) | |||
388 | %!assert (str2double ("-.1e-5"), -1e-6) | |||
389 | %!assert (str2double (char ("1", "2 3", "4i")), [1; NaN; 4i]) | |||
390 | %!assert (str2double ("1,222.5"), 1222.5) | |||
391 | %!assert (str2double ("i"), i) | |||
392 | %!assert (str2double ("2j"), 2i) | |||
393 | %!assert (str2double ("2 + j"), 2+j) | |||
394 | %!assert (str2double ("i*2 + 3"), 3+2i) | |||
395 | %!assert (str2double (".5*i + 3.5"), 3.5+0.5i) | |||
396 | %!assert (str2double ("1e-3 + i*.25"), 1e-3 + 0.25i) | |||
397 | %!assert (str2double (["2 + j";"1.25e-3";"-05"]), [2+i; 1.25e-3; -5]) | |||
398 | %!assert (str2double ({"2 + j","1.25e-3","-05"}), [2+i, 1.25e-3, -5]) | |||
399 | %!assert (str2double (1), NaN) | |||
400 | %!assert (str2double ("1 2 3 4"), NaN) | |||
401 | %!assert (str2double ("Hello World"), NaN) | |||
402 | %!assert (str2double ("NaN"), NaN) | |||
403 | %!assert (str2double ("NA"), NA) | |||
404 | %!assert (str2double ("Inf"), Inf) | |||
405 | %!assert (str2double ("iNF"), Inf) | |||
406 | %!assert (str2double ("-Inf"), -Inf) | |||
407 | %!assert (str2double ("Inf*i"), complex (0, Inf)) | |||
408 | %!assert (str2double ("iNF*i"), complex (0, Inf)) | |||
409 | %!assert (str2double ("NaN + Inf*i"), complex (NaN, Inf)) | |||
410 | %!assert (str2double ("Inf - Inf*i"), complex (Inf, -Inf)) | |||
411 | %!assert (str2double ("-i*NaN - Inf"), complex (-Inf, -NaN)) | |||
412 | %!assert (str2double ({"abc", "4i"}), [NaN + 0i, 4i]) | |||
413 | %!assert (str2double ({2, "4i"}), [NaN + 0i, 4i]) | |||
414 | %!assert (str2double (zeros (3,1,2)), NaN) | |||
415 | %!assert (str2double (''), NaN) | |||
416 | %!assert (str2double ([]), NaN) | |||
417 | %!assert (str2double (char(zeros(3,0))), NaN) | |||
418 | */ |