diff options
author | Ed Allen Smith <easmith@beatrice.rutgers.edu> | 2010-10-03 15:51:34 -0700 |
---|---|---|
committer | Father Chrysostomos <sprout@cpan.org> | 2010-10-03 15:51:59 -0700 |
commit | ffa277e59cf0a21b8d133be39d7e10fad0154ae8 (patch) | |
tree | c5125d1d73a3ba4a6c77b95576143ba263c5008f /numeric.c | |
parent | 6d24fbd10b671f02fd7526bee66bd955389d9ee4 (diff) | |
download | perl-ffa277e59cf0a21b8d133be39d7e10fad0154ae8.tar.gz |
[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.
Diffstat (limited to 'numeric.c')
-rw-r--r-- | numeric.c | 9 |
1 files changed, 8 insertions, 1 deletions
@@ -887,7 +887,14 @@ Perl_my_atof2(pTHX_ const char* orig, NV* value) * 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) +#ifdef MAX_SIG_DIG_PLUS + /* It is not necessarily the case that adding 2 to NV_DIG gets all the + possible digits in a NV, especially if NVs are not IEEE compliant + (e.g., long doubles on IRIX) - Allen <allens@cpan.org> */ +# define MAX_SIG_DIGITS (NV_DIG+MAX_SIG_DIG_PLUS) +#else +# define MAX_SIG_DIGITS (NV_DIG+2) +#endif /* the max number we can accumulate in a UV, and still safely do 10*N+9 */ #define MAX_ACCUMULATE ( (UV) ((UV_MAX - 9)/10)) |