Hi,
In the current behaviour of xstrtod:
Condition RET *RESULT errno
-----------------------------------------------------------------------------
conversion error: no number parsed false 0.0
EINVAL or 0
PTR == NULL, number parsed but junk after number false value 0
NaN true NaN 0
±Infinity true ±HUGE_VAL 0
overflow false ±HUGE_VAL ERANGE
gradual underflow [!MSVC] false near zero ERANGE
gradual underflow [MSVC] true near zero 0
flush-to-zero underflow true ±0.0 ERANGE
other finite value true value 0
the behaviour upon gradual underflow does not make sense to me:
* It is platform-dependent: on MSVC gradual underflow is seen as "normal"
or successful, on other platforms as an error.
* On platforms other than MSVC:
1.0 -> ret = true, *result = 1.0
1e-320 -> ret = false, *result = 1e-320 (approx.)
1e-500 -> ret = true, *result = 0.0
That is, a reduced accuracy of the result (in gradual underflow) is
reported as a failure, but a completely removed accuracy of the result
(in flush-to-zero underflow) is reported as success.
I propose to change the gradual underflow behaviour of xstrtod so that the
above table becomes:
Condition RET *RESULT errno
-----------------------------------------------------------------------------
conversion error: no number parsed false 0.0
EINVAL or 0
PTR == NULL, number parsed but junk after number false value 0
NaN true NaN 0
±Infinity true ±HUGE_VAL 0
overflow false ±HUGE_VAL ERANGE
gradual underflow true near zero 0
flush-to-zero underflow true ±0.0 ERANGE
other finite value true value 0
and similarly for xstrtold.
coreutils' 'sleep' and 'timeout' would be unaffected, because they treat
overflow
and underflow as success anyway:
xstrtod (argv[i], &p, &s, cl_strtod) || errno == ERANGE
The effect on coreutils' 'tail' would be that in
$ tail -f -s 1.0 /dev/null
<succeeds>
$ tail -f -s 0.000001 /dev/null
<succeeds>
$ tail -f -s 1e-300 /dev/null
<succeeds>
$ tail -f -s 1e-320 /dev/null
tail: invalid number of seconds: ‘1e-320’
$ tail -f -s 1e-400 /dev/null
<succeeds>
the error in the 1e-320 case goes away. That is, that 1e-320 behaves like
1e-300 and 1e-400.
Objections?
-------------------------------------------------------------------
I do *not* propose to change the *overflow* behaviour, because I think
that overflow handling should better be handled by the caller.
$ tail -f -s 1e300 /dev/null
<succeeds>
$ tail -f -s 1e500 /dev/null
tail: invalid number of seconds: ‘1e500’
$ tail -f -s infinity /dev/null
<succeeds>
Here, the caller should probably test isfinite() of the result, or use
|| errno == ERANGE
like the other two programs.
Bruno