diff mbox

[libgfortran] Fix numerous formatting bugs

Message ID 4DB55E86.5030001@frontier.com
State New
Headers show

Commit Message

Jerry DeLisle April 25, 2011, 11:44 a.m. UTC
On 04/25/2011 03:48 AM, Janne Blomqvist wrote:
> On Sun, Apr 24, 2011 at 23:32, Jerry DeLisle<jvdelisle@frontier.com>  wrote:
>> The final solution to 48602 I want to do as a second phase to this. The
>> second phase will attempt to avoid floating point comparisons which are
>> sensitive to optimizations and or printf behavior.
>
> Sounds like a good idea. I think it should be possible to modify the
> algorithm to just count decimal places with integer arithmetic.
>
>> Regression tested on x86-64. I do have some concern that the test cases
>> modified may have issues on other platforms because we have increased the
>> default precision on some reals.  If this happens we should be able to
>> adjust test cases by not using default formatting.
>
> Or xfail the testcases in question on those targets; I think it makes
> sense to assume IEEE 754 hardware and a snprintf() capable of correct
> rounding as the baseline.
>
> Now, for one of the testcase changes:
>
> --- gcc/testsuite/gfortran.dg/char4_iunit_1.f03	(revision 172909)
> +++ gcc/testsuite/gfortran.dg/char4_iunit_1.f03	(working copy)
> @@ -24,11 +24,11 @@ program char4_iunit_1
>     write(string, *) .true., .false. , .true.
>     if (string .ne. 4_" T F T                                    ") call abort
>     write(string, *) 1.2345e-06, 4.2846e+10_8
> -  if (string .ne. 4_"  1.23450002E-06   42846000000.000000     ") call abort
> +  if (string .ne. 4_"  1.234500019E-06   42846000000.000000    ") call abort
>
> This looks wrong. For correctly rounded REAL(4) output, we need 9
> significant digits, but here we print 10.
>

Well, I bumped it up for defaults based on pr48488 comment #2 shown below. Have 
I misinterpreted? Maybe what we want is w=16, d=8?

Jerry

Comments

Janne Blomqvist April 25, 2011, 2:36 p.m. UTC | #1
On Mon, Apr 25, 2011 at 14:44, Jerry DeLisle <jvdelisle@frontier.com> wrote:
> On 04/25/2011 03:48 AM, Janne Blomqvist wrote:
>> Now, for one of the testcase changes:
>>
>> --- gcc/testsuite/gfortran.dg/char4_iunit_1.f03 (revision 172909)
>> +++ gcc/testsuite/gfortran.dg/char4_iunit_1.f03 (working copy)
>> @@ -24,11 +24,11 @@ program char4_iunit_1
>>    write(string, *) .true., .false. , .true.
>>    if (string .ne. 4_" T F T                                    ") call
>> abort
>>    write(string, *) 1.2345e-06, 4.2846e+10_8
>> -  if (string .ne. 4_"  1.23450002E-06   42846000000.000000     ") call
>> abort
>> +  if (string .ne. 4_"  1.234500019E-06   42846000000.000000    ") call
>> abort
>>
>> This looks wrong. For correctly rounded REAL(4) output, we need 9
>> significant digits, but here we print 10.
>>
>
> Well, I bumped it up for defaults based on pr48488 comment #2 shown below.

Yes, that comment in the PR is correct; to guarantee that a
binary->ascii->binary roundtrip preserves the original binary value
(with the default "round to nearest, break on even" rounding mode),
one must output at least {9, 17, 21, 36} significant digits for real
kinds 4, 8, 10, and 16, respectively (yes, I double-checked IEEE
754-2008 that this is indeed correct).

Since for the G edit descriptor d is equivalent to the number of
significant digits, AFAICS the write.c patch below is correct and the
bug must be elsewhere, no?


