|
6 | 6 | /* San Jose, California */ |
7 | 7 | /* */ |
8 | 8 | /************************************************************************/ |
| 9 | + |
| 10 | +#include <stdbool.h> |
| 11 | +#include <stdint.h> |
9 | 12 | #include <stdlib.h> |
10 | 13 | #include <ctype.h> |
11 | 14 | #include <stdio.h> |
|
14 | 17 | #include <math.h> |
15 | 18 | #include <errno.h> |
16 | 19 |
|
| 20 | +typedef union F32_pun { |
| 21 | + float flt; |
| 22 | + uint32_t bin; |
| 23 | +} F32_pun; |
| 24 | + |
17 | 25 | /************************************************* |
18 | 26 | * |
19 | 27 | * strtod - string to double conversion |
|
27 | 35 | * the value of the number |
28 | 36 | * |
29 | 37 | *************************************************/ |
30 | | -float _strtof_c(const char *__restrict nptr, |
31 | | - char **__restrict endptr) |
| 38 | + |
| 39 | +/** |
| 40 | + * @remarks `*str >= '0' && *str <= '9'` is smaller than calls to `isdigit(*str)` |
| 41 | + * @todo Add support for INF INFINITY NAN NAN(...) |
| 42 | + */ |
| 43 | +float _strtof_c(const char *__restrict nptr, char **__restrict endptr) |
32 | 44 | { |
33 | | - union |
34 | | - { |
35 | | - float d; |
36 | | - unsigned short s[2]; |
37 | | - }val; |
38 | | - int frac = 0; |
39 | | - int exp = 0; |
40 | | - signed char sign = 1; |
41 | | - signed char exp_sign = 1; |
42 | | - char *str = (char*)nptr; |
| 45 | + F32_pun val; |
| 46 | + int frac = 0; |
| 47 | + int exp = 0; |
| 48 | + bool sign = false; |
| 49 | + bool exp_sign = false; |
| 50 | + char *str = (char*)nptr; |
43 | 51 |
|
44 | | - while (isspace(*str)) |
45 | | - ++str; |
| 52 | + while (isspace(*str)) { |
| 53 | + ++str; |
| 54 | + } |
46 | 55 |
|
47 | | - if (*str == '-') { |
48 | | - sign = -1; |
49 | | - ++str; |
50 | | - } |
51 | | - else if (*str == '+') |
52 | | - ++str; |
| 56 | + if (*str == '-') { |
| 57 | + sign = true; |
| 58 | + ++str; |
| 59 | + } else if (*str == '+') { |
| 60 | + ++str; |
| 61 | + } |
53 | 62 |
|
54 | | - val.d = 0; |
55 | | - while (*str >= '0' && *str <= '9') { |
56 | | - val.d = val.d * 10 + (*str - '0'); |
57 | | - ++str; |
58 | | - } |
| 63 | + val.flt = 0.0f; |
59 | 64 |
|
60 | | - if (*str == '.') { |
61 | | - ++str; |
62 | 65 | while (*str >= '0' && *str <= '9') { |
63 | | - val.d = val.d * 10 + (*str - '0'); |
64 | | - ++frac; |
65 | | - ++str; |
| 66 | + val.flt = val.flt * 10.0f + (float)(*str - '0'); |
| 67 | + ++str; |
66 | 68 | } |
67 | | - } |
68 | 69 |
|
69 | | - if (*str == 'e' || *str == 'E') { |
70 | | - ++str; |
71 | | - if (*str == '-') { |
72 | | - exp_sign = -1; |
73 | | - ++str; |
| 70 | + if (*str == '.') { |
| 71 | + ++str; |
| 72 | + while (*str >= '0' && *str <= '9') { |
| 73 | + val.flt = val.flt * 10.0f + (float)(*str - '0'); |
| 74 | + ++frac; |
| 75 | + ++str; |
| 76 | + } |
74 | 77 | } |
75 | | - else if (*str == '+') { |
76 | | - exp_sign = 1; |
77 | | - ++str; |
78 | | - } |
79 | | - while (*str >= '0' && *str <= '9') { |
80 | | - exp = exp * 10 + (*str - '0'); |
81 | | - ++str; |
| 78 | + |
| 79 | + if (*str == 'e' || *str == 'E') { |
| 80 | + ++str; |
| 81 | + if (*str == '-') { |
| 82 | + exp_sign = true; |
| 83 | + ++str; |
| 84 | + } else if (*str == '+') { |
| 85 | + exp_sign = false; |
| 86 | + ++str; |
| 87 | + } |
| 88 | + while (*str >= '0' && *str <= '9') { |
| 89 | + exp = exp * 10 + (*str - '0'); |
| 90 | + ++str; |
| 91 | + } |
82 | 92 | } |
83 | | - } |
84 | 93 |
|
85 | | - if (endptr) |
86 | | - *endptr = (char*)str; |
| 94 | + if (endptr) { |
| 95 | + *endptr = (char*)str; |
| 96 | + } |
87 | 97 |
|
88 | | - if (exp_sign < 0 ) |
89 | | - exp = -exp; |
90 | | - exp -= frac; |
91 | | - if (val.d != 0) |
92 | | - { |
93 | | - while (exp > 0 ) |
94 | | - { |
95 | | - val.d *= 10.0; |
96 | | - if (val.s[1] == 0x7f80) |
97 | | - { |
98 | | - errno = ERANGE; |
99 | | - val.d = HUGE_VAL; |
100 | | - break; |
101 | | - } |
102 | | - --exp; |
| 98 | + if (exp_sign) { |
| 99 | + exp = -exp; |
103 | 100 | } |
104 | | - while (exp < 0 ) |
| 101 | + exp -= frac; |
| 102 | + if (val.bin != 0) |
105 | 103 | { |
106 | | - val.d *= .1; |
107 | | - if (val.s[1] == 0) |
108 | | - { |
109 | | - errno = ERANGE; |
110 | | - break; |
111 | | - } |
112 | | - ++exp; |
| 104 | + while (exp > 0 ) |
| 105 | + { |
| 106 | + val.flt *= 10.0f; |
| 107 | + if (!isfinite(val.flt)) |
| 108 | + { |
| 109 | + errno = ERANGE; |
| 110 | + val.flt = HUGE_VALF; |
| 111 | + break; |
| 112 | + } |
| 113 | + --exp; |
| 114 | + } |
| 115 | + while (exp < 0 ) |
| 116 | + { |
| 117 | + val.flt /= 10.0f; |
| 118 | + if (val.bin == 0) |
| 119 | + { |
| 120 | + errno = ERANGE; |
| 121 | + break; |
| 122 | + } |
| 123 | + ++exp; |
| 124 | + } |
| 125 | + } |
| 126 | + if (sign) { |
| 127 | + val.flt = -val.flt; |
113 | 128 | } |
114 | | - if (sign < 0 ) |
115 | | - val.s[1] |= 0x8000; |
116 | | - } |
117 | | - return val.d; |
| 129 | + return val.flt; |
118 | 130 | } |
119 | 131 |
|
120 | 132 | double _strtod_c(const char *, char **) __attribute__((alias("_strtof_c"))); |
0 commit comments