On Thursday 18 September 2008 06:13:30 Patrick R. Michaud (via RT) wrote:
When generating PIR output (e.g., from the compiler tools), we
often need to convert a Float value into an equivalent representation
for PIR. Unfortunately, all of the mechanisms I've looked at for
doing this lose a lot of precision, which really isn't acceptable.
The prime candidate for this seems to be the Cget_repr opcode,
which AFAICT is intended for this purpose. However, it appears to
provide only about 7 digits of precision.
Yes.
The approaches I've tried thus far are simple stringification,
the get_repr opcode, and variations on sprintf formats. Here's
an example showing the difficulty:
$ cat x.pir
.sub 'main'
$N0 = exp 1.0
'as_pir'($N0)
.end
.sub 'as_pir'
.param pmc value
print set_p_s :
$S0 = value
say $S0
print get_repr :
$S0 = get_repr value
say $S0
print printf %g:
$P0 = new 'ResizablePMCArray'
push $P0, value
$S0 = sprintf '%g', $P0
say $S0
.end
$ ./parrot x.pir
set_p_s : 2.71828
get_repr : 2.718282
printf %g: 2.71828
By way of comparison, Perl 5 gives a far more reasonable result:
$ perl -e 'print exp(1),\n'
2.71828182845905
One approach might be to take whatever algorithm Perl 5 uses for
stringifying its floats (or something close to it), and adopt that
for get_repr and/or Float stringification.
How about 15 digits of precision? The attached patch (which requires a
reconfigure) does so. It also drops trailing zeroes, which may or may not be
what you want. It's much more precise though:
set_p_s : 2.71828182845905
get_repr : 2.718281828459045
printf %g: 2.718282
(I used %.15g for the format.)
Note that several tests fail as they rely on hard-coded values matching
the %vg and %g formats, with seven digits of precision retaining any trailing
zeroes.
-- c
=== config/auto/format.pm
==
--- config/auto/format.pm (revision 31407)
+++ config/auto/format.pm (local)
@@ -67,7 +67,7 @@
$nvsize = $floatsize;
if ( $nv eq double ) {
$nvsize = $doublesize;
-$nvformat = %f;
+$nvformat = %.15g;
}
elsif ( $nv eq long double ) {
=== src/string.c
==
--- src/string.c (revision 31407)
+++ src/string.c (local)
@@ -2079,7 +2079,7 @@
/* Too damn hard--hand it off to Parrot_sprintf, which'll probably
use the system sprintf anyway, but has gigantic buffers that are
awfully hard to overflow. */
-return Parrot_sprintf_c(interp, %vg, f);
+return Parrot_sprintf_c(interp, FLOATVAL_FMT, f);
}