1 /*-------------------------------------------------------------------------
5 * Portions Copyright (c) 2019-2021, PostgreSQL Global Development Group
11 *-------------------------------------------------------------------------
21 * strtof() is part of C99; this version is only for the benefit of obsolete
22 * platforms. As such, it is known to return incorrect values for edge cases,
23 * which have to be allowed for in variant files for regression test results
24 * for any such platform.
28 strtof(const char *nptr
, char **endptr
)
30 int caller_errno
= errno
;
35 dresult
= strtod(nptr
, endptr
);
36 fresult
= (float) dresult
;
41 * Value might be in-range for double but not float.
43 if (dresult
!= 0 && fresult
== 0)
44 caller_errno
= ERANGE
; /* underflow */
45 if (!isinf(dresult
) && isinf(fresult
))
46 caller_errno
= ERANGE
; /* overflow */
55 #elif HAVE_BUGGY_STRTOF
57 * On Windows, there's a slightly different problem: VS2013 has a strtof()
58 * that returns the correct results for valid input, but may fail to report an
59 * error for underflow or overflow, returning 0 instead. Work around that by
60 * trying strtod() when strtof() returns 0.0 or [+-]Inf, and calling it an
61 * error if the result differs. Also, strtof() doesn't handle subnormal input
62 * well, so prefer to round the strtod() result in such cases. (Normally we'd
63 * just say "too bad" if strtof() doesn't support subnormals, but since we're
64 * already in here fixing stuff, we might as well do the best fix we can.)
66 * Cygwin has a strtof() which is literally just (float)strtod(), which means
67 * we can't avoid the double-rounding problem; but using this wrapper does get
68 * us proper over/underflow checks. (Also, if they fix their strtof(), the
69 * wrapper doesn't break anything.)
71 * Test results on Mingw suggest that it has the same problem, though looking
72 * at the code I can't figure out why.
75 pg_strtof(const char *nptr
, char **endptr
)
77 int caller_errno
= errno
;
81 fresult
= (strtof
) (nptr
, endptr
);
84 /* On error, just return the error to the caller. */
87 else if ((*endptr
== nptr
) || isnan(fresult
) ||
88 ((fresult
>= FLT_MIN
|| fresult
<= -FLT_MIN
) && !isinf(fresult
)))
91 * If we got nothing parseable, or if we got a non-0 non-subnormal
92 * finite value (or NaN) without error, then return that to the caller
101 * Try again. errno is already 0 here.
103 double dresult
= strtod(nptr
, NULL
);
107 /* On error, just return the error */
110 else if ((dresult
== 0.0 && fresult
== 0.0) ||
111 (isinf(dresult
) && isinf(fresult
) && (fresult
== dresult
)))
113 /* both values are 0 or infinities of the same sign */
114 errno
= caller_errno
;
117 else if ((dresult
> 0 && dresult
<= FLT_MIN
&& (float) dresult
!= 0.0) ||
118 (dresult
< 0 && dresult
>= -FLT_MIN
&& (float) dresult
!= 0.0))
120 /* subnormal but nonzero value */
121 errno
= caller_errno
;
122 return (float) dresult
;