Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

avoiding trailing zeros

527 views
Skip to first unread message

norb...@gmail.com

unread,
Dec 19, 2008, 3:37:58 PM12/19/08
to
Is there an edit descriptor in Fortran that suppresses trailing zeros,
but outputs significant digits when not zero?

My (unformatted) output looks typically like
.... 0. 0. 0. 0. 0. 0. 0.7875317755557483 0.7862384282167548
0.784890147719363 ....
Many values are zero, but others are not. To save storage space I
would like it to output
.... 0. 0. 0. 0. 0. 0. 0.7875 0.7862 0.7849 ....

With the edit descriptor f6.4, it would look like
.... 0.0000 0.0000 0.0000 0.0000 0.0000 0.000 0.7875 0.7862
0.7849 ....
which is not space efficient either.

Is there a way to get a fixed number of digits, but avoid the trailing
zeros when the output is exactly zero?

Gordon Sande

unread,
Dec 19, 2008, 3:52:03 PM12/19/08
to
On 2008-12-19 16:37:58 -0400, norb...@gmail.com said:

> Is there an edit descriptor in Fortran that suppresses trailing zeros,
> but outputs significant digits when not zero?
>
> My (unformatted) output looks typically like
> .... 0. 0. 0. 0. 0. 0. 0.7875317755557483 0.7862384282167548
> 0.784890147719363 ....
> Many values are zero, but others are not. To save storage space I
> would like it to output
> .... 0. 0. 0. 0. 0. 0. 0.7875 0.7862 0.7849 ....

That looks very formatted as it is human legible. I think you mean
free formatted. Unformatted is the native machine form that often
goes by the street name of binary. The terminology is that of Fortran
rather than the street. Precision is neded here to talk to others for
advice and to find things in the manual.

Unformatted means there is NO format, which includes the list format
of "*" that is just the compilers choice rather than yours.

> With the edit descriptor f6.4, it would look like
> .... 0.0000 0.0000 0.0000 0.0000 0.0000 0.000 0.7875 0.7862
> 0.7849 ....
> which is not space efficient either.
>
> Is there a way to get a fixed number of digits, but avoid the trailing
> zeros when the output is exactly zero?

If you are using F90 then you need to URGENTLY (as in right now!) reread
the section on the advance = "no" option of write. The result will have
full control over the output but will be more verbose.

write ( 10, "(10f20.8)" ) ( x(i), i = 1, 10 )

becomes

do i = 1, 10
if ( x(i) == 0.0 ) then
write ( 10, "(1x,f2.0)", advance = "no" ) x(i)
else
write ( 10, "(1x,f20.8)", advance = "no" ) x(i)
end if
end do
write ( 10, "('')" )

where your details and style will almost surely be something else.


glen herrmannsfeldt

unread,
Dec 19, 2008, 4:13:24 PM12/19/08
to

If you have non-advancing I/O you can print numbers one at a
time with any desired format.

if(x.eq.0) then
write(*,'(A)',advance='no') ' 0.0'
else
write(*,'(f7.4)',advance='no') x
endif

You can put that in a loop and add the appropriate record advance
with something like:

write(*,'(1x)')
or
write(*,'(/)',advance='no')

(I am not sure what the best advance but don't write anything
statement is.)

Keep track of the number of columns written and advance
as appropriate.

It is problems like this that have been so easy to do in
other languages that have always had non-advancing I/O,
but hard to do in Fortran.

-- glen

Terence

unread,
Dec 19, 2008, 7:52:34 PM12/19/08
to

norbe...@gmail.com wrote:
> Is there an edit descriptor in Fortran that suppresses trailing zeros,
> but outputs significant digits when not zero?

...


> Is there a way to get a fixed number of digits, but avoid the trailing
> zeros when the output is exactly zero?

Write the data line to a character string (an internel formatted
WRITE).
Then pass down the string to locate a decimal point at j1, and check
only zeroes till a blank at j2 (else pass this field).
Then move the whole line down from j2 to j1+2 (overwriting by j2-j1-2
zeroes) and pad the same thngth at the far right. This leave the
decimal point and one zero on each zero string field..
Repeat.
Write out the new string, either full original length or the new
shorter version.

This method avoids needing non-advancing I/O.

Dave Allured

unread,
Dec 20, 2008, 3:23:56 AM12/20/08
to

Norb,

I wanted to do the same thing a while back, and I did not find any
standardized edit descriptor to do it. So I wrote an F90 subroutine to
do it. If you would like a copy of the routine, please say so and I
will post it early next week. It's good for making compact CSV output,
among other things.

It uses about the same algorithm that Terrence posted, except that it
also strips the unprotected decimal point if the fraction equals
.000... You could of course tweak it to do exactly what you want, or
roll your own.

--Dave

Dave Allured

unread,
Dec 20, 2008, 3:31:47 AM12/20/08
to

Make that "Terence" with one "r". Ouch.

Michel Olagnon

unread,
Dec 20, 2008, 4:58:43 AM12/20/08
to

You might write into a string, and replace occurrences of "0 " with " "
until all have disappeared before actually printing the string.

robin

unread,
Dec 21, 2008, 5:39:23 PM12/21/08
to
"Michel Olagnon" <mola...@ifremer-a-oter.fr> wrote in message
news:494CC1D3...@ifremer-a-oter.fr...

This method wastes time as well as being more involved than
using non-advancing output (which seems to fit the bill
in this case).


robin

unread,
Dec 21, 2008, 5:39:22 PM12/21/08
to
"Gordon Sande" <g.s...@worldnet.att.net> wrote in message
news:2008121916520216807-gsande@worldnetattnet...

Sufficient would be
write (10, '(A)' , advance = 'no' ) ' 0.'

robin

unread,
Dec 21, 2008, 5:39:22 PM12/21/08
to
"Terence" <tbwr...@cantv.net> wrote in message
news:3c724097-14dd-4204...@40g2000prx.googlegroups.com...

> Write the data line to a character string (an internel formatted
> WRITE).
> Then pass down the string to locate a decimal point at j1, and check
> only zeroes till a blank at j2 (else pass this field).
> Then move the whole line down from j2 to j1+2 (overwriting by j2-j1-2
> zeroes) and pad the same thngth at the far right. This leave the
> decimal point and one zero on each zero string field..
> Repeat.
> Write out the new string, either full original length or the new
> shorter version.

This would give very short lines when many zeros are present,
as well as not being particularly fast.

> This method avoids needing non-advancing I/O.

There's no need to avoid non-advancing output.
It provides the simplest method.


robin

unread,
Dec 21, 2008, 5:39:24 PM12/21/08
to
"glen herrmannsfeldt" <g...@ugcs.caltech.edu> wrote in message news:gih2pj$ko6$1...@naig.caltech.edu...

> norb...@gmail.com wrote:
> > Is there an edit descriptor in Fortran that suppresses trailing zeros,
> > but outputs significant digits when not zero?
>
> > My (unformatted) output looks typically like
> > .... 0. 0. 0. 0. 0. 0. 0.7875317755557483 0.7862384282167548
> > 0.784890147719363 ....
> > Many values are zero, but others are not. To save storage space I
> > would like it to output
> > .... 0. 0. 0. 0. 0. 0. 0.7875 0.7862 0.7849 ....
>
> > With the edit descriptor f6.4, it would look like
> > .... 0.0000 0.0000 0.0000 0.0000 0.0000 0.000 0.7875 0.7862
> > 0.7849 ....
> > which is not space efficient either.
>
> > Is there a way to get a fixed number of digits, but avoid the trailing
> > zeros when the output is exactly zero?
>
> If you have non-advancing I/O you can print numbers one at a
> time with any desired format.
>
> if(x.eq.0) then

This archaic form was superseded nearly 20 years ago
with: if (x == 0) then

> write(*,'(A)',advance='no') ' 0.0'
> else
> write(*,'(f7.4)',advance='no') x
> endif
>
> You can put that in a loop and add the appropriate record advance
> with something like:
>
> write(*,'(1x)')

Sufficient is:- write (*,*)

> or
> write(*,'(/)',advance='no')
>
> (I am not sure what the best advance but don't write anything
> statement is.)
>
> Keep track of the number of columns written and advance
> as appropriate.

It isn't necessary to do that, as new lines are automatically started.

> It is problems like this that have been so easy to do in
> other languages that have always had non-advancing I/O,
> but hard to do in Fortran.

Indeed, it's been available in PL/I and Algol for 40+ years.
In PL/I:
if x(i) ^= 0
then put edit (x(i)) (f(20,16));
else put edit (' 0.')(a);

In PL/I it's possible to write out all the values of X in a single
statement, by making use of the TRIM function (which can also
trim trailing zeros as well as leading blanks) and the EDIT function.

The following statement prints an abbreviated form of x(i)
when zero, and a formatted form when non-zero:-

put edit (trim(edit(x(i), '-9.V999999'), ' ', '0') ) (x(1), a);

This statement can be extended to print all elements
of the array X, as foreshadowed above.

> -- glen


Gary Scott

unread,
Dec 21, 2008, 5:49:12 PM12/21/08
to
robin wrote:
> "glen herrmannsfeldt" <g...@ugcs.caltech.edu> wrote in message news:gih2pj$ko6$1...@naig.caltech.edu...
>
>>norb...@gmail.com wrote:
>>
>>>Is there an edit descriptor in Fortran that suppresses trailing zeros,
>>>but outputs significant digits when not zero?
>>
>>>My (unformatted) output looks typically like
>>>.... 0. 0. 0. 0. 0. 0. 0.7875317755557483 0.7862384282167548
>>>0.784890147719363 ....
>>>Many values are zero, but others are not. To save storage space I
>>>would like it to output
>>>.... 0. 0. 0. 0. 0. 0. 0.7875 0.7862 0.7849 ....
>>
>>>With the edit descriptor f6.4, it would look like
>>>.... 0.0000 0.0000 0.0000 0.0000 0.0000 0.000 0.7875 0.7862
>>>0.7849 ....
>>>which is not space efficient either.
>>
>>>Is there a way to get a fixed number of digits, but avoid the trailing
>>>zeros when the output is exactly zero?
>>
>>If you have non-advancing I/O you can print numbers one at a
>>time with any desired format.
>>
>> if(x.eq.0) then
>
>
> This archaic form was superseded nearly 20 years ago
> with: if (x == 0) then

it wasn't actually superceded, it was made redundant with an unnecessary
new form.
<snip>
--

Gary Scott
mailto:garylscott@sbcglobal dot net

Fortran Library: http://www.fortranlib.com

Support the Original G95 Project: http://www.g95.org
-OR-
Support the GNU GFortran Project: http://gcc.gnu.org/fortran/index.html

If you want to do the impossible, don't hire an expert because he knows
it can't be done.

-- Henry Ford

Gordon Sande

unread,
Dec 21, 2008, 6:32:34 PM12/21/08
to

