source: mainline/uspace/lib/posix/stdlib/strtold.c@ fc3680e

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since fc3680e was ec18957a, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 14 years ago

Added errno.h (see commentary inside).

  • Property mode set to 100644
File size: 12.1 KB
Line 
1/*
2 * Copyright (c) 2011 Jiri Zarevucky
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup libposix
30 * @{
31 */
32/** @file
33 */
34
35#define LIBPOSIX_INTERNAL
36
37/* Must be first. */
38#include "../stdbool.h"
39
40#include "../internal/common.h"
41#include "../stdlib.h"
42
43#include "../assert.h"
44#include "../ctype.h"
45#include "../stdint.h"
46#include "../strings.h"
47#include "../errno.h"
48
49#ifndef HUGE_VALL
50 #define HUGE_VALL (+1.0l / +0.0l)
51#endif
52
53#ifndef abs
54 #define abs(x) ((x < 0) ? -x : x)
55#endif
56
57// TODO: clean up, documentation
58
59// FIXME: ensure it builds and works on all platforms
60
61const int max_small_pow5 = 15;
62
63/* The value at index i is approximately 5**i. */
64long double small_pow5[] = {
65 0x1P0,
66 0x5P0,
67 0x19P0,
68 0x7dP0,
69 0x271P0,
70 0xc35P0,
71 0x3d09P0,
72 0x1312dP0,
73 0x5f5e1P0,
74 0x1dcd65P0,
75 0x9502f9P0,
76 0x2e90eddP0,
77 0xe8d4a51P0,
78 0x48c27395P0,
79 0x16bcc41e9P0,
80 0x71afd498dP0
81};
82
83/* The value at index i is approximately 5**(2**i). */
84long double large_pow5[] = {
85 0x5P0l,
86 0x19P0l,
87 0x271P0l,
88 0x5f5e1P0l,
89 0x2386f26fc1P0l,
90 0x4ee2d6d415b85acef81P0l,
91 0x184f03e93ff9f4daa797ed6e38ed64bf6a1f01P0l,
92 0x24ee91f2603a6337f19bccdb0dac404dc08d3cff5ecP128l,
93 0x553f75fdcefcef46eeddcP512l,
94 0x1c633415d4c1d238d98cab8a978a0b1f138cb07303P1024l,
95 0x325d9d61a05d4305d9434f4a3c62d433949ae6209d492P2200l,
96 0x9e8b3b5dc53d5de4a74d28ce329ace526a3197bbebe3034f77154ce2bcba1964P4500l,
97 0x6230290145104bcd64a60a9fc025254932bb0fd922271133eeae7P9300l
98};
99
100/* Powers of two. */
101long double pow2[] = {
102 0x1P1l,
103 0x1P2l,
104 0x1P4l,
105 0x1P8l,
106 0x1P16l,
107 0x1P32l,
108 0x1P64l,
109 0x1P128l,
110 0x1P256l,
111 0x1P512l,
112 0x1P1024l,
113 0x1P2048l,
114 0x1P4096l,
115 0x1P8192l
116};
117
118static inline bool out_of_range(long double num)
119{
120 return num == 0.0l || num == HUGE_VALL;
121}
122
123/**
124 * Multiplies a number by a power of five.
125 * The result is not exact and may not be the best possible approximation.
126 *
127 * @param base Number to be multiplied.
128 * @param exponent Base 5 exponent.
129 * @return base multiplied by 5**exponent
130 */
131static long double mul_pow5(long double base, int exponent)
132{
133 if (out_of_range(base)) {
134 return base;
135 }
136
137 if (abs(exponent) >> 13 != 0) {
138 errno = ERANGE;
139 return exponent < 0 ? 0.0l : HUGE_VALL;
140 }
141
142 if (exponent < 0) {
143 exponent = -exponent;
144 base /= small_pow5[exponent & 0xF];
145 for (int i = 4; i < 13; ++i) {
146 if (((exponent >> i) & 1) != 0) {
147 base /= large_pow5[i];
148 if (out_of_range(base)) {
149 errno = ERANGE;
150 break;
151 }
152 }
153 }
154 } else {
155 base *= small_pow5[exponent & 0xF];
156 for (int i = 4; i < 13; ++i) {
157 if (((exponent >> i) & 1) != 0) {
158 base *= large_pow5[i];
159 if (out_of_range(base)) {
160 errno = ERANGE;
161 break;
162 }
163 }
164 }
165 }
166
167 return base;
168}
169
170/**
171 * Multiplies a number by a power of two.
172 *
173 * @param base Number to be multiplied.
174 * @param exponent Base 2 exponent.
175 * @return base multiplied by 2**exponent
176 */
177static long double mul_pow2(long double base, int exponent)
178{
179 if (out_of_range(base)) {
180 return base;
181 }
182
183 if (abs(exponent) >> 14 != 0) {
184 errno = ERANGE;
185 return exponent < 0 ? 0.0l : HUGE_VALL;
186 }
187
188 if (exponent < 0) {
189 exponent = -exponent;
190 for (int i = 0; i < 14; ++i) {
191 if (((exponent >> i) & 1) != 0) {
192 base /= pow2[i];
193 if (out_of_range(base)) {
194 errno = ERANGE;
195 break;
196 }
197 }
198 }
199 } else {
200 for (int i = 0; i < 14; ++i) {
201 if (((exponent >> i) & 1) != 0) {
202 base *= pow2[i];
203 if (out_of_range(base)) {
204 errno = ERANGE;
205 break;
206 }
207 }
208 }
209 }
210
211 return base;
212}
213
214
215static long double parse_decimal(const char **sptr)
216{
217 // TODO: Use strtol(), at least for exponent.
218
219 const int DEC_BASE = 10;
220 const char DECIMAL_POINT = '.';
221 const char EXPONENT_MARK = 'e';
222 /* The highest amount of digits that can be safely parsed
223 * before an overflow occurs.
224 */
225 const int PARSE_DECIMAL_DIGS = 19;
226
227 /* significand */
228 uint64_t significand = 0;
229
230 /* position in the input string */
231 int i = 0;
232
233 /* number of digits parsed so far */
234 int parsed_digits = 0;
235
236 int exponent = 0;
237
238 const char *str = *sptr;
239
240 /* digits before decimal point */
241 while (isdigit(str[i])) {
242 if (parsed_digits == 0 && str[i] == '0') {
243 /* Nothing, just skip leading zeros. */
244 } else if (parsed_digits < PARSE_DECIMAL_DIGS) {
245 significand *= DEC_BASE;
246 significand += str[i] - '0';
247 parsed_digits++;
248 } else {
249 exponent++;
250 }
251
252 i++;
253 }
254
255 if (str[i] == DECIMAL_POINT) {
256 i++;
257
258 /* digits after decimal point */
259 while (isdigit(str[i])) {
260 if (parsed_digits == 0 && str[i] == '0') {
261 /* Skip leading zeros and decrement exponent. */
262 exponent--;
263 } else if (parsed_digits < PARSE_DECIMAL_DIGS) {
264 significand *= DEC_BASE;
265 significand += str[i] - '0';
266 exponent--;
267 parsed_digits++;
268 } else {
269 /* ignore */
270 }
271
272 i++;
273 }
274 }
275
276 /* exponent */
277 if (tolower(str[i]) == EXPONENT_MARK) {
278 i++;
279
280 bool negative = false;
281 int exp = 0;
282
283 switch (str[i]) {
284 case '-':
285 negative = true;
286 /* fallthrough */
287 case '+':
288 i++;
289 }
290
291 while (isdigit(str[i])) {
292 if (exp < 65536) {
293 exp *= DEC_BASE;
294 exp += str[i] - '0';
295 }
296
297 i++;
298 }
299
300 if (negative) {
301 exp = -exp;
302 }
303
304 exponent += exp;
305 }
306
307 long double result = (long double) significand;
308 result = mul_pow5(result, exponent);
309 if (result != HUGE_VALL) {
310 result = mul_pow2(result, exponent);
311 }
312
313 *sptr = &str[i];
314 return result;
315}
316
317static inline int hex_value(char ch)
318{
319 if (ch <= '9') {
320 return ch - '0';
321 } else {
322 return 10 + tolower(ch) - 'a';
323 }
324}
325
326/**
327 * @param val Integer value.
328 * @return How many leading zero bits there are. (Maximum is 3)
329 */
330static inline int leading_zeros(uint64_t val)
331{
332 for (int i = 3; i > 0; --i) {
333 if ((val >> (64 - i)) == 0) {
334 return i;
335 }
336 }
337
338 return 0;
339}
340
341static long double parse_hexadecimal(const char **sptr)
342{
343 // TODO: Use strtol(), at least for exponent.
344
345 /* this function currently always rounds to zero */
346 // TODO: honor rounding mode
347
348 const int DEC_BASE = 10;
349 const int HEX_BASE = 16;
350 const char DECIMAL_POINT = '.';
351 const char EXPONENT_MARK = 'p';
352 /* The highest amount of digits that can be safely parsed
353 * before an overflow occurs.
354 */
355 const int PARSE_HEX_DIGS = 16;
356
357 /* significand */
358 uint64_t significand = 0;
359
360 /* position in the input string */
361 int i = 0;
362
363 /* number of digits parsed so far */
364 int parsed_digits = 0;
365
366 int exponent = 0;
367
368 const char *str = *sptr;
369
370 /* digits before decimal point */
371 while (posix_isxdigit(str[i])) {
372 if (parsed_digits == 0 && str[i] == '0') {
373 /* Nothing, just skip leading zeros. */
374 } else if (parsed_digits < PARSE_HEX_DIGS) {
375 significand *= HEX_BASE;
376 significand += hex_value(str[i]);
377 parsed_digits++;
378 } else if (parsed_digits == PARSE_HEX_DIGS) {
379 /* The first digit may have had leading zeros,
380 * so we need to parse one more digit and shift
381 * the value accordingly.
382 */
383
384 int zeros = leading_zeros(significand);
385 significand = (significand << zeros) |
386 (hex_value(str[i]) >> (4 - zeros));
387
388 exponent += (4 - zeros);
389 parsed_digits++;
390 } else {
391 exponent += 4;
392 }
393
394 i++;
395 }
396
397 if (str[i] == DECIMAL_POINT) {
398 i++;
399
400 /* digits after decimal point */
401 while (posix_isxdigit(str[i])) {
402 if (parsed_digits == 0 && str[i] == '0') {
403 /* Skip leading zeros and decrement exponent. */
404 exponent -= 4;
405 } else if (parsed_digits < PARSE_HEX_DIGS) {
406 significand *= HEX_BASE;
407 significand += hex_value(str[i]);
408 exponent -= 4;
409 parsed_digits++;
410 } else if (parsed_digits == PARSE_HEX_DIGS) {
411 /* The first digit may have had leading zeros,
412 * so we need to parse one more digit and shift
413 * the value accordingly.
414 */
415
416 int zeros = leading_zeros(significand);
417 significand = (significand << zeros) |
418 (hex_value(str[i]) >> (4 - zeros));
419
420 exponent -= zeros;
421 parsed_digits++;
422 } else {
423 /* ignore */
424 }
425
426 i++;
427 }
428 }
429
430 /* exponent */
431 if (tolower(str[i]) == EXPONENT_MARK) {
432 i++;
433
434 bool negative = false;
435 int exp = 0;
436
437 switch (str[i]) {
438 case '-':
439 negative = true;
440 /* fallthrough */
441 case '+':
442 i++;
443 }
444
445 while (isdigit(str[i])) {
446 if (exp < 65536) {
447 exp *= DEC_BASE;
448 exp += str[i] - '0';
449 }
450
451 i++;
452 }
453
454 if (negative) {
455 exp = -exp;
456 }
457
458 exponent += exp;
459 }
460
461 long double result = (long double) significand;
462 result = mul_pow2(result, exponent);
463
464 *sptr = &str[i];
465 return result;
466}
467
468/**
469 * Converts a string representation of a floating-point number to
470 * its native representation. Largely POSIX compliant, except for
471 * locale differences (always uses '.' at the moment) and rounding.
472 * Decimal strings are NOT guaranteed to be correctly rounded. This function
473 * should return a good enough approximation for most purposes but if you
474 * depend on a precise conversion, use hexadecimal representation.
475 * Hexadecimal strings are currently always rounded towards zero, regardless
476 * of the current rounding mode.
477 *
478 * @param nptr Input string.
479 * @param endptr If non-NULL, *endptr is set to the position of the first
480 * unrecognized character.
481 * @return An approximate representation of the input floating-point number.
482 */
483long double posix_strtold(const char *restrict nptr, char **restrict endptr)
484{
485 assert(nptr != NULL);
486
487 const int RADIX = '.';
488
489 /* minus sign */
490 bool negative = false;
491 /* current position in the string */
492 int i = 0;
493
494 /* skip whitespace */
495 while (isspace(nptr[i])) {
496 i++;
497 }
498
499 /* parse sign */
500 switch (nptr[i]) {
501 case '-':
502 negative = true;
503 /* fallthrough */
504 case '+':
505 i++;
506 }
507
508 /* check for NaN */
509 if (posix_strncasecmp(&nptr[i], "nan", 3) == 0) {
510 // FIXME: return NaN
511 // TODO: handle the parenthesised case
512
513 if (endptr != NULL) {
514 *endptr = (char *) &nptr[i + 3];
515 }
516 errno = ERANGE;
517 return negative ? -0.0l : +0.0l;
518 }
519
520 /* check for Infinity */
521 if (posix_strncasecmp(&nptr[i], "inf", 3) == 0) {
522 i += 3;
523 if (posix_strncasecmp(&nptr[i], "inity", 5) == 0) {
524 i += 5;
525 }
526
527 if (endptr != NULL) {
528 *endptr = (char *) &nptr[i];
529 }
530 return negative ? -HUGE_VALL : +HUGE_VALL;
531 }
532
533 /* check for a hex number */
534 if (nptr[i] == '0' && tolower(nptr[i + 1]) == 'x' &&
535 (posix_isxdigit(nptr[i + 2]) ||
536 (nptr[i + 2] == RADIX && posix_isxdigit(nptr[i + 3])))) {
537 i += 2;
538
539 const char *ptr = &nptr[i];
540 /* this call sets errno if appropriate. */
541 long double result = parse_hexadecimal(&ptr);
542 if (endptr != NULL) {
543 *endptr = (char *) ptr;
544 }
545 return negative ? -result : result;
546 }
547
548 /* check for a decimal number */
549 if (isdigit(nptr[i]) || (nptr[i] == RADIX && isdigit(nptr[i + 1]))) {
550 const char *ptr = &nptr[i];
551 /* this call sets errno if appropriate. */
552 long double result = parse_decimal(&ptr);
553 if (endptr != NULL) {
554 *endptr = (char *) ptr;
555 }
556 return negative ? -result : result;
557 }
558
559 /* nothing to parse */
560 if (endptr != NULL) {
561 *endptr = (char *) nptr;
562 }
563 errno = EINVAL;
564 return 0;
565}
566
567/** @}
568 */
569
Note: See TracBrowser for help on using the repository browser.