Skip to content

Commit ffa277e

Browse files
Ed Allen SmithFather Chrysostomos
Ed Allen Smith
authored and
Father Chrysostomos
committed
[perl #32380] numeric.c assumes that NV_DIG+2 will be enough digits
for all precision possible in NV numeric.c, in the Perl_my_atof2 function, makes the following assumption: /* There is no point in processing more significant digits * than the NV can hold. Note that NV_DIG is a lower-bound value, * while we need an upper-bound value. We add 2 to account for this; * since it will have been conservative on both the first and last digit. * For example a 32-bit mantissa with an exponent of 4 would have * exact values in the set * 4 * 8 * .. * 17179869172 * 17179869176 * 17179869180 * * where for the purposes of calculating NV_DIG we would have to discount * both the first and last digit, since neither can hold all values from * 0..9; but for calculating the value we must examine those two digits. */ #define MAX_SIG_DIGITS (NV_DIG+2) Digits beyond MAX_SIG_DIGITS are ignored. In some systems and/or modes (e.g., with/without using long doubles), this is not the case. One example is IRIX when using long doubles, which are not fully IEEE compliant; with it, while NV_DIG (the _minimum_ number of digits usable) is 31 for long doubles used as NVs, long doubles can have up to 34 digits of accuracy. (As well as IRIX with long doubles, other machines using a mode in which NV is not IEEE compliant (e.g., as found by the following from numeric.c: #ifdef ((defined(VMS) && !defined(__IEEE_FP)) || defined(_UNICOS)) (although UNICOS does not by default use Perl's atof in any event) or as noted in the hints files for DEC OSF with the old MIPS CC) may benefit from a change to this.) I will attach a test program, example set of problematic outputs, and experimental patch so others can explore this on their systems. (With the patch and a -Accflags='-DMAX_SIG_DIG_PLUS=3' (or -Accflags='-DMAX_SIG_DIG_PLUS=4'), the test program was successful. Different values of MAX_SIG_DIG_PLUS may need to be experimented with, especially with different other Configure/compiler flags (long doubles yes/no, optimization affecting floating point, etcetera); 3 was the maximum that did any good on IRIX with long doubles, but others may differ.) I have done some local testing (as in the normal testsuite) of the patch and different -DMAX_SIG_DIG_PLUS values, and will be doing more; it is possible that it would be best to build in the test program into, say, numconvert.t. Patching hints/irix_6.sh to use -DMAX_SIG_DIG_PLUS=3 if long doubles are in use, or a define of MAX_SIG_DIG_PLUS to 3 if defined(IRIX) and long doubles are in use, is also advisable; I have not included either in my patch because I was unsure which was recommended practice.
1 parent 6d24fbd commit ffa277e

File tree

1 file changed

+8
-1
lines changed

1 file changed

+8
-1
lines changed

numeric.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -887,7 +887,14 @@ Perl_my_atof2(pTHX_ const char* orig, NV* value)
887887
* both the first and last digit, since neither can hold all values from
888888
* 0..9; but for calculating the value we must examine those two digits.
889889
*/
890-
#define MAX_SIG_DIGITS (NV_DIG+2)
890+
#ifdef MAX_SIG_DIG_PLUS
891+
/* It is not necessarily the case that adding 2 to NV_DIG gets all the
892+
possible digits in a NV, especially if NVs are not IEEE compliant
893+
(e.g., long doubles on IRIX) - Allen <[email protected]> */
894+
# define MAX_SIG_DIGITS (NV_DIG+MAX_SIG_DIG_PLUS)
895+
#else
896+
# define MAX_SIG_DIGITS (NV_DIG+2)
897+
#endif
891898

892899
/* the max number we can accumulate in a UV, and still safely do 10*N+9 */
893900
#define MAX_ACCUMULATE ( (UV) ((UV_MAX - 9)/10))

0 commit comments

Comments
 (0)