Optimization and illustrating a method are often at odds.
Optimization then obscures the point being illustrated.
In this case illustrating the method was the greater requirement.
The optimization of a purely text format was considered and rejected.
The form write ( 10, "(' 0.')" was considered but was considered
a poor illustration even while being an even better optimiaztion
than the proposed improvement.

Dick Hendrickson

unread,
Dec 21, 2008, 7:40:11 PM12/21/08
to
If you are sure that for evermore you'll only want up to 4
digits of output, consider doing a table lookup. Something
like
write (unit,*) (trim(table(int(10000*data(i)))),i=1,whatever)

where table is a character(len=6) array.
You'll have to populate it with
'0. '
'0.0001'
...
'0.0999'
'0.1 '
'0.1001'
etc.

But, when you trim the values you'll suppress all of the trailing
spaces, not just the ones after 0. .

Like all clever optimizations, the code is difficult for a
human to read.

Dick Hendrickson

James Van Buskirk

unread,
Dec 21, 2008, 9:04:59 PM12/21/08
to
<norb...@gmail.com> wrote in message
news:6a57bddf-75e5-4102...@w24g2000prd.googlegroups.com...

One way to do it is to write a separate function that formats each
output string just the way you want and then invoke it in an implied
DO-loop:

C:\gfortran\clf\zeros>type zeros.f90
module mykinds
implicit none
integer, parameter :: dp = selected_real_kind(15,300)
end module mykinds

module funcs
use mykinds
implicit none
contains
function write_fmt(x, fmt)
real(dp) x
character(*) fmt
character(write_fmt_len(x, fmt)) write_fmt

if(x /= 0) then
write(write_fmt, fmt) x
else
write_fmt = '0.'
end if
end function write_fmt

pure function write_fmt_len(x, fmt)
real(dp), intent(in) :: x
character(*), intent(in) :: fmt
integer write_fmt_len
character(256) temp

if(x /= 0) then
write(temp, fmt) x
write_fmt_len = len_trim(temp)
else
write_fmt_len = 2
end if
end function write_fmt_len
end module funcs

program zeros
use mykinds, only: dp
use funcs, only: write_fmt
implicit none
real(dp) A(9)
character(20) fmt
integer i

A = (/0.0_dp, 0.0_dp, 0.0_dp, 0.0_dp, 0.0_dp, 0.0_dp, &
0.7875317755557483_dp, 0.7862384282167548_dp, &
0.784890147719363_dp/)
write(fmt,'(a,i0,a)') '(',size(A),'(a:1x))'
write(*,fmt) (write_fmt(A(i),'(f6.4)'), i = 1, size(A))
end program zeros

C:\gfortran\clf\zeros>gfortran zeros.f90 -ozeros

C:\gfortran\clf\zeros>zeros


0. 0. 0. 0. 0. 0. 0.7875 0.7862 0.7849

Actually, the above technically requires f03 to enable invocation of
a function that does internal I/O during execution of a WRITE
statement, but this feature of f03 still works in many f95 compilers.

--
write(*,*) transfer((/17.392111325966148d0,6.5794487871554595D-85, &
6.0134700243160014d-154/),(/'x'/)); end


robin

unread,
Dec 25, 2008, 7:55:43 PM12/25/08
to
"Gary Scott" <garyl...@sbcglobal.net> wrote in message
news:JJz3l.15189$ZP4....@nlpi067.nbdc.sbc.com...

> robin wrote:
> > "glen herrmannsfeldt" <g...@ugcs.caltech.edu> wrote in message
news:gih2pj$ko6$1...@naig.caltech.edu...
> >
> >> if(x.eq.0) then
> >
> > This archaic form was superseded nearly 20 years ago
> > with: if (x == 0) then
>
> it wasn't actually superceded, it was made redundant with an unnecessary
> new form.

It's an archaic form, and has been superseded (=displaced) by the improved form.


robin

unread,
Dec 25, 2008, 7:55:43 PM12/25/08
to
"Gordon Sande" <g.s...@worldnet.att.net> wrote in message
news:2008122119323416807-gsande@worldnetattnet...

> On 2008-12-21 18:39:22 -0400, "robin" <rob...@bigpond.com> said:
>
> > "Gordon Sande" <g.s...@worldnet.att.net> wrote in message
> > news:2008121916520216807-gsande@worldnetattnet...
> >> On 2008-12-19 16:37:58 -0400, norb...@gmail.com said:
> >>
> >> write ( 10, "(10f20.8)" ) ( x(i), i = 1, 10 )
> >>
> >> becomes
> >>
> >> do i = 1, 10
> >> if ( x(i) == 0.0 ) then
> >> write ( 10, "(1x,f2.0)", advance = "no" ) x(i)
> >
> > Sufficient would be
> > write (10, '(A)' , advance = 'no' ) ' 0.'
>
> Optimization and illustrating a method are often at odds.

Printing 0. is clearer than printing x(i) when x(i) is zero.


0 new messages