【问题标题】:Printing a Fortran array with an implicit loop使用隐式循环打印 Fortran 数组
【发布时间】:2016-08-17 16:51:35
【问题描述】:

该程序未成功地尝试使用格式规范中的隐式循环在一行上打印一个数组。它通过显式循环成功地完成了这项工作。

program cycle
    implicit none
    integer, dimension(5) :: a=(/1,2,3,4,5/), b=(/11,12,13,14,15/)
    integer :: n, i

    Print *, "Implicit loop"
    print "(i0, 1x)", (a(i)*b(i), i=1,n)
    Print *, "Explicit loop"
    do i=1,n-1
        write(*, '(i0, 1x)', advance = "no") a(i)*b(i)
    end do
    write(*, '(i0)') a(n)*b(n)
end program cycle

结果如下:

 Implicit loop
11
24
39
 Explicit loop
11 24 39

如何使隐式循环在一行上打印所有内容?甚至可能吗?我尝试插入advance="no",并用各种逗号和括号括起来,但没有奏效。

【问题讨论】:

  • 我很惊讶程序会打印任何东西,因为 n 从未被赋予值。
  • 你的阵列结构伤害了我的眼睛。既然a 从未被修改过,为什么不使用integer, parameter :: a(*)= [1, 2, 3, 4, 5]
  • n的省略确实是一个错误。这是我在 WIndows 下编译名为 m.exe 的可执行文件的命令行: gfortran mullist2q2.f90 -o m 我的问题:我应该使用任何编译器标志来捕获此类错误吗?您有什么工具可以推荐用于检查 Fortran 源代码吗?
  • jlokimlin,感谢方括号。我正在尝试使用 Fortran 的“现代子集”。我发现 Walter S. Brainerd 的“Fortran 2008 编程指南”是一份有价值但简明的指南。他也显示方括号。我养成了上网找代码的坏习惯。
  • @wander95,在问题中编辑代码时请非常小心。是的,缺少的n 很重要,但是您所做的更改使代码无法编译。虽然您当时没有评论权限,但最好通过请求作者澄清来完成此类事情(如高性能标记的评论)。

标签: arrays printing formatting fortran


【解决方案1】:

你的格式字符串只支持两个项目,一个整数和一个空格。之后开始一条新记录并从头开始解释格式字符串。

(i0, 1x)

您必须将其转换为多个项目

(999(i0, 1x))

或(Fortran 2008)

(*(i0, 1x))

然后括号的使用次数与前面的数字一样多。 * 表示无限期。当然,只要 i/o 列表中还有项目需要处理。

【讨论】:

  • 谢谢,弗拉基米尔。我在学习 Fortran 方面又进了一步。这正是我一直在努力做的事情。
【解决方案2】:

目前,我无法发布 cmets,因为我的声誉较低,因此将其写为答案。弗拉基米尔的回答是完美的。但要添加到该答案,您还可以执行以下操作:

         integer, parameter :: n=5    ! this line was missing in the question
         write(fmt, 5)n , "(i0, 1x)"
  5      format('(', I2, A9, ')')
         write(*,*)"Implicit loop, formatted"
         write(*, fmt) (a(i)*b(i), i=1,n)

对于显式循环,您可以在 Fortran 2003 或更高版本中使用 new_line 执行以下操作:

    Print *, "Explicit loop 2"
    do i=1,n  ! notice the loop ends at 'n'
        write(*, '(i0, 1x)', advance = "no") a(i)*b(i)
    end do
    write(*, *) new_line('')

这适用于 intel 和 gfortran。

【讨论】:

  • 如果原始代码中不存在 FORMAT 语句,我不会真正在 2016 年引入它。我发现在写入另一个格式字符串时,特别是在这种组合中很难阅读。但更重要的是,它只是更多的工作,这不是必需的,一个大的常数就足够了,所以为什么要麻烦。
  • 谢谢 Wander95,我运行了你的代码,它工作正常。您的代码和 Vladimir 对我的隐式循环的修改的有趣特性是末尾缺少最后一个空格。为了用显式循环实现同样的目的,我有第二个 write 语句。我假设这个属性是标准行为,而不是依赖于编译器。这是真的吗?。
  • 我添加了一个显式循环示例,您可以在其中使用 Fortran 2003 的 new_line() 编写换行符。
  • 在一些非前进输出后前进到下一条记录只需使用write (unit, "()")。在一般情况下,将 new_line() 写入顺序格式化文件是没有意义的。
【解决方案3】:

首先,非高级 I/O 只能在外部文件上执行,不能用于名称列表或列表导向 I/O。

其次,可以将重复计数应用于一组编辑描述符, 括在括号中:

print '(4(i5,f10.3))', (bar(j), foo(j), j=1,4)

(对于整数 bar 和实数 foo)。这相当于写

print '(i5,f10.3,i5,f10.3,i5,f10.3,i5,f10.3)', (bar(j), foo(j), j=1,4)

这样的重复计数可能是嵌套的:

print '(2(2i5,2f10.3))', bar(1),bar(2),foo(1),foo(2),bar(3),bar(4),foo(3),foo(4)

第三,可以通过三种方式给出format 规范。它们如下:

(1) 一个默认的字符表达式(我有偏见的最佳方法):

print '(f10.3)', foo
write(*, '(f10.3)') foo

character(len=*), parameter :: FMT='(f10.3)'

print FMT, foo
write(*, FMT) foo

character, parameter :: FMT_ARRAY(*)=[ '(','f','1','0','.','3',')' ]

! Elements of an array expression are concatenated.
print FMT_ARRAY, foo
write(*, FMT_ARRAY) foo 

or

character(4) :: fmt_1(10)
character(3) :: fmt_2(10)
integer      :: i, j

fmt_1(10) = '(f10'
fmt_2(3) = '.3)'

i = 10
j = 3

! Format is built dynamically at execution time from various components.
print fmt_11(i)//fmt_2(j), foo 
write(*, fmt_11(i)//fmt_2(j)) foo 

(2) 星号(仅在代码的测试/开发阶段使用):

print *, foo
write(*,*) foo

(3) 声明标签(今天不是撒旦!2016 年没有这个位置):

    print 42, foo
    write(*, 42) foo

42 format(f10.3)

【讨论】:

  • 您是想在这里回答吗?这似乎与问题不太相关。
  • @francescalus 为了完整起见,将其包括在内。大多数新的 Fortraner(包括我自己)不知道任何替代标记为 format 的语句或非高级 I/O 仅限于外部文件的替代方法。
  • 欣赏您提供的示例,为我阐明了有些模糊的格式主题。我仍然需要帮助的一个领域是:对于实数,我一直得到 -.462 而不是 -0.462。如何获得单个前导零?
  • @Fishsticks 获得单个前导零取决于您使用的精度。也就是说,对于 32 位单精度(默认)print '(e13.6e2)', x,对于 64 位双精度 print '(e23.15e3)', x,如果您的编译器支持 128 位四精度,print '(e42.33e4)', x。您可以从内部模块ISO_Fortran_env 中获取基于存储的kind 参数。
猜你喜欢
  • 1970-01-01
  • 2013-02-20
  • 2017-05-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-01-31
相关资源
最近更新 更多