如何用前导零填充Fortran浮点输出?

时间:2013-07-26 16:23:57

标签: floating-point formatting fortran

我需要从Fortran程序输出一些浮点数。让我们说最大数字可能是999.9999,它们都是非负数。我需要在所有小于100的数字前面进行零填充。

例如,如果我有25.6893782,245.354567和1.2345678,我需要以类似

的形式打印出来
025.6894
245.3546
001.2346

我该怎么做?使用T编辑描述符会相当容易,例如,我知道所有数字都在10到99之间,就像那样。但是我没办法提前知道。

5 个答案:

答案 0 :(得分:11)

这对我有用

real :: areal

然后

write(*,'(i3.3,f0.6)') int(areal),areal-int(areal)

答案 1 :(得分:2)

可以对整数字段执行零填充,因此如果您将结果打印为两个单独的字段,您可能能够实现它。这是一种不太漂亮的方式,但有效。说x是您要打印的值:

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被声明为CHARACTER*6,因为它需要保存数字的小数部分(小数点后4位),前导零和小数点。如果你想显示更多小数位,这可以很容易地改变,但如果你想显示可变数量的小数位,那将会更加棘手。

I3.3字段描述符表示"打印一个最大字段宽度为3的整数,并用零填充左边,这样总有3个数字"。打印出值时,我们会y(2:5)去掉前导零。

快乐的编码!

答案 2 :(得分:1)

这是我在70年代后期在Commodore PET上用于MS BASIC的技巧。代码已针对负数进行了修改。如果你想要正数来得+,只需将signchr的最后一个字符改为'+'

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

编辑 - 以字符串形式返回结果

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

答案 3 :(得分:1)

High Performance Mark方法的另一种方法是使用TLTR位置编辑描述符。首先使用Fw.d打印浮点,向后移动 w 位置,打印填充零和宽度为 w − d 的整数,移动 d + 1 < / em>向前定位。

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

此方法和High Performance Mark的方法存在的问题是舍入。下面的程序演示了这一点:

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

最后一个方法可能很有趣,但实际上并不是期望值。但是,它具有相同的准确性。

以下两种方法可以正常工作,但是需要以尊重的准确性手动操作数字。这不是人们所期望的:

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

两个都返回06.000

答案 4 :(得分:0)

我不相信有edit descriptor符合您的要求,但您可以使用if语句模拟它:

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