develooper Front page | perl.perl5.porters | Postings from January 2001

Re: [ID 20010101.004] Not OK: perl v5.7.0 +DEVEL8268 on i586-linux-64int-ld 2.2.17-21mdk (UNINSTALLED)

Thread Previous | Thread Next
From:
Nicholas Clark
Date:
January 7, 2001 11:47
Subject:
Re: [ID 20010101.004] Not OK: perl v5.7.0 +DEVEL8268 on i586-linux-64int-ld 2.2.17-21mdk (UNINSTALLED)
Message ID:
20010107194714.B1048@plum.flirble.org
On Mon, Jan 01, 2001 at 11:16:10PM -0600, Mike Stok wrote:
> All of the messages seem to be due to somthing like '18446744073709551616'
> ne '1.84467440737095516e+19' where the last couple of digits are lost in
> the scientific representation e.g.
> 
> # '18446744073709551600' ne '1.84467440737095516e+19',  1.84467440737095516e+19 => P N P vs P P
> not ok 16

Thanks. I was aware that there was a problem and I thought I knew what it was
(but not how to solve it easily), but it's nice to get a second analysis of
the cause that backs the first up.

> >     ivtype='long long', ivsize=8, nvtype='long double', nvsize=12, Off_t='off_t', lseeksize=8

12 byte NVs seem to preserve exactly 64 bits of UVs, but I don't think that
this is the problem. I think it's to due to the numeric code's correct
conversion of 18446744073709551616 to the string 1.84467440737095516e+19
(which I believe is the correct length of decimal digits for the precision)
where 1.84467440737095516e+19 is unfortunately less than 18446744073709551616.
Because of this, it can convert to an in range unsigned integer value.

For doubles with 53 bit mantissas, the decimal representation
"1.84467440737096e+19" happens to be greater than 18446744073709551616, so
it won't convert to an in range integer value.
It's only chance that we've not seen it before.
There may also be similar change bugs lurking for the conversion of numbers
in the range 9223372036854775808 - 9999999999999999999 in 64 bit perl 5.6
and earlier, because 2**64-1 (max UV) has 1 more decimal digit than
2**63-1 (max IV)

This patch makes op/numconvert.t aware of some precision issues.
All tests pass on 32 bit IV, 64 bit IV, 64 bit IV with 12 byte long doubles.

Nicholas Clark

--- t/op/numconvert.t.orig	Fri Dec 15 19:20:34 2000
+++ t/op/numconvert.t	Sun Jan  7 19:00:55 2001
@@ -95,6 +95,15 @@
 my $max_uv_pp = "$max_uv"; $max_uv_pp++;
 my $max_uv_p1 = "$max_uv"; $max_uv_p1+=0; $max_uv_p1++;
 
+# Also need to cope with %g notation for max_uv_p1 that actually gives an
+# integer less than max_uv because of correct rounding for the limited
+# precisision. This bites for 12 byte long doubles and 8 byte UVs
+
+my $temp = $max_uv_p1;
+my $max_uv_p1_as_iv;
+{use integer; $max_uv_p1_as_iv = 0 + sprintf "%s", $temp}
+my $max_uv_p1_as_uv = 0 | sprintf "%s", $temp;
+
 my @opnames = split //, "-+UINPuinp";
 
 # @list = map { 2->($_), 3->($_), 4->($_), 5->($_),  } @list; # Prepare input
@@ -193,6 +202,15 @@
 	      # string ++ versus numeric ++. Tolerate this little
 	      # bit of insanity
 	      print "# ok, as string ++ of max_uv is \"$max_uv_pp\", numeric is $max_uv_p1\n"
+	    } elsif ($opnames[$last] eq 'I' and $ans[1] eq "-1"
+		     and $ans[0] eq $max_uv_p1_as_iv) {
+	      print "# ok, \"$max_uv_p1\" correctly converts to IV \"$max_uv_p1_as_iv\"\n";
+	    } elsif ($opnames[$last] eq 'U' and $ans[1] eq ~0
+		     and $ans[0] eq $max_uv_p1_as_uv) {
+	      print "# ok, \"$max_uv_p1\" correctly converts to UV \"$max_uv_p1_as_uv\"\n";
+	    } elsif (grep {/^N$/} @opnames[@{$curops[0]}]
+		     and $ans[0] == $ans[1] and $ans[0] <= ~0) {
+	      print "# ok, numerically equal - notation changed due to adding zero\n";
 	    } else {
 	      $nok++,
 	    }


Thread Previous | Thread Next


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About