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

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

style: Remove trailing whitespace on _all_ lines, including empty ones, for particular file types.

Command used: tools/srepl '\s\+$' '' -- *.c *.h *.py *.sh *.s *.S *.ag

Currently, whitespace on empty lines is very inconsistent.
There are two basic choices: Either remove the whitespace, or keep empty lines
indented to the level of surrounding code. The former is AFAICT more common,
and also much easier to do automatically.

Alternatively, we could write script for automatic indentation, and use that
instead. However, if such a script exists, it's possible to use the indented
style locally, by having the editor apply relevant conversions on load/save,
without affecting remote repository. IMO, it makes more sense to adopt
the simpler rule.

  • Property mode set to 100644
File size: 11.4 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 Backend for floating point conversions.
33 */
34
35#include "../internal/common.h"
36#include "libc/stdbool.h"
37#include "posix/stdlib.h"
38
39#include <assert.h>
40#include "posix/ctype.h"
41#include "posix/stdint.h"
42#include "posix/strings.h"
43
44#include <errno.h>
45
46#include "posix/limits.h"
47
48#include "posix/float.h"
49
50#include "libc/str.h"
51
52#ifndef HUGE_VALL
53 #define HUGE_VALL (+1.0l / +0.0l)
54#endif
55
56#ifndef abs
57 #define abs(x) (((x) < 0) ? -(x) : (x))
58#endif
59
60/* If the constants are not defined, use double precision as default. */
61#ifndef LDBL_MANT_DIG
62 #define LDBL_MANT_DIG 53
63#endif
64#ifndef LDBL_MAX_EXP
65 #define LDBL_MAX_EXP 1024
66#endif
67#ifndef LDBL_MIN_EXP
68 #define LDBL_MIN_EXP (-1021)
69#endif
70#ifndef LDBL_DIG
71 #define LDBL_DIG 15
72#endif
73#ifndef LDBL_MIN
74 #define LDBL_MIN 2.2250738585072014E-308
75#endif
76
77/* power functions ************************************************************/
78
79#if LDBL_MAX_EXP >= 16384
80const int MAX_POW5 = 12;
81#else
82const int MAX_POW5 = 8;
83#endif
84
85/* The value at index i is approximately 5**(2**i). */
86long double pow5[] = {
87 0x5p0l,
88 0x19p0l,
89 0x271p0l,
90 0x5F5E1p0l,
91 0x2386F26FC1p0l,
92 0x4EE2D6D415B85ACEF81p0l,
93 0x184F03E93FF9F4DAA797ED6E38ED6p36l,
94 0x127748F9301D319BF8CDE66D86D62p185l,
95 0x154FDD7F73BF3BD1BBB77203731FDp482l,
96#if LDBL_MAX_EXP >= 16384
97 0x1C633415D4C1D238D98CAB8A978A0p1076l,
98 0x192ECEB0D02EA182ECA1A7A51E316p2265l,
99 0x13D1676BB8A7ABBC94E9A519C6535p4643l,
100 0x188C0A40514412F3592982A7F0094p9398l,
101#endif
102};
103
104#if LDBL_MAX_EXP >= 16384
105const int MAX_POW2 = 15;
106#else
107const int MAX_POW2 = 9;
108#endif
109
110/* Powers of two. */
111long double pow2[] = {
112 0x1P1l,
113 0x1P2l,
114 0x1P4l,
115 0x1P8l,
116 0x1P16l,
117 0x1P32l,
118 0x1P64l,
119 0x1P128l,
120 0x1P256l,
121 0x1P512l,
122#if LDBL_MAX_EXP >= 16384
123 0x1P1024l,
124 0x1P2048l,
125 0x1P4096l,
126 0x1P8192l,
127#endif
128};
129
130/**
131 * Multiplies a number by a power of five.
132 * The result may be inexact and may not be the best possible approximation.
133 *
134 * @param mant Number to be multiplied.
135 * @param exp Base 5 exponent.
136 * @return mant multiplied by 5**exp
137 */
138static long double mul_pow5(long double mant, int exp)
139{
140 if (mant == 0.0l || mant == HUGE_VALL) {
141 return mant;
142 }
143
144 if (abs(exp) >> (MAX_POW5 + 1) != 0) {
145 /* Too large exponent. */
146 errno = ERANGE;
147 return exp < 0 ? LDBL_MIN : HUGE_VALL;
148 }
149
150 if (exp < 0) {
151 exp = abs(exp);
152 for (int bit = 0; bit <= MAX_POW5; ++bit) {
153 /* Multiply by powers of five bit-by-bit. */
154 if (((exp >> bit) & 1) != 0) {
155 mant /= pow5[bit];
156 if (mant == 0.0l) {
157 /* Underflow. */
158 mant = LDBL_MIN;
159 errno = ERANGE;
160 break;
161 }
162 }
163 }
164 } else {
165 for (int bit = 0; bit <= MAX_POW5; ++bit) {
166 /* Multiply by powers of five bit-by-bit. */
167 if (((exp >> bit) & 1) != 0) {
168 mant *= pow5[bit];
169 if (mant == HUGE_VALL) {
170 /* Overflow. */
171 errno = ERANGE;
172 break;
173 }
174 }
175 }
176 }
177
178 return mant;
179}
180
181/**
182 * Multiplies a number by a power of two. This is always exact.
183 *
184 * @param mant Number to be multiplied.
185 * @param exp Base 2 exponent.
186 * @return mant multiplied by 2**exp.
187 */
188static long double mul_pow2(long double mant, int exp)
189{
190 if (mant == 0.0l || mant == HUGE_VALL) {
191 return mant;
192 }
193
194 if (exp > LDBL_MAX_EXP || exp < LDBL_MIN_EXP) {
195 errno = ERANGE;
196 return exp < 0 ? LDBL_MIN : HUGE_VALL;
197 }
198
199 if (exp < 0) {
200 exp = abs(exp);
201 for (int i = 0; i <= MAX_POW2; ++i) {
202 if (((exp >> i) & 1) != 0) {
203 mant /= pow2[i];
204 if (mant == 0.0l) {
205 mant = LDBL_MIN;
206 errno = ERANGE;
207 break;
208 }
209 }
210 }
211 } else {
212 for (int i = 0; i <= MAX_POW2; ++i) {
213 if (((exp >> i) & 1) != 0) {
214 mant *= pow2[i];
215 if (mant == HUGE_VALL) {
216 errno = ERANGE;
217 break;
218 }
219 }
220 }
221 }
222
223 return mant;
224}
225
226/* end power functions ********************************************************/
227
228
229
230/**
231 * Convert decimal string representation of the floating point number.
232 * Function expects the string pointer to be already pointed at the first
233 * digit (i.e. leading optional sign was already consumed by the caller).
234 *
235 * @param sptr Pointer to the storage of the string pointer. Upon successful
236 * conversion, the string pointer is updated to point to the first
237 * unrecognized character.
238 * @return An approximate representation of the input floating-point number.
239 */
240static long double parse_decimal(const char **sptr)
241{
242 assert(sptr != NULL);
243 assert (*sptr != NULL);
244
245 const int DEC_BASE = 10;
246 const char DECIMAL_POINT = '.';
247 const char EXPONENT_MARK = 'e';
248
249 const char *str = *sptr;
250 long double significand = 0;
251 long exponent = 0;
252
253 /* number of digits parsed so far */
254 int parsed_digits = 0;
255 bool after_decimal = false;
256
257 while (isdigit(*str) || (!after_decimal && *str == DECIMAL_POINT)) {
258 if (*str == DECIMAL_POINT) {
259 after_decimal = true;
260 str++;
261 continue;
262 }
263
264 if (parsed_digits == 0 && *str == '0') {
265 /* Nothing, just skip leading zeros. */
266 } else if (parsed_digits < LDBL_DIG) {
267 significand = significand * DEC_BASE + (*str - '0');
268 parsed_digits++;
269 } else {
270 exponent++;
271 }
272
273 if (after_decimal) {
274 /* Decrement exponent if we are parsing the fractional part. */
275 exponent--;
276 }
277
278 str++;
279 }
280
281 /* exponent */
282 if (tolower(*str) == EXPONENT_MARK) {
283 str++;
284
285 /* Returns MIN/MAX value on error, which is ok. */
286 long exp = strtol(str, (char **) &str, DEC_BASE);
287
288 if (exponent > 0 && exp > LONG_MAX - exponent) {
289 exponent = LONG_MAX;
290 } else if (exponent < 0 && exp < LONG_MIN - exponent) {
291 exponent = LONG_MIN;
292 } else {
293 exponent += exp;
294 }
295 }
296
297 *sptr = str;
298
299 /* Return multiplied by a power of ten. */
300 return mul_pow2(mul_pow5(significand, exponent), exponent);
301}
302
303/**
304 * Derive a hexadecimal digit from its character representation.
305 *
306 * @param ch Character representation of the hexadecimal digit.
307 * @return Digit value represented by an integer.
308 */
309static inline int hex_value(char ch)
310{
311 if (ch <= '9') {
312 return ch - '0';
313 } else {
314 return 10 + tolower(ch) - 'a';
315 }
316}
317
318/**
319 * Convert hexadecimal string representation of the floating point number.
320 * Function expects the string pointer to be already pointed at the first
321 * digit (i.e. leading optional sign and 0x prefix were already consumed
322 * by the caller).
323 *
324 * @param sptr Pointer to the storage of the string pointer. Upon successful
325 * conversion, the string pointer is updated to point to the first
326 * unrecognized character.
327 * @return Representation of the input floating-point number.
328 */
329static long double parse_hexadecimal(const char **sptr)
330{
331 assert(sptr != NULL && *sptr != NULL);
332
333 const int DEC_BASE = 10;
334 const int HEX_BASE = 16;
335 const char DECIMAL_POINT = '.';
336 const char EXPONENT_MARK = 'p';
337
338 const char *str = *sptr;
339 long double significand = 0;
340 long exponent = 0;
341
342 /* number of bits parsed so far */
343 int parsed_bits = 0;
344 bool after_decimal = false;
345
346 while (isxdigit(*str) || (!after_decimal && *str == DECIMAL_POINT)) {
347 if (*str == DECIMAL_POINT) {
348 after_decimal = true;
349 str++;
350 continue;
351 }
352
353 if (parsed_bits == 0 && *str == '0') {
354 /* Nothing, just skip leading zeros. */
355 } else if (parsed_bits <= LDBL_MANT_DIG) {
356 significand = significand * HEX_BASE + hex_value(*str);
357 parsed_bits += 4;
358 } else {
359 exponent += 4;
360 }
361
362 if (after_decimal) {
363 exponent -= 4;
364 }
365
366 str++;
367 }
368
369 /* exponent */
370 if (tolower(*str) == EXPONENT_MARK) {
371 str++;
372
373 /* Returns MIN/MAX value on error, which is ok. */
374 long exp = strtol(str, (char **) &str, DEC_BASE);
375
376 if (exponent > 0 && exp > LONG_MAX - exponent) {
377 exponent = LONG_MAX;
378 } else if (exponent < 0 && exp < LONG_MIN - exponent) {
379 exponent = LONG_MIN;
380 } else {
381 exponent += exp;
382 }
383 }
384
385 *sptr = str;
386
387 /* Return multiplied by a power of two. */
388 return mul_pow2(significand, exponent);
389}
390
391/**
392 * Converts a string representation of a floating-point number to
393 * its native representation. Largely POSIX compliant, except for
394 * locale differences (always uses '.' at the moment) and rounding.
395 * Decimal strings are NOT guaranteed to be correctly rounded. This function
396 * should return a good enough approximation for most purposes but if you
397 * depend on a precise conversion, use hexadecimal representation.
398 * Hexadecimal strings are currently always rounded towards zero, regardless
399 * of the current rounding mode.
400 *
401 * @param nptr Input string.
402 * @param endptr If non-NULL, *endptr is set to the position of the first
403 * unrecognized character.
404 * @return An approximate representation of the input floating-point number.
405 */
406long double strtold(const char *restrict nptr, char **restrict endptr)
407{
408 assert(nptr != NULL);
409
410 const int RADIX = '.';
411
412 /* minus sign */
413 bool negative = false;
414 /* current position in the string */
415 int i = 0;
416
417 /* skip whitespace */
418 while (isspace(nptr[i])) {
419 i++;
420 }
421
422 /* parse sign */
423 switch (nptr[i]) {
424 case '-':
425 negative = true;
426 /* Fallthrough */
427 case '+':
428 i++;
429 }
430
431 /* check for NaN */
432 if (strncasecmp(&nptr[i], "nan", 3) == 0) {
433 // FIXME: return NaN
434 // TODO: handle the parenthesised case
435
436 if (endptr != NULL) {
437 *endptr = (char *) nptr;
438 }
439 errno = EINVAL;
440 return 0;
441 }
442
443 /* check for Infinity */
444 if (strncasecmp(&nptr[i], "inf", 3) == 0) {
445 i += 3;
446 if (strncasecmp(&nptr[i], "inity", 5) == 0) {
447 i += 5;
448 }
449
450 if (endptr != NULL) {
451 *endptr = (char *) &nptr[i];
452 }
453 return negative ? -HUGE_VALL : +HUGE_VALL;
454 }
455
456 /* check for a hex number */
457 if (nptr[i] == '0' && tolower(nptr[i + 1]) == 'x' &&
458 (isxdigit(nptr[i + 2]) ||
459 (nptr[i + 2] == RADIX && isxdigit(nptr[i + 3])))) {
460 i += 2;
461
462 const char *ptr = &nptr[i];
463 /* this call sets errno if appropriate. */
464 long double result = parse_hexadecimal(&ptr);
465 if (endptr != NULL) {
466 *endptr = (char *) ptr;
467 }
468 return negative ? -result : result;
469 }
470
471 /* check for a decimal number */
472 if (isdigit(nptr[i]) || (nptr[i] == RADIX && isdigit(nptr[i + 1]))) {
473 const char *ptr = &nptr[i];
474 /* this call sets errno if appropriate. */
475 long double result = parse_decimal(&ptr);
476 if (endptr != NULL) {
477 *endptr = (char *) ptr;
478 }
479 return negative ? -result : result;
480 }
481
482 /* nothing to parse */
483 if (endptr != NULL) {
484 *endptr = (char *) nptr;
485 }
486 errno = EINVAL;
487 return 0;
488}
489
490/** @}
491 */
Note: See TracBrowser for help on using the repository browser.