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
RevLine 
[63fc519]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 */
[087c8798]32/** @file Backend for floating point conversions.
[63fc519]33 */
34
35#include "../internal/common.h"
[3e6a98c5]36#include "libc/stdbool.h"
[a3da2b2]37#include "posix/stdlib.h"
[63fc519]38
[e8d3c6f5]39#include <assert.h>
[a3da2b2]40#include "posix/ctype.h"
41#include "posix/stdint.h"
42#include "posix/strings.h"
[0d0b319]43
44#include <errno.h>
45
[a3da2b2]46#include "posix/limits.h"
[d43c117]47
[a3da2b2]48#include "posix/float.h"
[63fc519]49
[1d6dd2a]50#include "libc/str.h"
51
[63fc519]52#ifndef HUGE_VALL
53 #define HUGE_VALL (+1.0l / +0.0l)
54#endif
55
56#ifndef abs
[d43c117]57 #define abs(x) (((x) < 0) ? -(x) : (x))
[63fc519]58#endif
59
[d43c117]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
[63fc519]76
[d43c117]77/* power functions ************************************************************/
[63fc519]78
[d43c117]79#if LDBL_MAX_EXP >= 16384
80const int MAX_POW5 = 12;
81#else
82const int MAX_POW5 = 8;
83#endif
[63fc519]84
85/* The value at index i is approximately 5**(2**i). */
[d43c117]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
[63fc519]102};
103
[d43c117]104#if LDBL_MAX_EXP >= 16384
105const int MAX_POW2 = 15;
106#else
107const int MAX_POW2 = 9;
108#endif
109
[63fc519]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,
[d43c117]122#if LDBL_MAX_EXP >= 16384
[63fc519]123 0x1P1024l,
124 0x1P2048l,
125 0x1P4096l,
[d43c117]126 0x1P8192l,
127#endif
[63fc519]128};
129
130/**
131 * Multiplies a number by a power of five.
[d43c117]132 * The result may be inexact and may not be the best possible approximation.
[63fc519]133 *
[d43c117]134 * @param mant Number to be multiplied.
135 * @param exp Base 5 exponent.
136 * @return mant multiplied by 5**exp
[63fc519]137 */
[d43c117]138static long double mul_pow5(long double mant, int exp)
[63fc519]139{
[d43c117]140 if (mant == 0.0l || mant == HUGE_VALL) {
141 return mant;
[63fc519]142 }
[a35b458]143
[d43c117]144 if (abs(exp) >> (MAX_POW5 + 1) != 0) {
145 /* Too large exponent. */
[63fc519]146 errno = ERANGE;
[d43c117]147 return exp < 0 ? LDBL_MIN : HUGE_VALL;
[63fc519]148 }
[a35b458]149
[d43c117]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;
[63fc519]159 errno = ERANGE;
160 break;
161 }
162 }
163 }
164 } else {
[d43c117]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. */
[63fc519]171 errno = ERANGE;
172 break;
173 }
174 }
175 }
176 }
[a35b458]177
[d43c117]178 return mant;
[63fc519]179}
180
181/**
[d43c117]182 * Multiplies a number by a power of two. This is always exact.
[63fc519]183 *
[d43c117]184 * @param mant Number to be multiplied.
185 * @param exp Base 2 exponent.
186 * @return mant multiplied by 2**exp.
[63fc519]187 */
[d43c117]188static long double mul_pow2(long double mant, int exp)
[63fc519]189{
[d43c117]190 if (mant == 0.0l || mant == HUGE_VALL) {
191 return mant;
[63fc519]192 }
[a35b458]193
[d43c117]194 if (exp > LDBL_MAX_EXP || exp < LDBL_MIN_EXP) {
[63fc519]195 errno = ERANGE;
[d43c117]196 return exp < 0 ? LDBL_MIN : HUGE_VALL;
[63fc519]197 }
[a35b458]198
[d43c117]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;
[63fc519]206 errno = ERANGE;
207 break;
208 }
209 }
210 }
211 } else {
[d43c117]212 for (int i = 0; i <= MAX_POW2; ++i) {
213 if (((exp >> i) & 1) != 0) {
214 mant *= pow2[i];
215 if (mant == HUGE_VALL) {
[63fc519]216 errno = ERANGE;
217 break;
218 }
219 }
220 }
221 }
[a35b458]222
[d43c117]223 return mant;
[63fc519]224}
225
[d43c117]226/* end power functions ********************************************************/
227
228
229
[087c8798]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).
[1b20da0]234 *
[087c8798]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 */
[63fc519]240static long double parse_decimal(const char **sptr)
241{
[d43c117]242 assert(sptr != NULL);
243 assert (*sptr != NULL);
[a35b458]244
[63fc519]245 const int DEC_BASE = 10;
246 const char DECIMAL_POINT = '.';
247 const char EXPONENT_MARK = 'e';
[a35b458]248
[d43c117]249 const char *str = *sptr;
250 long double significand = 0;
251 long exponent = 0;
[a35b458]252
[63fc519]253 /* number of digits parsed so far */
254 int parsed_digits = 0;
[d43c117]255 bool after_decimal = false;
[a35b458]256
[d43c117]257 while (isdigit(*str) || (!after_decimal && *str == DECIMAL_POINT)) {
258 if (*str == DECIMAL_POINT) {
259 after_decimal = true;
260 str++;
261 continue;
262 }
[a35b458]263
[d43c117]264 if (parsed_digits == 0 && *str == '0') {
[5ee9692]265 /* Nothing, just skip leading zeros. */
[d43c117]266 } else if (parsed_digits < LDBL_DIG) {
267 significand = significand * DEC_BASE + (*str - '0');
[63fc519]268 parsed_digits++;
269 } else {
270 exponent++;
271 }
[a35b458]272
[d43c117]273 if (after_decimal) {
274 /* Decrement exponent if we are parsing the fractional part. */
275 exponent--;
[63fc519]276 }
[a35b458]277
[d43c117]278 str++;
[63fc519]279 }
[a35b458]280
[63fc519]281 /* exponent */
[d43c117]282 if (tolower(*str) == EXPONENT_MARK) {
283 str++;
[a35b458]284
[d43c117]285 /* Returns MIN/MAX value on error, which is ok. */
286 long exp = strtol(str, (char **) &str, DEC_BASE);
[a35b458]287
[d43c117]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;
[63fc519]294 }
295 }
[a35b458]296
[d43c117]297 *sptr = str;
[a35b458]298
[d43c117]299 /* Return multiplied by a power of ten. */
300 return mul_pow2(mul_pow5(significand, exponent), exponent);
[63fc519]301}
302
[087c8798]303/**
304 * Derive a hexadecimal digit from its character representation.
[1b20da0]305 *
[087c8798]306 * @param ch Character representation of the hexadecimal digit.
307 * @return Digit value represented by an integer.
308 */
[5ee9692]309static inline int hex_value(char ch)
310{
[63fc519]311 if (ch <= '9') {
312 return ch - '0';
313 } else {
314 return 10 + tolower(ch) - 'a';
315 }
316}
317
[087c8798]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 */
[63fc519]329static long double parse_hexadecimal(const char **sptr)
330{
[d43c117]331 assert(sptr != NULL && *sptr != NULL);
[a35b458]332
[63fc519]333 const int DEC_BASE = 10;
334 const int HEX_BASE = 16;
335 const char DECIMAL_POINT = '.';
336 const char EXPONENT_MARK = 'p';
[a35b458]337
[63fc519]338 const char *str = *sptr;
[d43c117]339 long double significand = 0;
340 long exponent = 0;
[a35b458]341
[d43c117]342 /* number of bits parsed so far */
343 int parsed_bits = 0;
344 bool after_decimal = false;
[a35b458]345
[dbbbe75b]346 while (isxdigit(*str) || (!after_decimal && *str == DECIMAL_POINT)) {
[d43c117]347 if (*str == DECIMAL_POINT) {
348 after_decimal = true;
349 str++;
350 continue;
351 }
[a35b458]352
[d43c117]353 if (parsed_bits == 0 && *str == '0') {
[5ee9692]354 /* Nothing, just skip leading zeros. */
[d43c117]355 } else if (parsed_bits <= LDBL_MANT_DIG) {
356 significand = significand * HEX_BASE + hex_value(*str);
357 parsed_bits += 4;
[63fc519]358 } else {
359 exponent += 4;
360 }
[a35b458]361
[d43c117]362 if (after_decimal) {
363 exponent -= 4;
[63fc519]364 }
[a35b458]365
[d43c117]366 str++;
[63fc519]367 }
[a35b458]368
[63fc519]369 /* exponent */
[d43c117]370 if (tolower(*str) == EXPONENT_MARK) {
371 str++;
[a35b458]372
[d43c117]373 /* Returns MIN/MAX value on error, which is ok. */
374 long exp = strtol(str, (char **) &str, DEC_BASE);
[a35b458]375
[d43c117]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;
[63fc519]382 }
383 }
[a35b458]384
[d43c117]385 *sptr = str;
[a35b458]386
[d43c117]387 /* Return multiplied by a power of two. */
388 return mul_pow2(significand, exponent);
[63fc519]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
[4cf8ca6]403 * unrecognized character.
[63fc519]404 * @return An approximate representation of the input floating-point number.
405 */
[7f9df7b9]406long double strtold(const char *restrict nptr, char **restrict endptr)
[63fc519]407{
408 assert(nptr != NULL);
[a35b458]409
[63fc519]410 const int RADIX = '.';
[a35b458]411
[63fc519]412 /* minus sign */
413 bool negative = false;
414 /* current position in the string */
415 int i = 0;
[a35b458]416
[63fc519]417 /* skip whitespace */
418 while (isspace(nptr[i])) {
419 i++;
420 }
[a35b458]421
[63fc519]422 /* parse sign */
423 switch (nptr[i]) {
424 case '-':
425 negative = true;
[dc12262]426 /* Fallthrough */
[63fc519]427 case '+':
428 i++;
429 }
[a35b458]430
[63fc519]431 /* check for NaN */
[7f9df7b9]432 if (strncasecmp(&nptr[i], "nan", 3) == 0) {
[63fc519]433 // FIXME: return NaN
434 // TODO: handle the parenthesised case
[a35b458]435
[63fc519]436 if (endptr != NULL) {
[102a729]437 *endptr = (char *) nptr;
[63fc519]438 }
[102a729]439 errno = EINVAL;
440 return 0;
[63fc519]441 }
[a35b458]442
[63fc519]443 /* check for Infinity */
[7f9df7b9]444 if (strncasecmp(&nptr[i], "inf", 3) == 0) {
[63fc519]445 i += 3;
[7f9df7b9]446 if (strncasecmp(&nptr[i], "inity", 5) == 0) {
[63fc519]447 i += 5;
448 }
[a35b458]449
[63fc519]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' &&
[dbbbe75b]458 (isxdigit(nptr[i + 2]) ||
459 (nptr[i + 2] == RADIX && isxdigit(nptr[i + 3])))) {
[63fc519]460 i += 2;
[a35b458]461
[63fc519]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 }
[a35b458]470
[63fc519]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 }
[a35b458]481
[63fc519]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.