> Index: libgfortran/io/write.c
> ===================================================================
> --- libgfortran/io/write.c      (revision 172909)
> +++ libgfortran/io/write.c      (working copy)
> @@ -1432,8 +1432,8 @@ set_fnode_default (st_parameter_dt *dtp, fnode *f,
>   switch (length)
>     {
>     case 4:
> -      f->u.real.w = 15;
> -      f->u.real.d = 8;
> +      f->u.real.w = 16;
> +      f->u.real.d = 9;
>       f->u.real.e = 2;
>       break;
>     case 8:
> @@ -1442,13 +1442,13 @@ set_fnode_default (st_parameter_dt *dtp, fnode *f,
>       f->u.real.e = 3;
>       break;
>     case 10:
> -      f->u.real.w = 29;
> -      f->u.real.d = 20;
> +      f->u.real.w = 30;
> +      f->u.real.d = 21;
>       f->u.real.e = 4;
>       break;
>     case 16:
> -      f->u.real.w = 44;
> -      f->u.real.d = 35;
> +      f->u.real.w = 45;
> +      f->u.real.d = 36;
>       f->u.real.e = 4;
>       break;
>     default:
>
Jerry DeLisle April 26, 2011, 4:58 a.m. UTC | #2
On 04/25/2011 07:36 AM, Janne Blomqvist wrote:
> On Mon, Apr 25, 2011 at 14:44, Jerry DeLisle<jvdelisle@frontier.com>  wrote:
>> On 04/25/2011 03:48 AM, Janne Blomqvist wrote:
>>> Now, for one of the testcase changes:
>>>
>>> --- gcc/testsuite/gfortran.dg/char4_iunit_1.f03 (revision 172909)
>>> +++ gcc/testsuite/gfortran.dg/char4_iunit_1.f03 (working copy)
>>> @@ -24,11 +24,11 @@ program char4_iunit_1
>>>     write(string, *) .true., .false. , .true.
>>>     if (string .ne. 4_" T F T                                    ") call
>>> abort
>>>     write(string, *) 1.2345e-06, 4.2846e+10_8
>>> -  if (string .ne. 4_"  1.23450002E-06   42846000000.000000     ") call
>>> abort
>>> +  if (string .ne. 4_"  1.234500019E-06   42846000000.000000    ") call
>>> abort
>>>
>>> This looks wrong. For correctly rounded REAL(4) output, we need 9
>>> significant digits, but here we print 10.
>>>
>>
>> Well, I bumped it up for defaults based on pr48488 comment #2 shown below.
>
> Yes, that comment in the PR is correct; to guarantee that a
> binary->ascii->binary roundtrip preserves the original binary value
> (with the default "round to nearest, break on even" rounding mode),
> one must output at least {9, 17, 21, 36} significant digits for real
> kinds 4, 8, 10, and 16, respectively (yes, I double-checked IEEE
> 754-2008 that this is indeed correct).
>
> Since for the G edit descriptor d is equivalent to the number of
> significant digits, AFAICS the write.c patch below is correct and the
> bug must be elsewhere, no?

Looking for it.

Jerry
Jerry DeLisle April 27, 2011, 4:09 a.m. UTC | #3
On 04/25/2011 07:36 AM, Janne Blomqvist wrote:
> On Mon, Apr 25, 2011 at 14:44, Jerry DeLisle<jvdelisle@frontier.com>  wrote:
>> On 04/25/2011 03:48 AM, Janne Blomqvist wrote:
>>> Now, for one of the testcase changes:
>>>
>>> --- gcc/testsuite/gfortran.dg/char4_iunit_1.f03 (revision 172909)
>>> +++ gcc/testsuite/gfortran.dg/char4_iunit_1.f03 (working copy)
>>> @@ -24,11 +24,11 @@ program char4_iunit_1
>>>     write(string, *) .true., .false. , .true.
>>>     if (string .ne. 4_" T F T                                    ") call
>>> abort
>>>     write(string, *) 1.2345e-06, 4.2846e+10_8
>>> -  if (string .ne. 4_"  1.23450002E-06   42846000000.000000     ") call
>>> abort
>>> +  if (string .ne. 4_"  1.234500019E-06   42846000000.000000    ") call
>>> abort
>>>
>>> This looks wrong. For correctly rounded REAL(4) output, we need 9
>>> significant digits, but here we print 10.
>>>
>>
>> Well, I bumped it up for defaults based on pr48488 comment #2 shown below.
>
> Yes, that comment in the PR is correct; to guarantee that a
> binary->ascii->binary roundtrip preserves the original binary value
> (with the default "round to nearest, break on even" rounding mode),
> one must output at least {9, 17, 21, 36} significant digits for real
> kinds 4, 8, 10, and 16, respectively (yes, I double-checked IEEE
> 754-2008 that this is indeed correct).
>
> Since for the G edit descriptor d is equivalent to the number of
> significant digits, AFAICS the write.c patch below is correct and the
> bug must be elsewhere, no?
>

No.

Look at this example:

program t4
   implicit none
   character(len=44) :: string
   write(*,*) 1.2345e-06, 4.2846e+10_8
   write(*,'(1x,1pG16.9e2,1x,1pG25.17e3)') 1.2345e-06, 4.2846e+10_8
   write(*,'(1x,1pG15.8e2,1x,1pG25.17e3)') 1.2345e-06, 4.2846e+10_8
end program t4

This gives with the patch:

   1.234500019E-06   42846000000.000000
   1.234500019E-06   42846000000.000000
   1.23450002E-06   42846000000.000000

And without the patch:

   1.23450002E-06   42846000000.000000
   1.234500019E-06   42846000000.000000
   1.23450002E-06   42846000000.000000

d is the number of digits after the decimal point, not the number of significant 
digits.

For comaprison, ifort gives:

   1.2345000E-06   42846000000.0000
   1.234500019E-06   42846000000.000000
   1.23450002E-06   42846000000.000000

Ifort chooses to use d=7 for list directed.

With that being said, I do think there is possibly a different bug not related 
to the above that I am working on isolating it.  Stay tuned.

Jerry
Jerry DeLisle April 27, 2011, 4:43 a.m. UTC | #4
On 04/26/2011 09:09 PM, Jerry DeLisle wrote:
---snip---
>
> 1.234500019E-06 42846000000.000000
> 1.234500019E-06 42846000000.000000
> 1.23450002E-06 42846000000.000000
>
> And without the patch:
>
> 1.23450002E-06 42846000000.000000
> 1.234500019E-06 42846000000.000000
> 1.23450002E-06 42846000000.000000
>
> d is the number of digits after the decimal point, not the number of significant
> digits.
>
> For comaprison, ifort gives:
>
> 1.2345000E-06 42846000000.0000
> 1.234500019E-06 42846000000.000000
> 1.23450002E-06 42846000000.000000
>
> Ifort chooses to use d=7 for list directed.
>
> With that being said, I do think there is possibly a different bug not related
> to the above that I am working on isolating it. Stay tuned.
>
> Jerry
>
Ooops! I fooled my self.  I made a slight mod while testing above and thought I 
had a bug.  Now putting it back all is well.  I am back to the original posted 
patch awaiting approval.

Jerry
Janne Blomqvist April 27, 2011, 5:53 a.m. UTC | #5
On Wed, Apr 27, 2011 at 07:09, Jerry DeLisle <jvdelisle@frontier.com> wrote:
> On 04/25/2011 07:36 AM, Janne Blomqvist wrote:
>>
>> On Mon, Apr 25, 2011 at 14:44, Jerry DeLisle<jvdelisle@frontier.com>
>>  wrote:
>>>
>>> On 04/25/2011 03:48 AM, Janne Blomqvist wrote:
>>>>
>>>> Now, for one of the testcase changes:
>>>>
>>>> --- gcc/testsuite/gfortran.dg/char4_iunit_1.f03 (revision 172909)
>>>> +++ gcc/testsuite/gfortran.dg/char4_iunit_1.f03 (working copy)
>>>> @@ -24,11 +24,11 @@ program char4_iunit_1
>>>>    write(string, *) .true., .false. , .true.
>>>>    if (string .ne. 4_" T F T                                    ") call
>>>> abort
>>>>    write(string, *) 1.2345e-06, 4.2846e+10_8
>>>> -  if (string .ne. 4_"  1.23450002E-06   42846000000.000000     ") call
>>>> abort
>>>> +  if (string .ne. 4_"  1.234500019E-06   42846000000.000000    ") call
>>>> abort
>>>>
>>>> This looks wrong. For correctly rounded REAL(4) output, we need 9
>>>> significant digits, but here we print 10.
>>>>
>>>
>>> Well, I bumped it up for defaults based on pr48488 comment #2 shown
>>> below.
>>
>> Yes, that comment in the PR is correct; to guarantee that a
>> binary->ascii->binary roundtrip preserves the original binary value
>> (with the default "round to nearest, break on even" rounding mode),
>> one must output at least {9, 17, 21, 36} significant digits for real
>> kinds 4, 8, 10, and 16, respectively (yes, I double-checked IEEE
>> 754-2008 that this is indeed correct).
>>
>> Since for the G edit descriptor d is equivalent to the number of
>> significant digits, AFAICS the write.c patch below is correct and the
>> bug must be elsewhere, no?
>>
>
> No.
>
> Look at this example:
>
> program t4
>  implicit none
>  character(len=44) :: string
>  write(*,*) 1.2345e-06, 4.2846e+10_8
>  write(*,'(1x,1pG16.9e2,1x,1pG25.17e3)') 1.2345e-06, 4.2846e+10_8
>  write(*,'(1x,1pG15.8e2,1x,1pG25.17e3)') 1.2345e-06, 4.2846e+10_8
> end program t4
>
> This gives with the patch:
>
>  1.234500019E-06   42846000000.000000
>  1.234500019E-06   42846000000.000000
>  1.23450002E-06   42846000000.000000
>
> And without the patch:
>
>  1.23450002E-06   42846000000.000000
>  1.234500019E-06   42846000000.000000
>  1.23450002E-06   42846000000.000000
>
> d is the number of digits after the decimal point, not the number of
> significant digits.

I stand corrected. Or well, I still stand by my previous statement
that with the G edit descriptor d corresponds to the number of
significant digits. However, only when not using the scale factor.

Since we use a scale factor of 1, when the magnitude of the number is
such that the E edit descriptor is used, according to F2008 10.7.2.3.3
paragraph 6 for 0 < k < d+2 we must print k significant digits to the
left of the decimal point and d-k+1 to the right. That is, with k=1 we
print one digit to the left of the decimal point and d-1+1=d to the
right which has the effect of increasing the number of significant
digits by one!

However, when the magnitude of the value is such that F editing is
used, the scale factor has no effect and we thus print d significant
digits.

So in order to guarantee an exact binary<->ascii roundtrip we must
accept an extra digit in some cases. Or then do something which would
make list formatted (and perhaps G0 as well?) write differ from 1PGw.d
(effectively, reduce d by one when the magnitude is such that E
editing is used)?
diff mbox

Patch

Index: libgfortran/io/write.c
===================================================================
--- libgfortran/io/write.c	(revision 172909)
+++ libgfortran/io/write.c	(working copy)
@@ -1432,8 +1432,8 @@  set_fnode_default (st_parameter_dt *dtp, fnode *f,
    switch (length)
      {
      case 4:
-      f->u.real.w = 15;
-      f->u.real.d = 8;
+      f->u.real.w = 16;
+      f->u.real.d = 9;
        f->u.real.e = 2;
        break;
      case 8:
@@ -1442,13 +1442,13 @@  set_fnode_default (st_parameter_dt *dtp, fnode *f,
        f->u.real.e = 3;
        break;
      case 10:
-      f->u.real.w = 29;
-      f->u.real.d = 20;
+      f->u.real.w = 30;
+      f->u.real.d = 21;
        f->u.real.e = 4;
        break;
      case 16:
-      f->u.real.w = 44;
-      f->u.real.d = 35;
+      f->u.real.w = 45;
+      f->u.real.d = 36;
        f->u.real.e = 4;
        break;
      default: