@@ -211,18 +211,21 @@ naive_strtold(const char *buf)
211
211
{
212
212
long double v = 0.0L ;
213
213
long exp = 0 ;
214
- long double frac_mul = 1.0L / 16.0L ;
214
+ long double frac_mul ;
215
215
long exp_sign = 1 ;
216
+ long double base = 10.0L ;
216
217
char c ;
217
218
enum {
218
219
LDOUBLE_INT ,
219
220
LDOUBLE_FRAC ,
220
221
LDOUBLE_EXP ,
221
222
} state = LDOUBLE_INT ;
222
223
223
- if (strncmp (buf , "0x" , 2 ) != 0 )
224
- return - (long double )INFINITY ;
225
- buf += 2 ;
224
+ if (strncmp (buf , "0x" , 2 ) == 0 ) {
225
+ base = 16.0L ;
226
+ buf += 2 ;
227
+ }
228
+ frac_mul = 1.0L / base ;
226
229
while ((c = * buf ++ )) {
227
230
int digit ;
228
231
switch (c ) {
@@ -233,9 +236,11 @@ naive_strtold(const char *buf)
233
236
}
234
237
return - (long double )INFINITY ;
235
238
case 'p' :
236
- if (state == LDOUBLE_INT || state == LDOUBLE_FRAC ) {
237
- state = LDOUBLE_EXP ;
238
- continue ;
239
+ if (base == 16.0L ) {
240
+ if (state == LDOUBLE_INT || state == LDOUBLE_FRAC ) {
241
+ state = LDOUBLE_EXP ;
242
+ continue ;
243
+ }
239
244
}
240
245
return - (long double )INFINITY ;
241
246
case '-' :
@@ -254,15 +259,41 @@ naive_strtold(const char *buf)
254
259
case '5' : case '6' : case '7' : case '8' : case '9' :
255
260
digit = c - '0' ;
256
261
break ;
262
+ case 'E' :
263
+ if (base == 10.0L ) {
264
+ if (state == LDOUBLE_INT || state == LDOUBLE_FRAC ) {
265
+ state = LDOUBLE_EXP ;
266
+ continue ;
267
+ }
268
+ return - (long double )INFINITY ;
269
+ }
270
+ /* FALLTHROUGH */
271
+ if (base == 10.0L ) {
272
+ if (state == LDOUBLE_INT || state == LDOUBLE_FRAC ) {
273
+ state = LDOUBLE_EXP ;
274
+ continue ;
275
+ }
276
+ return - (long double )INFINITY ;
277
+ }
278
+ /* FALLTHROUGH */
257
279
case 'A' : case 'B' : case 'C' :
258
- case 'D' : case 'E' : case ' F' :
280
+ case 'D' : case 'F' :
259
281
if (state == LDOUBLE_INT || state == LDOUBLE_FRAC ) {
260
282
digit = c - 'A' + 10 ;
261
283
break ;
262
284
}
263
285
return - (long double )INFINITY ;
286
+ case 'e' :
287
+ if (base == 10.0L ) {
288
+ if (state == LDOUBLE_INT || state == LDOUBLE_FRAC ) {
289
+ state = LDOUBLE_EXP ;
290
+ continue ;
291
+ }
292
+ return - (long double )INFINITY ;
293
+ }
294
+ /* FALLTHROUGH */
264
295
case 'a' : case 'b' : case 'c' :
265
- case 'd' : case 'e' : case ' f' :
296
+ case 'd' : case 'f' :
266
297
if (state == LDOUBLE_INT || state == LDOUBLE_FRAC ) {
267
298
digit = c - 'a' + 10 ;
268
299
break ;
@@ -273,62 +304,150 @@ naive_strtold(const char *buf)
273
304
}
274
305
switch (state ) {
275
306
case LDOUBLE_INT :
276
- v = v * 16.0L + digit ;
307
+ v = v * base + digit ;
277
308
break ;
278
309
case LDOUBLE_FRAC :
279
310
v = v + digit * frac_mul ;
280
- frac_mul *= 1.0L / 16.0L ;
311
+ frac_mul *= 1.0L / base ;
281
312
break ;
282
313
case LDOUBLE_EXP :
283
314
exp = exp * 10 + digit ;
284
315
break ;
285
316
}
286
317
}
287
- return ldexpl (v , exp * exp_sign );
318
+ if (base == 10.0L ) {
319
+ long etop = exp / 2 ;
320
+ long ebot = exp - etop ;
321
+ long double epow_top = powl (10.0L , etop * exp_sign );
322
+ long double epow_bot = powl (10.0L , ebot * exp_sign );
323
+ long double vpow = v * epow_top ;
324
+ long double r = vpow * epow_bot ;
325
+ return r ;
326
+ } else
327
+ return ldexpl (v , exp * exp_sign );
328
+ }
329
+
330
+ static const char * formats [] = { "%La" , "%.30Le" , };
331
+
332
+ #define NFMTS (sizeof (formats)/sizeof(formats[0]))
333
+
334
+ static bool
335
+ close (long double have , long double want , long double max_error )
336
+ {
337
+ if (have == want )
338
+ return true;
339
+
340
+ if (max_error == 0.0L )
341
+ return false;
342
+
343
+ if (want == 0.0L )
344
+ return fabsl (have ) <= max_error ;
345
+ return fabsl ((have - want ) / want ) <= max_error ;
288
346
}
289
347
348
+ static const int test_exp [] = {
349
+ __LDBL_MIN_EXP__ - __LDBL_MANT_DIG__ - 1 ,
350
+ __LDBL_MIN_EXP__ - __LDBL_MANT_DIG__ ,
351
+ __LDBL_MIN_EXP__ - __LDBL_MANT_DIG__ + 1 ,
352
+ __LDBL_MIN_EXP__ - __LDBL_MANT_DIG__ + 2 ,
353
+ __LDBL_MIN_EXP__ - __LDBL_MANT_DIG__ + 3 ,
354
+ __LDBL_MIN_EXP__ - 3 ,
355
+ __LDBL_MIN_EXP__ - 2 ,
356
+ __LDBL_MIN_EXP__ - 1 ,
357
+ __LDBL_MIN_EXP__ ,
358
+ __LDBL_MIN_EXP__ + 1 ,
359
+ __LDBL_MIN_EXP__ + 2 ,
360
+ __LDBL_MIN_EXP__ + 3 ,
361
+ -3 ,
362
+ -2 ,
363
+ -1 ,
364
+ 0 ,
365
+ 1 ,
366
+ 2 ,
367
+ 3 ,
368
+ __LDBL_MAX_EXP__ - 3 ,
369
+ __LDBL_MAX_EXP__ - 2 ,
370
+ __LDBL_MAX_EXP__ - 1 ,
371
+ __LDBL_MAX_EXP__ ,
372
+ __LDBL_MAX_EXP__ + 1 ,
373
+ };
374
+
375
+ #define NEXPS (sizeof (test_exp)/ sizeof(test_exp[0]))
376
+
377
+ /*
378
+ * For 64-bit values, we may have exact conversions. Otherwise, allow
379
+ * some error
380
+ */
381
+ #ifdef _IO_FLOAT_EXACT
382
+ # if __SIZEOF_LONG_DOUBLE__ == 8
383
+ # define MAX_DECIMAL_ERROR 0
384
+ # else
385
+ # define MAX_DECIMAL_ERROR 1e-10L
386
+ # endif
387
+ #else
388
+ # if __SIZEOF_LONG_DOUBLE__ == 8
389
+ # define MAX_DECIMAL_ERROR 1e-5L
390
+ # else
391
+ # define MAX_DECIMAL_ERROR 1e-10L
392
+ # endif
393
+ #endif
394
+
290
395
static int
291
396
test_io (void )
292
397
{
293
- int e ;
398
+ unsigned e ;
294
399
int result = 0 ;
295
400
char buf [80 ];
296
- unsigned i ;
401
+ unsigned i , j ;
402
+ long double max_error , max_error_naive ;
297
403
char * end ;
298
404
299
- for (e = __LDBL_MIN_EXP__ - __LDBL_MANT_DIG__ ; e <= __LDBL_MAX_EXP__ ; e ++ )
405
+ for (e = 0 ; e < NEXPS ; e ++ )
300
406
{
301
- long double v , r ;
302
407
for (i = 0 ; i < NVALS ; i ++ ) {
303
- v = ldexpl (vals [i ], e );
304
- sprintf (buf , "%La" , v );
305
- if (isinf (v )) {
306
- if (strcmp (buf , "inf" ) != 0 ) {
307
- printf ("test_io i %d val %La exp %d: is %s should be inf\n" , i , vals [i ], e , buf );
308
- result ++ ;
408
+
409
+ long double v , r ;
410
+ v = ldexpl (vals [i ], test_exp [e ]);
411
+
412
+ for (j = 0 ; j < NFMTS ; j ++ ) {
413
+
414
+ if (j == 0 ) {
415
+ max_error = 0 ;
416
+ max_error_naive = 0 ;
417
+ } else {
418
+ max_error = MAX_DECIMAL_ERROR ;
419
+ max_error_naive = 1e-6L ;
309
420
}
310
- } else if (isnan (v )) {
311
- if (strcmp (buf , "nan" ) != 0 ) {
312
- printf ("test_io is %s should be nan\n" , buf );
421
+
422
+ sprintf (buf , formats [j ], v );
423
+ if (isinf (v )) {
424
+ if (strcmp (buf , "inf" ) != 0 ) {
425
+ printf ("test_io i %d val %La exp %d: is %s should be inf\n" , i , vals [i ], test_exp [e ], buf );
426
+ result ++ ;
427
+ }
428
+ } else if (isnan (v )) {
429
+ if (strcmp (buf , "nan" ) != 0 ) {
430
+ printf ("test_io is %s should be nan\n" , buf );
431
+ result ++ ;
432
+ }
433
+ } else {
434
+ r = naive_strtold (buf );
435
+ if (!close (r , v , max_error_naive )) {
436
+ printf ("test_io naive i %d val %La exp %d: \"%s\", is %La should be %La\n" , i , vals [i ], test_exp [e ], buf , r , v );
437
+ result ++ ;
438
+ }
439
+ }
440
+ sscanf (buf , "%Lf" , & r );
441
+ if (!close (r , v , max_error ) && !(isnan (v ) && isnan (r ))) {
442
+ printf ("test_io scanf i %d val %La exp %d: \"%s\", is %La should be %La\n" , i , vals [i ], test_exp [e ], buf , r , v );
313
443
result ++ ;
314
444
}
315
- } else {
316
- r = naive_strtold (buf );
317
- if (v != r ) {
318
- printf ("test_io naive i %d val %La exp %d: \"%s\", is %La should be %La\n" , i , vals [i ], e , buf , r , v );
445
+ r = strtold (buf , & end );
446
+ if ((!close (r , v , max_error ) && !(isnan (v ) && isnan (r )))|| end != buf + strlen (buf )) {
447
+ printf ("test_io strtold i %d val %La exp %d: \"%s\", is %La should be %La\n" , i , vals [i ], test_exp [e ], buf , r , v );
319
448
result ++ ;
320
449
}
321
450
}
322
- sscanf (buf , "%Lf" , & r );
323
- if (v != r && !(isnan (v ) && isnan (r ))) {
324
- printf ("test_io scanf i %d val %La exp %d: \"%s\", is %La should be %La\n" , i , vals [i ], e , buf , r , v );
325
- result ++ ;
326
- }
327
- r = strtold (buf , & end );
328
- if ((v != r && !(isnan (v ) && isnan (r )))|| end != buf + strlen (buf )) {
329
- printf ("test_io strtold i %d val %La exp %d: \"%s\", is %La should be %La\n" , i , vals [i ], e , buf , r , v );
330
- result ++ ;
331
- }
332
451
}
333
452
}
334
453
return result ;
0 commit comments