9

I have some floating point numbers that I need to output from a Fortran program. Let's say the maximum number could be 999.9999 and they are all non-negative. I need zero-padding in front of all numbers less than 100.

For instance, if I have 25.6893782, 245.354567, and 1.2345678, I need to print them out in a form something like

025.6894
245.3546
001.2346

How can I do this? It would be fairly easy with the T edit descriptor if I knew that, for instance, all numbers would be between 10 and 99, something like that. But there is no way for me to know that ahead of time.

bob.sacamento
  • 6,283
  • 10
  • 56
  • 115

5 Answers5

13

This works for me

real :: areal

then

write(*,'(i3.3,f0.6)') int(areal),areal-int(areal)
High Performance Mark
  • 77,191
  • 7
  • 105
  • 161
2

Zero-padding can be performed for integer fields, so if you printed the result as two separate fields you might be able to make it happen. Here's a way that is less than pretty, but works. Say x is the value you want to print:

DOUBLE PRECISION x
CHARACTER*6 y

x = 123.4567

WRITE(y,'(F6.4)') x-int(x)


WRITE(*,'(I3.3,A5)') int(x), y(2:5)

y is declared as a CHARACTER*6 because it needs to hold the fractional part of your number (4 decimal places), a leading zero, and a decimal point. This can be easily changed if you want to show more decimal places, though it would be trickier if you wanted to show a variable number of decimal places.

The I3.3 field descriptor means "print an integer with a maximum field width of 3 and pad left with zeroes so that there are always 3 digits". When printing out the value we take y(2:5) to strip off the leading zero.

Happy coding!

c.maclean
  • 401
  • 2
  • 9
  • I came up with something similar. You and I are basically doing what High Performance Mark did, but his way is much more compact. Thanks for the help. – bob.sacamento Jul 26 '13 at 19:35
  • I saw High Performance Mark's fix and I agree. I didn't know about the '0' width specifier but it's a much better solution. Glad to help. – c.maclean Jul 26 '13 at 19:56
2

This is a trick I used to use in MS BASIC on the Commodore PETs in the late 70s. The code has been modified for negative numbers. If you would like positive numbers to have a leading +, just change the last character of signchr to '+'

subroutine leadingzero(x)
   real x
   character(len=16) str
   character, dimension(3):: signchr = (/'-', ' ', ' ' /)
   write(str,'(F9.4)') 1000.0 + abs(x)
   write(*,*) signchr(int(sign(1.0,x)) + 2), str(2:) ! drop the 1
end subroutine leadingzero

program main
   call leadingzero(0.01)
   call leadingzero(0.1)
   call leadingzero(2.532)
   call leadingzero(9.9999)
   call leadingzero(9.999999)
   call leadingzero(10.987)
   call leadingzero(123.456)
   call leadingzero(0.0)
   call leadingzero(-0.01)
   call leadingzero(-0.1)
   call leadingzero(-2.532)
   call leadingzero(-9.9999)
   call leadingzero(-9.999999)
   call leadingzero(-10.987)
   call leadingzero(-123.456)
end program

Edit - returning result in a string

subroutine leadingzerostr(x, str_temp)
    real x
    character(*) str_temp
    character(len=10) str
    character, dimension(3):: signchr = (/'-', ' ', ' ' /)
    write(str,'(F10.4)') 10000.0 + abs(x)
    str_temp = str
    str_temp(1:1) = signchr(int(sign(1.0,x)) + 2)
end subroutine leadingzerostr
cup
  • 7,589
  • 4
  • 19
  • 42
  • Can you provide solution if the value is negative? –  Jan 03 '18 at 00:14
  • What sort of result are you expecting? It prints -000.01 for -ve, 000.01 for +ve. – cup Jan 03 '18 at 14:03
  • Is there a chance to show how we can write `signchr(int(sign(1.0,x)) + 2), str(2:)` , for example, `str_temp`, which is a `character type` with lenght of `0000.0000`? –  Jan 03 '18 at 18:09
  • The result is blank character. Try to make a function with `str_temp` like character result. –  Jan 04 '18 at 09:31
1

An alternative method to the method of High Performance Mark is to do use the TL and TR position-edit-descriptors. First print the float with Fw.d, move w positions back, print the integer with padding zeros and width w − d, move d + 1 positions forward.

write (*, '(F6.3,TL6,I2.2,TR4)') f,int(f)

The problem this method and the method of High Performance Mark have is rounding. The following program demonstrates this:

program test_rounding
  double precision :: f
  f = 6 - 1D-6
  ! default compiler dependent rounding :: gfortran NEAREST
  write (*, '(F6.3,TL6,I2.2,TR4)') f,int(f)
  write (*, '(I2.2,F0.3)') int(f), f-int(f)
  write (*, '(I2.2,F4.3)') int(f), f-int(f)
  ! rounding to ZERO
  write (*, '(I2.2,RZ,F4.3)') int(f), f-int(f)
  write (*, '(RZ,F6.3,TL6,I2.2,TR4)') f,int(f)
end program
05.000          < WRONG
051.000         < VERY WRONG
05****          < EUH
05.999          < OFF BY 0.001
05.999          < OFF BY 0.001

The last method might be of interest, but it is not really the expected value. However, it has the same accuracy.

The following two methods work as expected, but it is required to do manual manipulate the numbers with the respected accuracy. This is not what one would expect:

program test_rounding
  double precision :: f
  f = 6 - 1D-6
  ! manual manipulation
  write (*,'(I2.2,".",I3.3)') nint(f*1D3)/1000, mod(nint(f*1D3),1000)
  write (*,'(F6.3,TL6,I2.2,TR4)') f,nint(f*1D3)/1000
end program

Both return 06.000

kvantour
  • 25,269
  • 4
  • 47
  • 72
0

I do not believe that there is an edit descriptor that does what you want, but you could simulate it with an if-statement:

if(var < 10) then
   write(*,'(a,f6.4)') '00',var
else if(var < 100) then
   write(*,'(a,f7.4)') '0',var
else
   write(*,'(f8.4)') var
endif
Kyle Kanos
  • 3,257
  • 2
  • 23
  • 37
  • If a value is nearly 10, say 9.999999, will the `write` statement format it as “10.0000”, thus producing output of “0010.0000” instead of the desired “010.0000”? – Eric Postpischil Jul 26 '13 at 17:01
  • It will give the desired `010.0000`, but if you have `9.9999`, it will output `009.9999`. – Kyle Kanos Jul 26 '13 at 17:04
  • How does that work? Would not 9.999999 pass the test `var < 10`, resulting in writing “00” followed by “10.0000”? – Eric Postpischil Jul 26 '13 at 17:16
  • I just tested it & it worked that way; I presume it is due to the precision (using `REAL`). If I use `9.99999`, it returns `00******`. – Kyle Kanos Jul 26 '13 at 17:23