diff --git a/fortran90.html.markdown b/fortran.html.markdown similarity index 50% rename from fortran90.html.markdown rename to fortran.html.markdown index 2f2cfdfd..316f8c87 100644 --- a/fortran90.html.markdown +++ b/fortran.html.markdown @@ -11,9 +11,9 @@ Translation"). Despite its age, it is still used for high-performance computing such as weather prediction. However, the language has changed considerably over the years, although mostly maintaining backwards compatibility; well known versions are FORTRAN 77, Fortran 90, Fortran 95, Fortran 2003, Fortran 2008, -Fortran 2015, and Fortran 2018. +Fortran 2018 and Fortran 2023. -This overview will discuss the features of Fortran 95 since it is the most +This overview will discuss the features of Fortran 2008 since it is the most widely implemented of the more recent specifications and the later versions are largely similar (by comparison FORTRAN 77 is a very different language). @@ -21,158 +21,147 @@ largely similar (by comparison FORTRAN 77 is a very different language). ! This is a comment. - -program example !declare a program called example. +program example ! declare a program called example. ! Code can only exist inside programs, functions, subroutines or modules. ! Using indentation is not required but it is recommended. - ! Declaring Variables ! =================== ! All declarations must come before statements and expressions. - implicit none !prevents dynamic declaration of variables (recommended!) + implicit none ! prevents dynamic declaration of variables (recommended!) ! Implicit none must be redeclared in every function/program/module... ! IMPORTANT - Fortran is case insensitive. real z REAL Z2 - real :: v,x ! WARNING: default initial values are compiler dependent! - real :: a = 3, b=2E12, c = 0.01 - integer :: i, j, k=1, m - real, parameter :: PI = 3.1415926535897931 !declare a constant. - logical :: y = .TRUE. , n = .FALSE. !boolean type. - complex :: w = (0,1) !sqrt(-1) - character (len=3) :: month !string of 3 characters. + real :: v, x ! WARNING: default initial values are compiler dependent! + real :: a = 3, b = 2E12, c = 0.01 + integer :: i, j, k = 1, m + real, parameter :: PI = 3.1415926535897931 ! declare a constant. + logical :: y = .TRUE., n = .FALSE. ! boolean type. + complex :: w = (0, 1) ! sqrt(-1) + character(len=3) :: month ! string of 3 characters. - real :: array(6) !declare an array of 6 reals. - real, dimension(4) :: arrayb !another way to declare an array. - integer :: arrayc(-10:10) !an array with a custom index. - real :: array2d(3,2) !multidimensional array. + real :: array(6) ! declare an array of 6 reals. + real, dimension(4) :: arrayb ! another way to declare an array. + integer :: arrayc(-10:10) ! an array with a custom index. + real :: array2d(3, 2) ! multidimensional array. ! The '::' separators are not always necessary but are recommended. ! many other variable attributes also exist: - real, pointer :: p !declare a pointer. + real, pointer :: p ! declare a pointer. integer, parameter :: LP = selected_real_kind(20) - real (kind = LP) :: d !long precision variable. + real(kind=LP) :: d ! long precision variable. ! WARNING: initialising variables during declaration causes problems ! in functions since this automatically implies the 'save' attribute ! whereby values are saved between function calls. In general, separate ! declaration and initialisation code except for constants! - ! Strings ! ======= character :: a_char = 'i' - character (len = 6) :: a_str = "qwerty" - character (len = 30) :: str_b - character (len = *), parameter :: a_long_str = "This is a long string." + character(len=6) :: a_str = "qwerty" + character(len=30) :: str_b + character(len=*), parameter :: a_long_str = "This is a long string." !can have automatic counting of length using (len=*) but only for constants. - str_b = a_str // " keyboard" !concatenate strings using // operator. - + str_b = a_str//" keyboard" ! concatenate strings using // operator. ! Assignment & Arithmetic ! ======================= - Z = 1 !assign to variable z declared above (case insensitive). + Z = 1 ! assign to variable z declared above (case insensitive). j = 10 + 2 - 3 - a = 11.54 / (2.3 * 3.1) - b = 2**3 !exponentiation - + a = 11.54/(2.3*3.1) + b = 2**3 ! exponentiation ! Control Flow Statements & Operators ! =================================== ! Single-line if statement - if (z == a) b = 4 !condition always need surrounding parentheses. + if (z == a) b = 4 ! condition always need surrounding parentheses. - if (z /= a) then !z not equal to a - ! Other symbolic comparisons are < > <= >= == /= - b = 4 - else if (z .GT. a) then !z greater than a - ! Text equivalents to symbol operators are .LT. .GT. .LE. .GE. .EQ. .NE. - b = 6 - else if (z < a) then !'then' must be on this line. - b = 5 !execution block must be on a new line. + if (z /= a) then ! z not equal to a + ! Other symbolic comparisons are < > <= >= == /= + b = 4 + else if (z .GT. a) then ! z greater than a + ! Text equivalents to symbol operators are .LT. .GT. .LE. .GE. .EQ. .NE. + b = 6 + else if (z < a) then ! 'then' must be on this line. + b = 5 ! execution block must be on a new line. else - b = 10 - end if !end statement needs the 'if' (or can use 'endif'). - - - if (.NOT. (x < c .AND. v >= a .OR. z == z)) then !boolean operators. - inner: if (.TRUE.) then !can name if-construct. - b = 1 - endif inner !then must name endif statement. - endif + b = 10 + end if ! end statement needs the 'if' (or can use 'endif'). + if (.NOT. (x < c .AND. v >= a .OR. z == z)) then ! boolean operators. + inner: if (.TRUE.) then ! can name if-construct. + b = 1 + end if inner ! then must name endif statement. + end if i = 20 select case (i) - case (0) !case i == 0 - j=0 - case (1:10) !cases i is 1 to 10 inclusive. - j=1 - case (11:) !all cases where i>=11 - j=2 - case default - j=3 + case (0, 1) ! cases i == 0 or i == 1 + j = 0 + case (2:10) ! cases i is 2 to 10 inclusive. + j = 1 + case (11:) ! all cases where i>=11 + j = 2 + case default + j = 3 end select - month = 'jan' ! Condition can be integer, logical or character type. ! Select constructions can also be named. - monthly: select case (month) - case ("jan") - j = 0 - case default - j = -1 + monthly:select case(month) + case ("jan") + j = 0 + case default + j = -1 end select monthly - - do i=2,10,2 !loops from 2 to 10 (inclusive) in increments of 2. - innerloop: do j=1,3 !loops can be named too. - exit !quits the loop. - end do innerloop - cycle !jump to next loop iteration. - enddo - + do i = 2, 10, 2 ! loops from 2 to 10 (inclusive) in increments of 2. + innerloop: do j = 1, 3 ! loops can be named too. + exit ! quits the loop. + end do innerloop + cycle ! jump to next loop iteration. + end do ! Goto statement exists but it is heavily discouraged though. goto 10 - stop 1 !stops code immediately (returning specified condition code). -10 j = 201 !this line is labeled as line 10 - + stop 1 ! stops code immediately (returning specified condition code). +10 j = 201 ! this line is labeled as line 10 ! Arrays ! ====== - array = (/1,2,3,4,5,6/) - array = [1,2,3,4,5,6] !using Fortran 2003 notation. - arrayb = [10.2,3e3,0.41,4e-5] - array2d = reshape([1.0,2.0,3.0,4.0,5.0,6.0], [3,2]) + array = (/1, 2, 3, 4, 5, 6/) + array = [1, 2, 3, 4, 5, 6] ! using Fortran 2003 notation. + arrayb = [10.2, 3e3, 0.41, 4e-5] + array2d = reshape([1.0, 2.0, 3.0, 4.0, 5.0, 6.0], [3, 2]) ! Fortran array indexing starts from 1. ! (by default but can be defined differently for specific arrays). - v = array(1) !take first element of array. - v = array2d(2,2) + v = array(1) ! take first element of array. + v = array2d(2, 2) - print *, array(3:5) !print all elements from 3rd to 5th (inclusive). - print *, array2d(1,:) !print first column of 2d array. + print *, array(3:5) ! print all elements from 3rd to 5th (inclusive). + print *, array2d(1, :) ! print first column of 2d array. - array = array*3 + 2 !can apply mathematical expressions to arrays. - array = array*array !array operations occur element-wise. - !array = array*array2d !these arrays would not be compatible. + array = array*3 + 2 ! can apply mathematical expressions to arrays. + array = array*array ! array operations occur element-wise. + ! array = array*array2d ! these arrays would not be compatible. ! There are many built-in functions that operate on arrays. - c = dot_product(array,array) !this is the dot product. + c = dot_product(array, array) ! this is the dot product. ! Use matmul() for matrix maths. c = sum(array) c = maxval(array) @@ -188,74 +177,73 @@ program example !declare a program called example. end do ! Conditionally execute element-wise assignments. - array = [1,2,3,4,5,6] + array = [1, 2, 3, 4, 5, 6] where (array > 3) array = array + 1 - elsewhere (array == 2) + elsewhere(array == 2) array = 1 elsewhere array = 0 end where ! Implied-DO loops are a compact way to create arrays. - array = [ (i, i = 1,6) ] !creates an array of [1,2,3,4,5,6] - array = [ (i, i = 1,12,2) ] !creates an array of [1,3,5,7,9,11] - array = [ (i**2, i = 1,6) ] !creates an array of [1,4,9,16,25,36] - array = [ (4,5, i = 1,3) ] !creates an array of [4,5,4,5,4,5] - + array = [(i, i=1, 6)] ! creates an array of [1,2,3,4,5,6] + array = [(i, i=1, 12, 2)] ! creates an array of [1,3,5,7,9,11] + array = [(i**2, i=1, 6)] ! creates an array of [1,4,9,16,25,36] + array = [(4, 5, i=1, 3)] ! creates an array of [4,5,4,5,4,5] ! Input/Output ! ============ - print *, b !print the variable 'b' to the command line + print *, b ! print the variable 'b' to the command line ! We can format our printed output. - print "(I6)", 320 !prints ' 320' - print "(I6.4)", 3 !prints ' 0003' - print "(F6.3)", 4.32 !prints ' 4.320' + print "(I6)", 320 ! prints ' 320' + print "(I6.4)", 3 ! prints ' 0003' + print "(F6.3)", 4.32 ! prints ' 4.320' ! The letter indicates the expected type and the number afterwards gives ! the number of characters to use for printing the value. ! Letters can be I (integer), F (real), E (engineering format), ! L (logical), A (characters) ... - print "(I3)", 3200 !print '***' since the number doesn't fit. + print "(I3)", 3200 ! print '***' since the number doesn't fit. ! we can have multiple format specifications. print "(I5,F6.2,E6.2)", 120, 43.41, 43.41 - print "(3I5)", 10, 20, 30 !3 repeats of integers (field width = 5). - print "(2(I5,F6.2))", 120, 43.42, 340, 65.3 !repeated grouping of formats. + print "(3I5)", 10, 20, 30 ! 3 repeats of integers (field width = 5). + print "(2(I5,F6.2))", 120, 43.42, 340, 65.3 ! repeated grouping of formats. ! We can also read input from the terminal. - read *, v - read "(2F6.2)", v, x !read two numbers - - ! To read a file. - open(unit=11, file="records.txt", status="old") - ! The file is referred to by a 'unit number', an integer that you pick in - ! the range 9:99. Status can be one of {'old','replace','new'}. - read(unit=11, fmt="(3F10.2)") a, b, c - close(11) + read (*, *) v + read (*, "(2F6.2)") v, x ! read two numbers ! To write a file. - open(unit=12, file="records.txt", status="replace") - write(12, "(F10.2,F10.2,F10.2)") c, b, a - close(12) + open (unit=12, file="records.txt", status="replace") + ! The file is referred to by a 'unit number', an integer that you pick in + ! the range 9:99. Status can be one of {'old','replace','new'}. + write (12, "(F10.2,F10.2,F10.2)") c, b, a + close (12) + + ! To read a file. + open (newunit=m, file="records.txt", status="old") + ! The file is referred to by a 'new unit number', an integer that the compiler + ! picks for you. + read (unit=m, fmt="(3F10.2)") a, b, c + close (m) ! There are more features available than discussed here and alternative ! variants due to backwards compatibility with older Fortran versions. - ! Built-in Functions ! ================== ! Fortran has around 200 functions/subroutines intrinsic to the language. ! Examples - - call cpu_time(v) !sets 'v' to a time in seconds. - k = ior(i,j) !bitwise OR of 2 integers. - v = log10(x) !log base 10. - i = floor(b) !returns the closest integer less than or equal to x. - v = aimag(w) !imaginary part of a complex number. - + call cpu_time(v) ! sets 'v' to a time in seconds. + k = ior(i, j) ! bitwise OR of 2 integers. + v = log10(x) ! log base 10. + i = floor(b) ! returns the closest integer less than or equal to x. + v = aimag(w) ! imaginary part of a complex number. ! Functions & Subroutines ! ======================= @@ -263,70 +251,69 @@ program example !declare a program called example. ! A subroutine runs some code on some input values and can cause ! side-effects or modify the input values. - call routine(a,c,v) !subroutine call. + call routine(a, c, v) ! subroutine call. ! A function takes a list of input parameters and returns a single value. ! However the input parameters may still be modified and side effects ! executed. - m = func(3,2,k) !function call. + m = func(3, 2, k) ! function call. ! Function calls can also be evoked within expressions. - Print *, func2(3,2,k) + print *, func2(3, 2, k) ! A pure function is a function that doesn't modify its input parameters ! or cause any side-effects. - m = func3(3,2,k) + m = func3(3, 2, k) - -contains ! Zone for defining sub-programs internal to the program. +contains ! Zone for defining sub-programs internal to the program. ! Fortran has a couple of slightly different ways to define functions. - integer function func(a,b,c) !a function returning an integer value. - implicit none !best to use implicit none in function definitions too. - integer :: a,b,c !type of input parameters defined inside the function. + integer function func(a, b, c) ! a function returning an integer value. + ! implicit none ! subvariable fields can no longer declare implicit none + integer, intent(in) :: a, b, c ! type of input parameters defined inside the function. + if (a >= 2) then - func = a + b + c !the return variable defaults to the function name. - return !can return the current value from the function at any time. - endif + func = a + b + c ! the return variable defaults to the function name. + return ! can return the current value from the function at any time. + end if func = a + c + ! Don't need a return statement at the end of a function. end function func - - function func2(a,b,c) result(f) !return variable declared to be 'f'. - implicit none - integer, intent(in) :: a,b !can declare and enforce that variables - !are not modified by the function. + function func2(a, b, c) result(f) ! return variable declared to be 'f'. + integer, intent(in) :: a, b ! can declare and enforce that variables + !are not modified by the function. integer, intent(inout) :: c - integer :: f !function return type declared inside the function. - integer :: cnt = 0 !GOTCHA - initialisation implies variable is - !saved between function calls. + integer :: f ! function return type declared inside the function. + integer :: cnt = 0 ! GOTCHA - initialisation implies variable is + !saved between function calls. + f = a + b - c - c = 4 !altering the value of an input variable. - cnt = cnt + 1 !count number of function calls. + c = 4 ! altering the value of an input variable. + cnt = cnt + 1 ! count number of function calls. + end function func2 - - pure function func3(a,b,c) !a pure function can have no side-effects. - implicit none - integer, intent(in) :: a,b,c + pure function func3(a, b, c) ! a pure function can have no side-effects. + integer, intent(in) :: a, b, c integer :: func3 + func3 = a*b*c + end function func3 - - subroutine routine(d,e,f) - implicit none + subroutine routine(d, e, f) real, intent(inout) :: f - real, intent(in) :: d,e + real, intent(in) :: d, e + f = 2*d + 3*e + f + end subroutine routine - -end program example ! End of Program Definition ----------------------- - +end program example ! End of Program Definition ----------------------- ! Functions and Subroutines declared externally to the program listing need ! to be declared to the program using an Interface declaration (even if they @@ -338,9 +325,10 @@ elemental real function func4(a) result(res) ! but can also be used on an array where it will be separately applied to all ! of the elements of an array and return a new array. real, intent(in) :: a - res = a**2 + 1.0 -end function func4 + res = a**2 + 1.0 + +end function func4 ! Modules ! ======= @@ -349,22 +337,23 @@ end function func4 ! subroutines together for reusability. module fruit + real :: apple real :: pear real :: orange -end module fruit +end module fruit module fruity ! Declarations must be in the order: modules, interfaces, variables. ! (can declare modules and interfaces in programs too). use fruit, only: apple, pear ! use apple and pear from fruit module. - implicit none !comes after module imports. + implicit none ! comes after module imports. - private !make things private to the module (default is public). + private ! make things private to the module (default is public). ! Declare some variables/functions explicitly public. - public :: apple,mycar,create_mycar + public :: apple, mycar, create_mycar ! Declare some variables/functions private to the module (redundant here). private :: func4 @@ -389,13 +378,15 @@ module fruity ! ================== ! Can create custom structured data collections. type car - character (len=100) :: model - real :: weight !(kg) - real :: dimensions(3) !i.e. length-width-height (metres). + character(len=100) :: model + real :: weight ! (kg) + real :: dimensions(3) ! i.e. length-width-height (metres). character :: colour + contains + procedure :: info ! bind a procedure to a type. end type car - type(car) :: mycar !declare a variable of your custom type. + type(car) :: mycar ! declare a variable of your custom type. ! See create_mycar() routine for usage. ! Note: There are no executable statements in modules. @@ -404,35 +395,48 @@ contains subroutine create_mycar(mycar) ! Demonstrates usage of a derived data type. - implicit none - type(car),intent(out) :: mycar + type(car), intent(out) :: mycar ! Access type elements using '%' operator. mycar%model = "Ford Prefect" mycar%colour = 'r' mycar%weight = 1400 - mycar%dimensions(1) = 5.0 !default indexing starts from 1! + mycar%dimensions(1) = 5.0 ! default indexing starts from 1! mycar%dimensions(2) = 3.0 mycar%dimensions(3) = 1.5 - end subroutine + end subroutine create_mycar - real function real_abs(x) - real :: x - if (x<0) then + subroutine info(self) + class(car), intent(in) :: self + ! 'class' keyword used to bind a procedure to a type here. + + print *, "Model : ", self%model + print *, "Colour : ", self%colour + print *, "Weight : ", self%weight + print *, "Dimensions: ", self%dimensions + + end subroutine info + + real pure function real_abs(x) + real, intent(in) :: x + + if (x < 0) then real_abs = -x else real_abs = x end if + end function real_abs - real function complex_abs(z) - complex :: z + real pure function complex_abs(z) + complex, intent(in) :: z ! long lines can be continued using the continuation character '&' - complex_abs = sqrt(real(z)**2 + & - aimag(z)**2) - end function complex_abs + complex_abs = sqrt(real(z)**2 + & + aimag(z)**2) + + end function complex_abs end module fruity diff --git a/zh-cn/fortran-cn.html.markdown b/zh-cn/fortran-cn.html.markdown new file mode 100644 index 00000000..ab521e0a --- /dev/null +++ b/zh-cn/fortran-cn.html.markdown @@ -0,0 +1,444 @@ +--- +language: Fortran +filename: learnfortran-cn.f90 +contributors: + - ["Robert Steed", "https://github.com/robochat"] +translators: + - ["Corvusnest", "https://github.com/Corvusnest"] +lang: zh-cn +--- + +Fortran 是最古老的计算机语言之一。它由 IBM 开发于 1950 年用于数值运算(Fortran 为 "Formula +Translation" 的缩写)。虽然该语言已年代久远,但目前仍用于高性能计算,如天气预报。 +该语言仍在持续发展,并且基本保持向下兼容。知名的版本为 Fortran 77, Fortran 90, +Fortran 95, Fortran 2008, Fortran 2015 和 Fortran 2023。 + +这篇概要将讨论 Fortran 2008 的一些特征。因为它是目前所广泛采用的标准版本,并且与最新版本的内容 +也基本相同(而 Fortran 77 则是一个非常不同的版本)。 + +```fortran +! 这是一个注释 + +program example ! 声明一个名为 example 的程序 + + ! 代码只能存在于程序、函数、子程序或模块中 + ! 使用缩进不是必需的,但推荐使用 + + ! 声明变量 + ! ========= + + ! 所有的声明必须在语句和表达式之前 + + implicit none ! 防止动态声明变量(推荐!) + ! implicit none 推荐在每个函数/程序/模块中重新声明... + + ! 注意 - Fortran 中对大小写不敏感 + real z + REAL Z2 + + real :: v, x ! 警告:默认的初始值取决于编译器! + real :: a = 3, b = 2E12, c = 0.01 + integer :: i, j, k = 1, m + real, parameter :: PI = 3.1415926535897931 ! 声明一个常数 + logical :: y = .TRUE., n = .FALSE. ! 布尔类型 + complex :: w = (0, 1) ! 单位虚数 + character(len=3) :: month ! 字符串,长度为 3 个字符 + + real :: array(6) ! 声明一个包含 6 个实数的数组 + real, dimension(4) :: arrayb ! 另一种声明数组的方式 + integer :: arrayc(-10:10) ! 具有自定义索引的数组 + real :: array2d(3, 2) ! 多维数组 + + ! 这些分隔符 '::' 并不总是必需的,但推荐使用 + + ! 还有许多其他的变量属性: + real, pointer :: p ! 声明一个指针 + + integer, parameter :: LP = selected_real_kind(20) + real(kind=LP) :: d ! 长精度变量 + + ! 警告:在声明过程中初始化变量会在函数中造成问题, + ! 因为这会自动暗示 'save' 属性, + ! 在函数调用之间保存变量的值一般情况下, + ! 除了常量外,声明和初始化的代码应该分开! + + ! 字符串 + ! ======= + + character :: a_char = 'i' + character(len=6) :: a_str = "qwerty" + character(len=30) :: str_b + character(len=*), parameter :: a_long_str = "This is a long string." + ! 使用 (len=*) 可以自动计算长度,但只适用于常量 + + str_b = a_str//" keyboard" ! 使用 // 运算符连接字符串 + + ! 赋值和算术 + ! ============= + + Z = 1 ! 对上面声明的变量 z 进行赋值(对大小写不敏感) + j = 10 + 2 - 3 + a = 11.54/(2.3*3.1) + b = 2**3 ! 幂运算 + + ! 流程控制语句和操作符 + ! =================== + + ! 单行 if 语句 + if (z == a) b = 4 ! 条件始终需要在括号中 + + if (z /= a) then ! z 不等于 a + ! 其他的比较操作符包括 < > <= >= == /= + b = 4 + else if (z .GT. a) then ! z 大于 a + ! 文本等价于符号操作符中的 .LT. .GT. .LE. .GE. .EQ. .NE. + b = 6 + else if (z < a) then ! 'then' 必须在本行上 + b = 5 ! 执行块必须在新的一行上 + else + b = 10 + end if ! end 语句后需要 'if'(或可以使用 'endif') + + if (.NOT. (x < c .AND. v >= a .OR. z == z)) then ! 布尔运算符 + inner: if (.TRUE.) then ! 可以对 if 结构命名 + b = 1 + end if inner ! then 必须命名对应的 endif 语句 + end if + + i = 20 + select case (i) + case (0, 1) ! 当 i == 0 或 i == 1 时 + j = 0 + case (2:10) ! 当 i 在 2 到 10 之间(包括边界)时 + j = 1 + case (11:) ! 当 i >= 11 时 + j = 2 + case default + j = 3 + end select + + month = 'jan' + ! 条件可以是整数、逻辑、或字符类型 + ! Select 结构也可以命名 + monthly:select case(month) + case ("jan") + j = 0 + case default + j = -1 + end select monthly + + do i = 2, 10, 2 ! 循环从 2 到 10(包括)以 2 为步长 + innerloop: do j = 1, 3 ! 循环也可以命名 + exit ! 退出循环 + end do innerloop + cycle ! 跳到下一个循环迭代 + end do + + ! 虽然存在 Goto 语句,但它被强烈不推荐 + goto 10 + stop 1 ! 立即停止代码(并返回指定的条件代码) +10 j = 201 ! 这一行被标记为 10 行 + + ! 数组 + ! ===== + array = (/1, 2, 3, 4, 5, 6/) + array = [1, 2, 3, 4, 5, 6] ! 使用 Fortran 2003 的表示法 + arrayb = [10.2, 3e3, 0.41, 4e-5] + array2d = reshape([1.0, 2.0, 3.0, 4.0, 5.0, 6.0], [3, 2]) + + ! Fortran 数组索引从 1 开始 + ! (默认情况下,但对于特定数组可以定义不同的索引) + v = array(1) ! 取数组的第一个元素 + v = array2d(2, 2) + + print *, array(3:5) ! 打印从第三个到第五个元素(包括) + print *, array2d(1, :) ! 打印二维数组的第一列 + + array = array*3 + 2 ! 可以对数组应用数学表达式 + array = array*array ! 数组操作是逐元素进行的 + ! array = array*array2d ! 这两个数组是不兼容的 + + ! 有许多内置函数可用于数组 + c = dot_product(array, array) ! 这是点积 + ! 使用 matmul() 进行矩阵运算 + c = sum(array) + c = maxval(array) + print *, minloc(array) + c = size(array) + print *, shape(array) + m = count(array > 0) + + ! 循环数组(通常使用 product() 函数) + v = 1 + do i = 1, size(array) + v = v*array(i) + end do + + ! 条件性地执行逐元素赋值 + array = [1, 2, 3, 4, 5, 6] + where (array > 3) + array = array + 1 + elsewhere(array == 2) + array = 1 + elsewhere + array = 0 + end where + + ! 隐含 do 循环是创建数组的紧凑方式 + array = [(i, i=1, 6)] ! 创建一个数组 [1,2,3,4,5,6] + array = [(i, i=1, 12, 2)] ! 创建一个数组 [1,3,5,7,9,11] + array = [(i**2, i=1, 6)] ! 创建一个数组 [1,4,9,16,25,36] + array = [(4, 5, i=1, 3)] ! 创建一个数组 [4,5,4,5,4,5] + + ! 输入/输出 + ! ========= + + print *, b ! 将变量 'b' 打印到命令行 + + ! 可以对打印的输出进行格式化 + print "(I6)", 320 ! 打印 ' 320' + print "(I6.4)", 3 ! 打印 ' 0003' + print "(F6.3)", 4.32 ! 打印 ' 4.320' + + ! 字母表示预期的类型,后面的数字表示用于打印值的字符数 + ! 字母可以是 I(整数),F(实数),E(工程表示法), + ! L(逻辑),A(字符串)... + print "(I3)", 3200 ! 打印 '***',因为该数字不适合 + + ! 可以有多个格式规范 + print "(I5,F6.2,E6.2)", 120, 43.41, 43.41 + print "(3I5)", 10, 20, 30 ! 整数的三次重复(字段宽度为 5) + print "(2(I5,F6.2))", 120, 43.42, 340, 65.3 ! 格式重复组合 + + ! 我们还可以从终端读取输入 + read (*, *) v + read (*, "(2F6.2)") v, x ! 读取两个数字 + + ! 写入文件 + open (unit=12, file="records.txt", status="replace") + ! 文件通过 'unit number' 引用,这个数字可以在 9:99 范围内选择 + ! Status 可以是 {'old','replace','new'} 中的一个 + write (12, "(F10.2,F10.2,F10.2)") c, b, a + close (12) + + ! 读取文件 + open (newunit=m, file="records.txt", status="old") + ! 文件通过 'new unit number' 引用,编译器为您选择一个整数 + read (unit=m, fmt="(3F10.2)") a, b, c + close (m) + + ! 还有更多功能可用,超出了本文所讨论的范围, + ! 还有由于与旧版本的 Fortran 的向后兼容性而存在的替代方案 + + ! 内置函数 + ! =========== + + ! Fortran 大约有 200 个语言内部的函数/子程序 + ! 例如 - + call cpu_time(v) ! 将 'v' 设置为以秒为单位的时间 + k = ior(i, j) ! 两个整数的位 OR 运算 + v = log10(x) ! 以 10 为底的对数 + i = floor(b) ! 返回小于或等于 x 的最接近的整数 + v = aimag(w) ! 复数的虚部 + + ! 函数和子程序 + ! ============== + + ! 子程序运行一些代码,并可以对输入值产生副作用或修改输入值 + + call routine(a, c, v) ! 子程序调用 + + ! 函数采用一系列输入参数,并返回一个单个值 + ! 不过,输入参数可能仍会被修改,并且会执行副作用 + + m = func(3, 2, k) ! 函数调用 + + ! 函数调用还可以在表达式中使用 + print *, func2(3, 2, k) + + ! 一个纯函数是一个不修改其输入参数, + ! 也不会引起任何副作用的函数 + m = func3(3, 2, k) + +contains ! 包含程序内部定义的子程序的区域 + + ! Fortran 有几种稍微不同的方式来定义函数 + + integer function func(a, b, c) ! 函数返回一个整数值 + ! implicit none ! 子变量域可以不再声明 implicit none + integer, intent(in) :: a, b, c ! 在函数内部定义输入参数的类型 + + if (a >= 2) then + func = a + b + c ! 返回变量默认为函数名 + return ! 随时可以从函数返回当前值 + end if + func = a + c + + ! 在函数的末尾不需要 return 语句 + end function func + + function func2(a, b, c) result(f) ! 返回变量声明为 'f' + integer, intent(in) :: a, b ! 可以声明和强制约定变量 + ! 不会被函数修改 + integer, intent(inout) :: c + integer :: f ! 函数返回类型在函数内部声明 + integer :: cnt = 0 ! 注意:初始化暗示变量在函数调用之间保存 + ! + + f = a + b - c + c = 4 ! 修改输入变量的值 + cnt = cnt + 1 ! 计算函数调用的次数 + + end function func2 + + pure function func3(a, b, c) ! 纯函数不能有副作用 + integer, intent(in) :: a, b, c + integer :: func3 + + func3 = a*b*c + + end function func3 + + subroutine routine(d, e, f) + real, intent(inout) :: f + real, intent(in) :: d, e + + f = 2*d + 3*e + f + + end subroutine routine + +end program example ! 程序定义结束-------------------------- + +! 函数和子程序在程序列表之外声明,在程序之间以及模块中声明时,需要使用 interface 声明(即使它们在同一源文件中)(见下面)将它们定义在模块或程序的 'contains' 部分更容易 + +elemental real function func4(a) result(res) +! elemental 函数是一个纯函数,它采用标量输入变量, +! 但也可以在数组上独立应用,并返回一个新的数组 + real, intent(in) :: a + + res = a**2 + 1.0 + +end function func4 + +! 模块 +! ======= + +! 模块是在可重用性中将相关的声明、函数和子程序结合在一起的有用方式 + +module fruit + + real :: apple + real :: pear + real :: orange + +end module fruit + +module fruity + ! 声明的顺序必须是:模块、接口、变量 + !(也可以在程序中声明模块和接口) + + use fruit, only: apple, pear ! 使用 fruit 模块中的 apple 和 pear + implicit none ! 导入模块之后 + + private ! 将一些内容私有化(默认为公共) + ! 显式将一些变量/函数声明为公共 + public :: apple, mycar, create_mycar + ! 将一些变量/函数声明为模块私有(本例中是多余的) + private :: func4 + + ! 接口 + ! ======== + ! 在模块内部(最好放在 'contains' 部分)显式声明外部函数/过程 + interface + elemental real function func4(a) result(res) + real, intent(in) :: a + end function func4 + end interface + + ! 可以使用命名接口定义重载函数 + interface myabs + ! 可以使用 'module procedure' 关键字包括模块内已经定义的函数 + module procedure real_abs, complex_abs + end interface + + ! 派生数据类型 + ! ================== + ! 可以创建自定义的结构化数据集合 + type car + character(len=100) :: model + real :: weight !(千克) + real :: dimensions(3) ! 即,长度-宽度-高度(米) + character :: colour + contains + procedure :: info ! 将过程绑定到类型 + end type car + + type(car) :: mycar ! 声明自定义类型的变量 + ! 请查看 create_mycar() 程序的用法 + + ! 注意:模块中没有可以执行的语句 + +contains + + subroutine create_mycar(mycar) + ! 演示派生数据类型的用法 + type(car), intent(out) :: mycar + + ! 使用 '%' 运算符访问类型元素 + mycar%model = "Ford Prefect" + mycar%colour = 'r' + mycar%weight = 1400 + mycar%dimensions(1) = 5.0 ! 默认索引从 1 开始! + mycar%dimensions(2) = 3.0 + mycar%dimensions(3) = 1.5 + + end subroutine create_mycar + + subroutine info(self) + class(car), intent(in) :: self + ! 使用 'class' 关键字将过程绑定到类型 + + print *, "Model : ", self%model + print *, "Colour : ", self%colour + print *, "Weight : ", self%weight + print *, "Dimensions: ", self%dimensions + + end subroutine info + + real pure function real_abs(x) + real, intent(in) :: x + + if (x < 0) then + real_abs = -x + else + real_abs = x + end if + + end function real_abs + + real pure function complex_abs(z) + complex, intent(in) :: z + ! 长行可以使用继续字符 '&' 进行延续 + + complex_abs = sqrt(real(z)**2 + & + aimag(z)**2) + + end function complex_abs + +end module fruity + +``` + +### 更多资源 + +了解更多的 Fortran 信息: + ++ [wikipedia](https://en.wikipedia.org/wiki/Fortran) ++ [Fortran-lang Organization](https://fortran-lang.org/) ++ [Fortran_95_language_features](https://en.wikipedia.org/wiki/Fortran_95_language_features) ++ [fortranwiki.org](http://fortranwiki.org) ++ [www.fortran90.org/](http://www.fortran90.org) ++ [list of Fortran 95 tutorials](http://www.dmoz.org/Computers/Programming/Languages/Fortran/FAQs%2C_Help%2C_and_Tutorials/Fortran_90_and_95/) ++ [Fortran wikibook](https://en.wikibooks.org/wiki/Fortran) ++ [Fortran resources](http://www.fortranplus.co.uk/resources/fortran_resources.pdf) ++ [Mistakes in Fortran 90 Programs That Might Surprise You](http://www.cs.rpi.edu/~szymansk/OOF90/bugs.html) diff --git a/zh-cn/fortran95-cn.html.markdown b/zh-cn/fortran95-cn.html.markdown deleted file mode 100644 index e28d309f..00000000 --- a/zh-cn/fortran95-cn.html.markdown +++ /dev/null @@ -1,435 +0,0 @@ ---- -language: Fortran -filename: learnfortran-cn.f95 -contributors: - - ["Robert Steed", "https://github.com/robochat"] -translators: - - ["Corvusnest", "https://github.com/Corvusnest"] -lang: zh-cn ---- - -Fortran 是最古老的计算机语言之一。它由IBM开发于1950年用于数值运算(Fortran 为 "Formula -Translation" 的缩写)。虽然该语言已年代久远,但目前仍用于高性能计算,如天气预报。 -该语言仍在持续发展,并且基本保持向下兼容。知名的版本为 Fortran 77, Fortran 90, -Fortran 95, Fortran 2003, Fortran 2008 与 Fortran 2015。 - -这篇概要将讨论 Fortran 95 的一些特征。因为它是目前所广泛采用的标准版本,并且与最新版本的内容 -也基本相同(而 Fortran 77 则是一个非常不同的版本)。 - -```fortran - -! 这是一行注释 - - -program example !声明一个叫做 example 的程序 - - ! 代码只能放在程序、函数、子程序或者模块内部 - ! 推荐使用缩进,但不是必须的。 - - ! 声明变量 - ! =================== - - ! 所有的声明必须放在语句与表达式之前 - - implicit none !阻止变量的隐式声明 (推荐!) - ! Implicit none 必须在每一个 函数/程序/模块 中进行声明 - - ! 重要 - Fortran 对大小写不敏感 - real z - REAL Z2 - - real :: v,x ! 警告: 默认值取决于编译器! - real :: a = 3, b=2E12, c = 0.01 - integer :: i, j, k=1, m - real, parameter :: PI = 3.1415926535897931 !声明一个常量 - logical :: y = .TRUE. , n = .FALSE. !布尔值 - complex :: w = (0,1) !sqrt(-1) (译注: 定义复数,此为-1的平方根) - character (len=3) :: month !长度为3的字符串 - - real :: array(6) !声明长度为6的浮点数数组 - real, dimension(4) :: arrayb !声明数组的另一种方法 - integer :: arrayc(-10:10) !有着自定义索引的数组 - real :: array2d(3,2) !多维数组 - - ! 分隔符 '::' 并不总是必要的,但推荐使用 - - ! 还存在很多其他的变量特征: - real, pointer :: p !声明一个指针 - - integer, parameter :: LP = selected_real_kind(20) - real (kind = LP) :: d !长精度变量 - - ! 警告:在声明期间初始化变量将导致在函数内发生问题,因为这将自动具备了 “save” 属性, - ! 因此变量的值在函数的多次调用期间将被存储。一般来说,除了常量,应分开声明与初始化! - - ! 字符串 - ! ======= - - character :: a_char = 'i' - character (len = 6) :: a_str = "qwerty" - character (len = 30) :: str_b - character (len = *), parameter :: a_long_str = "This is a long string." - !可以通过使用 (len=*) 来自动判断长度,但只对常量有效 - - str_b = a_str // " keyboard" !通过 // 操作符来连接字符串 - - - ! 任务与计算 - ! ======================= - - Z = 1 !向之前声明的变量 z 赋值 (大小写不敏感). - j = 10 + 2 - 3 - a = 11.54 / (2.3 * 3.1) - b = 2**3 !幂 - - - ! 控制流程语句 与 操作符 - ! =================================== - - !单行 if 语句 - if (z == a) b = 4 !判别句永远需要放在圆括号内 - - if (z /= a) then !z 不等于 a - ! 其他的比较运算符: < > <= >= == /= - b = 4 - else if (z .GT. a) then !z 大于(Greater) a - ! 文本形式的比较运算符: .LT. .GT. .LE. .GE. .EQ. .NE. - b = 6 - else if (z < a) then !'then' 必须放在该行 - b = 5 !执行部分必须放在新的一行里 - else - b = 10 - end if !结束语句需要 'if' (也可以用 'endif'). - - - if (.NOT. (x < c .AND. v >= a .OR. z == z)) then !布尔操作符 - inner: if (.TRUE.) then !可以为 if 结构命名 - b = 1 - endif inner !接下来必须命名 endif 语句. - endif - - - i = 20 - select case (i) - case (0) !当 i == 0 - j=0 - case (1:10) !当 i 为 1 到 10 之内 ( 1 <= i <= 10 ) - j=1 - case (11:) !当 i>=11 - j=2 - case default - j=3 - end select - - - month = 'jan' - ! 状态值可以为整数、布尔值或者字符类型 - ! Select 结构同样可以被命名 - monthly: select case (month) - case ("jan") - j = 0 - case default - j = -1 - end select monthly - - do i=2,10,2 !从2到10(包含2和10)以2为步进值循环 - innerloop: do j=1,3 !循环同样可以被命名 - exit !跳出循环 - end do innerloop - cycle !重复跳入下一次循环 - enddo - - - ! Goto 语句是存在的,但强烈不建议使用 - goto 10 - stop 1 !立即停止程序 (返回一个设定的状态码). -10 j = 201 !这一行被标注为 10 行 (line 10) - - - ! 数组 - ! ====== - array = (/1,2,3,4,5,6/) - array = [1,2,3,4,5,6] !当使用 Fortran 2003 版本. - arrayb = [10.2,3e3,0.41,4e-5] - array2d = reshape([1.0,2.0,3.0,4.0,5.0,6.0], [3,2]) - - ! Fortran 数组索引起始于 1 - ! (默认下如此,也可以为数组定义不同的索引起始) - v = array(1) !获取数组的第一个元素 - v = array2d(2,2) - - print *, array(3:5) !打印从第3到第五5之内的所有元素 - print *, array2d(1,:) !打印2维数组的第一列 - - array = array*3 + 2 !可为数组设置数学表达式 - array = array*array !数组操作支持元素级(操作) (element-wise) - !array = array*array2d !这两类数组并不是同一个维度的 - - ! 有很多内置的数组操作函数 - c = dot_product(array,array) !点乘 (点积) - ! 用 matmul() 来进行矩阵运算. - c = sum(array) - c = maxval(array) - print *, minloc(array) - c = size(array) - print *, shape(array) - m = count(array > 0) - - ! 遍历一个数组 (一般使用 Product() 函数). - v = 1 - do i = 1, size(array) - v = v*array(i) - end do - - ! 有条件地执行元素级操作 - array = [1,2,3,4,5,6] - where (array > 3) - array = array + 1 - elsewhere (array == 2) - array = 1 - elsewhere - array = 0 - end where - - ! 隐式DO循环可以很方便地创建数组 - array = [ (i, i = 1,6) ] !创建数组 [1,2,3,4,5,6] - array = [ (i, i = 1,12,2) ] !创建数组 [1,3,5,7,9,11] - array = [ (i**2, i = 1,6) ] !创建数组 [1,4,9,16,25,36] - array = [ (4,5, i = 1,3) ] !创建数组 [4,5,4,5,4,5] - - - ! 输入/输出 - ! ============ - - print *, b !向命令行打印变量 'b' - - ! 我们可以格式化输出 - print "(I6)", 320 !打印 ' 320' - print "(I6.4)", 3 !打印 ' 0003' - print "(F6.3)", 4.32 !打印 ' 4.320' - - - ! 该字母与数值规定了给定的数值与字符所用于打印输出的类型与格式 - ! 字母可为 I (整数), F (浮点数), E (工程格式), - ! L (逻辑/布尔值), A (字符) ... - print "(I3)", 3200 !如果数值无法符合格式将打印 '***' - - ! 可以同时设定多种格式 - print "(I5,F6.2,E6.2)", 120, 43.41, 43.41 - print "(3I5)", 10, 20, 30 !连续打印3个整数 (字段宽度 = 5). - print "(2(I5,F6.2))", 120, 43.42, 340, 65.3 !连续分组格式 - - ! 我们也可以从终端读取输入 - read *, v - read "(2F6.2)", v, x !读取2个数值 - - ! 读取文件 - open(unit=11, file="records.txt", status="old") - ! 文件被引用带有一个单位数 'unit', 为一个取值范围在9-99的整数 - ! 'status' 可以为 {'old','replace','new'} 其中之一 - read(unit=11, fmt="(3F10.2)") a, b, c - close(11) - - ! 写入一个文件 - open(unit=12, file="records.txt", status="replace") - write(12, "(F10.2,F10.2,F10.2)") c, b, a - close(12) - ! 在讨论范围之外的还有更多的细节与可用功能,并于老版本的 Fortran 保持兼容 - - - ! 内置函数 - ! ================== - - ! Fortran 拥有大约 200 个内置函数/子程序 - ! 例子 - call cpu_time(v) !以秒为单位设置时间 - k = ior(i,j) !2个整数的位或运算 - v = log10(x) !以10为底的log运算 - i = floor(b) !返回一个最接近的整数小于或等于x (地板数) - v = aimag(w) !复数的虚数部分 - - - ! 函数与子程序 - ! ======================= - - ! 一个子程序会根据输入值运行一些代码并会导致副作用 (side-effects) 或修改输入值 - ! (译者注: 副作用是指对子程序/函数外的环境产生影响,如修改变量) - - call routine(a,c,v) !调用子程序 - - ! 一个函数会根据输入的一系列数值来返回一个单独的值 - ! 但输入值仍然可能被修改以及产生副作用 - - m = func(3,2,k) !调用函数 - - ! 函数可以在表达式内被调用 - Print *, func2(3,2,k) - - ! 一个纯函数不会去修改输入值或产生副作用 - m = func3(3,2,k) - - -contains ! 用于定义程序内部的副程序(sub-programs)的区域 - - ! Fortran 拥有一些不同的方法去定义函数 - - integer function func(a,b,c) !一个返回一个整数的函数 - implicit none !最好也在函数内将含蓄模式关闭 (implicit none) - integer :: a,b,c !输入值类型定义在函数内部 - if (a >= 2) then - func = a + b + c !返回值默认为函数名 - return !可以在函数内任意时间返回当前值 - endif - func = a + c - ! 在函数的结尾不需要返回语句 - end function func - - - function func2(a,b,c) result(f) !将返回值声明为 'f' - implicit none - integer, intent(in) :: a,b !可以声明让变量无法被函数修改 - integer, intent(inout) :: c - integer :: f !函数的返回值类型在函数内声明 - integer :: cnt = 0 !注意 - 隐式的初始化变量将在函数的多次调用间被存储 - f = a + b - c - c = 4 !变动一个输入变量的值 - cnt = cnt + 1 !记录函数的被调用次数 - end function func2 - - - pure function func3(a,b,c) !一个没有副作用的纯函数 - implicit none - integer, intent(in) :: a,b,c - integer :: func3 - func3 = a*b*c - end function func3 - - - subroutine routine(d,e,f) - implicit none - real, intent(inout) :: f - real, intent(in) :: d,e - f = 2*d + 3*e + f - end subroutine routine - - -end program example ! 函数定义完毕 ----------------------- - -! 函数与子程序的外部声明对于生成程序清单来说,需要一个接口声明(即使它们在同一个源文件内)(见下) -! 使用 'contains' 可以很容易地在模块或程序内定义它们 - -elemental real function func4(a) result(res) -! 一个元函数(elemental function) 为一个纯函数使用一个标量输入值 -! 但同时也可以用在一个数组并对其中的元素分别处理,之后返回一个新的数组 - real, intent(in) :: a - res = a**2 + 1.0 -end function func4 - - -! 模块 -! ======= - -! 模块十分适合于存放与复用相关联的一组声明、函数与子程序 - -module fruit - real :: apple - real :: pear - real :: orange -end module fruit - - -module fruity - - ! 声明必须按照顺序: 模块、接口、变量 - ! (同样可在程序内声明模块和接口) - - use fruit, only: apple, pear ! 使用来自于 fruit 模块的 apple 和 pear - implicit none !在模块导入后声明 - - private !使得模块内容为私有(private)(默认为公共 public) - ! 显式声明一些变量/函数为公共 - public :: apple,mycar,create_mycar - ! 声明一些变量/函数为私有(在当前情况下没必要)(译注: 因为前面声明了模块全局 private) - private :: func4 - - ! 接口 - ! ========== - ! 在模块内显式声明一个外部函数/程序 - ! 一般最好将函数/程序放进 'contains' 部分内 - interface - elemental real function func4(a) result(res) - real, intent(in) :: a - end function func4 - end interface - - ! 重载函数可以通过已命名的接口来定义 - interface myabs - ! 可以通过使用 'module procedure' 关键词来包含一个已在模块内定义的函数 - module procedure real_abs, complex_abs - end interface - - ! 派生数据类型 - ! ================== - ! 可创建自定义数据结构 - type car - character (len=100) :: model - real :: weight !(公斤 kg) - real :: dimensions(3) !例: 长宽高(米) - character :: colour - end type car - - type(car) :: mycar !声明一个自定义类型的变量 - ! 用法具体查看 create_mycar() - - ! 注: 模块内没有可执行的语句 - -contains - - subroutine create_mycar(mycar) - ! 展示派生数据类型的使用 - implicit none - type(car),intent(out) :: mycar - - ! 通过 '%' 操作符来访问(派生数据)类型的元素 - mycar%model = "Ford Prefect" - mycar%colour = 'r' - mycar%weight = 1400 - mycar%dimensions(1) = 5.0 !索引默认起始值为 1 ! - mycar%dimensions(2) = 3.0 - mycar%dimensions(3) = 1.5 - - end subroutine - - real function real_abs(x) - real :: x - if (x<0) then - real_abs = -x - else - real_abs = x - end if - end function real_abs - - real function complex_abs(z) - complex :: z - ! 过长的一行代码可通过延续符 '&' 来换行 - complex_abs = sqrt(real(z)**2 + & - aimag(z)**2) - end function complex_abs - - -end module fruity - -``` - -### 更多资源 - -了解更多的 Fortran 信息: - -+ [wikipedia](https://en.wikipedia.org/wiki/Fortran) -+ [Fortran_95_language_features](https://en.wikipedia.org/wiki/Fortran_95_language_features) -+ [fortranwiki.org](http://fortranwiki.org) -+ [www.fortran90.org/](http://www.fortran90.org) -+ [list of Fortran 95 tutorials](http://www.dmoz.org/Computers/Programming/Languages/Fortran/FAQs%2C_Help%2C_and_Tutorials/Fortran_90_and_95/) -+ [Fortran wikibook](https://en.wikibooks.org/wiki/Fortran) -+ [Fortran resources](http://www.fortranplus.co.uk/resources/fortran_resources.pdf) -+ [Mistakes in Fortran 90 Programs That Might Surprise You](http://www.cs.rpi.edu/~szymansk/OOF90/bugs.html)