@@ -105,6 +105,96 @@ static inline const char *bc_skip_zero_reverse(const char *scanner, const char *
105
105
return scanner ;
106
106
}
107
107
108
+ static bool bc_scientific_notation_str2num (
109
+ bc_num * num , const char * str , const char * end , const char * integer_ptr , const char * fractional_ptr , const char * exponent_ptr ,
110
+ size_t digits , size_t * full_scale )
111
+ {
112
+ const char * fractional_end = exponent_ptr ;
113
+
114
+ /* In scientific notation, the mantissa always has one integer digit. */
115
+ if (UNEXPECTED (digits != 1 )) {
116
+ goto fail ;
117
+ }
118
+
119
+ /* Must be 1 <= mantissa < 10 */
120
+ if (UNEXPECTED (* integer_ptr == 0 )) {
121
+ goto fail ;
122
+ }
123
+
124
+ if (UNEXPECTED (* exponent_ptr != 'e' && * exponent_ptr != 'E' )) {
125
+ goto fail ;
126
+ }
127
+ exponent_ptr ++ ;
128
+
129
+ sign exponent_sign = PLUS ;
130
+ if (* exponent_ptr == '+' ) {
131
+ /* Skip Sign */
132
+ exponent_ptr ++ ;
133
+ } else if (* exponent_ptr == '-' ) {
134
+ exponent_sign = MINUS ;
135
+ exponent_ptr ++ ;
136
+ }
137
+
138
+ /* Skip exponent leading zeros. This is rare, so don't do bulk processing. */
139
+ while (* exponent_ptr == '0' ) {
140
+ exponent_ptr ++ ;
141
+ }
142
+
143
+ const char * exponent_end = bc_count_digits (exponent_ptr , end );
144
+ if (UNEXPECTED (* exponent_end != '\0' )) {
145
+ /* invalid num */
146
+ goto fail ;
147
+ }
148
+
149
+ size_t exponent = 0 ;
150
+ while (exponent_ptr < exponent_end ) {
151
+ exponent = exponent * 10 + (* exponent_ptr - '0' ); /* TODO: check overflow */
152
+ exponent_ptr ++ ;
153
+ }
154
+
155
+ size_t str_scale = fractional_end - fractional_ptr ;
156
+
157
+ if (exponent_sign == PLUS ) {
158
+ digits += exponent ;
159
+ str_scale = str_scale > exponent ? str_scale - exponent : 0 ;
160
+
161
+ * num = bc_new_num_nonzeroed (digits , str_scale );
162
+ (* num )-> n_sign = * str == '-' ? MINUS : PLUS ;
163
+ char * nptr = (* num )-> n_value ;
164
+ char * nend = nptr + digits + str_scale ;
165
+
166
+ * nptr ++ = * integer_ptr - '0' ;
167
+ nptr = bc_copy_and_toggle_bcd (nptr , fractional_ptr , fractional_end );
168
+ while (nptr < nend ) {
169
+ * nptr ++ = 0 ;
170
+ }
171
+ } else {
172
+ digits = 0 ;
173
+ str_scale += exponent ;
174
+
175
+ * num = bc_new_num_nonzeroed (1 , str_scale ); // 1 is for 0
176
+ (* num )-> n_sign = * str == '-' ? MINUS : PLUS ;
177
+ char * nptr = (* num )-> n_value ;
178
+
179
+ for (size_t i = 0 ; i < exponent ; i ++ ) {
180
+ * nptr ++ = 0 ;
181
+ }
182
+
183
+ * nptr ++ = * integer_ptr - '0' ;
184
+ nptr = bc_copy_and_toggle_bcd (nptr , fractional_ptr , fractional_end );
185
+ }
186
+
187
+ if (full_scale ) {
188
+ * full_scale = str_scale ;
189
+ }
190
+
191
+ return true;
192
+
193
+ fail :
194
+ * num = bc_copy_num (BCG (_zero_ ));
195
+ return false;
196
+ }
197
+
108
198
/* Assumes `num` points to NULL, i.e. does yet not hold a number. */
109
199
bool bc_str2num (bc_num * num , const char * str , const char * end , size_t scale , size_t * full_scale , bool auto_scale )
110
200
{
@@ -151,9 +241,8 @@ bool bc_str2num(bc_num *num, const char *str, const char *end, size_t scale, siz
151
241
152
242
/* validate */
153
243
fractional_end = bc_count_digits (fractional_ptr , end );
154
- if (UNEXPECTED (* fractional_end != '\0' )) {
155
- /* invalid num */
156
- goto fail ;
244
+ if (* fractional_end != '\0' ) {
245
+ return bc_scientific_notation_str2num (num , str , end , integer_ptr , fractional_ptr , fractional_end , digits , full_scale );
157
246
}
158
247
159
248
if (full_scale ) {
0 commit comments