[Patch, libfortran] PR 52434/48878/38199 Improve floating point formatted writes

Janne Blomqvist blomqvist.janne@gmail.com
Thu Mar 8 22:40:00 GMT 2012


Hi,

the attached patch implements some improvements for formatted writes
of floating point values. Currently libgfortran uses snprintf() to
fill a buffer with a fixed amount of digits, regardless of the digits
required, and then rounding or zero extending as needed. The patch
changes this to first figure out the number of digits needed, then
using snprintf() to fill the buffer with exactly the needed amount of
digits (except when a ROUND= specifier is used, in that case more
digits are generated). This has a few advantages:

- As the performance cost of snprintf() increases roughly linearly
with more digits (see
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=38199#c13 ), we needlessly
waste cycles when we don't need all the digits. The attached
write-many.f90 benchmark is almost twice as fast; best of five timings
with current trunk:

real    0m2.055s

with patch:

real    0m1.268s


- Although we generate enough digits to be able to get back the
original value exactly when reading, there are some (valid?) usecases
where more digits are needed. Exhibit 1 is dyadic.f90 which prints a
couple dyadic fractions which are exact both in binary and character
representations. With current trunk:

$ ./dyadic_f
.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004940656458412465441765687928682213723650600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
.99999999999999988897769753748434595763683000000000000

With patch:

$ ./dyadic_f
.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000000494065645841246544176568792868221372365059802614324
76442558568250067550727020875186529983636163599237979656469544571773092665671035593979639877479601078187812630071319031140452
78458171678489821036887186360569987307230500063874091535649843873124733972731696151400317153853980741262385655911710266585566
86768187039560310624931945271591492455329305456544401127480129709999541931989409080416563324524757147869014726780159355238611
55013480352649347201937902681071074917033322268447533357208324319360923828934583680601060115061698097530783422773183292479049
82524730776375927247874656084778203734469699533647017972677717585125660551199131504891101451037862738167250955837389733598993
664809941164205702637090279242767544565229087538682506419718265533447265625
.99999999999999988897769753748434595763683319091796875

For another example, Bob Corbett recently posted boz_corbett.f90 on
c.l.f. With trunk:

$ ./boz_corbett
.67242062862241870125253556346435045576786000...E-4931

where "..." is a very long string of zeros. With patch:

$ ./boz_corbett
.672420628622418701252535563464350455767864674589043138777375863685283014882452413061808444374167...E-4931

where "..." is a very long string of digits.

- With the patch, for the vast majority of Fortran programs which
don't use the F2003 ROUND= specifier, we let snprintf() do the
rounding (as we generate the correct number of digits to begin with).
Thus isolating the user from potential bugs in the rounding logic in
libgfortran, as well as the performance impacts of that same code.

Note that GFortran previously did roundTiesToAway, whereas at least
glibc snprintf() does roundTiesToEven, so some change in behavior is
expected. Anyway, this is IMHO for the better, as it avoids biasing
the magnitude upwards in some common cases. Also, roundTiesToAway is
the default rounding mode for arithmetic.

Regtested on x86_64-unknown-linux-gnu, Ok for trunk?

2012-03-09  Janne Blomqvist  <jb@gcc.gnu.org>

	PR libfortran/52434
	PR libfortran/48878
	PR libfortran/38199
	* io/unit.c (get_internal_unit): Default to ROUND_UNSPECIFIED.
	(init_units): Likewise.
	* io/write_float.def (determine_precision): New function.
	(output_float): Take into account buffer with %f format, no need
	for our own rounding if unspecified or processor specified
	rounding.
	(DTOA): Simplify format string, add parameters.
	(FDTOA): New macros similar to DTOA, but using %f format.
	(OUTPUT_FLOAT_FMT_G): Stack allocate newf, determine correct
	precision and fill buffer.
	(EN_PREC): New macro.
	(determine_en_precision): New function.
	(WRITE_FLOAT): For G format, move buffer filling into
	output_float_FMT_G, use FDTOA for F format.
	(write_float): Increase buffer due to F format.


testsuite ChangeLog:

2012-03-09  Janne Blomqvist  <jb@gcc.gnu.org>

	PR libfortran/52434
	PR libfortran/48878
	PR libfortran/38199
	* gfortran.dg/edit_real_1.f90: Don't assume roundTiesToAway.
	* gfortran.dg/round_1.f03: Likewise.

-- 
Janne Blomqvist
-------------- next part --------------
A non-text attachment was scrubbed...
Name: float_round.diff
Type: text/x-patch
Size: 21930 bytes
Desc: not available
URL: <http://gcc.gnu.org/pipermail/fortran/attachments/20120308/165d4e4a/attachment.bin>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: write-many.f90
Type: text/x-fortran
Size: 161 bytes
Desc: not available
URL: <http://gcc.gnu.org/pipermail/fortran/attachments/20120308/165d4e4a/attachment-0001.bin>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: dyadic.f90
Type: text/x-fortran
Size: 1478 bytes
Desc: not available
URL: <http://gcc.gnu.org/pipermail/fortran/attachments/20120308/165d4e4a/attachment-0002.bin>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: boz_corbett.f90
Type: text/x-fortran
Size: 125 bytes
Desc: not available
URL: <http://gcc.gnu.org/pipermail/fortran/attachments/20120308/165d4e4a/attachment-0003.bin>


More information about the Fortran mailing list