MK
摩柯社区 - 一个极简的技术知识社区
AI 面试

Fortran基础语法入门

2021-10-224.1k 阅读

Fortran基础语法入门

1. 程序结构

Fortran程序由一个主程序(main program)和零个或多个子程序(subprograms)组成。主程序是程序的入口点,负责调用子程序来完成特定任务。

1.1 主程序结构

program hello_world
    implicit none
    write(*,*) 'Hello, World!'
end program hello_world
  • program语句:定义主程序的开始,其后跟随程序名,这里是hello_world
  • implicit none语句:要求显式声明所有变量,这有助于减少编程错误。
  • write语句:用于输出信息。*表示标准输出设备(通常是屏幕),*后的*表示使用默认的输出格式。
  • end program语句:标志主程序的结束,后跟程序名(可省略)。

1.2 子程序结构

子程序分为函数(function)和子例程(subroutine)。

函数示例

function add_numbers(a, b) result(sum_value)
    implicit none
    real :: a, b
    real :: sum_value
    sum_value = a + b
end function add_numbers
  • function语句:定义函数开始,add_numbers是函数名,括号内是参数列表,result关键字指定函数返回值的变量名。
  • implicit none语句:同样要求显式声明变量。
  • 函数体中计算并返回两个实数的和。

子例程示例

subroutine print_message(message)
    implicit none
    character(len=*) :: message
    write(*,*) message
end subroutine print_message
  • subroutine语句:定义子例程开始,print_message是子例程名,括号内是参数列表。
  • character(len=*):声明一个长度可变的字符型变量,用于接收要打印的消息。
  • 子例程体将接收到的消息输出到标准输出。

2. 数据类型

Fortran提供了多种基本数据类型,包括整数、实数、复数、字符和逻辑类型。

2.1 整数类型

整数类型用于表示整数值。在Fortran中,有不同精度的整数类型。

program integer_example
    implicit none
    integer :: i1, i2
    integer(kind=4) :: i4
    integer(kind=8) :: i8

    i1 = 10
    i2 = -20
    i4 = 12345678
    i8 = 9876543210987654

    write(*,*) 'i1:', i1
    write(*,*) 'i2:', i2
    write(*,*) 'i4:', i4
    write(*,*) 'i8:', i8
end program integer_example
  • integer:默认的整数类型,通常为4字节(取决于编译器和系统)。
  • integer(kind=4):显式指定为4字节整数。
  • integer(kind=8):指定为8字节整数,可表示更大范围的整数。

2.2 实数类型

实数类型用于表示带有小数部分的数值。

program real_example
    implicit none
    real :: r1
    real(kind=4) :: r4
    real(kind=8) :: r8

    r1 = 3.14159
    r4 = 2.71828
    r8 = 1.6180339887498948482

    write(*,*) 'r1:', r1
    write(*,*) 'r4:', r4
    write(*,*) 'r8:', r8
end program real_example
  • real:默认实数类型,通常为4字节(单精度)。
  • real(kind=4):显式指定为单精度实数。
  • real(kind=8):指定为双精度实数,提供更高的精度。

2.3 复数类型

复数类型用于表示复数,由实部和虚部组成。

program complex_example
    implicit none
    complex :: c1
    complex(kind=4) :: c4
    complex(kind=8) :: c8

    c1 = (1.0, 2.0)
    c4 = (3.14, -1.0)
    c8 = (1.618, 0.577)

    write(*,*) 'c1:', c1
    write(*,*) 'c4:', c4
    write(*,*) 'c8:', c8
end program complex_example
  • complex:默认复数类型,实部和虚部的精度与默认实数类型相同。
  • complex(kind=4):实部和虚部为单精度。
  • complex(kind=8):实部和虚部为双精度。

2.4 字符类型

字符类型用于存储文本字符串。

program character_example
    implicit none
    character(len=10) :: str1
    character(len=*) :: str2

    str1 = 'Hello'
    str2 = 'This is a longer string'

    write(*,*) 'str1:', str1
    write(*,*) 'str2:', str2
end program character_example
  • character(len=10):声明一个长度为10的字符变量,若字符串长度不足10,会在右侧填充空格。
  • character(len=*):声明一个长度可变的字符变量,其长度由初始化时的字符串长度决定。

2.5 逻辑类型

逻辑类型用于表示逻辑值(真或假)。

program logical_example
    implicit none
    logical :: l1, l2

    l1 = .true.
    l2 = .false.

    write(*,*) 'l1:', l1
    write(*,*) 'l2:', l2
end program logical_example
  • logical:声明逻辑变量,.true..false.是Fortran中的逻辑常量。

3. 变量声明与作用域

在Fortran中,变量必须先声明后使用,且不同的声明位置决定了变量的作用域。

3.1 变量声明

program variable_declaration
    implicit none
    integer :: num1, num2
    real :: pi
    character(len=20) :: name

    num1 = 10
    num2 = 20
    pi = 3.14159
    name = 'John Doe'

    write(*,*) 'num1:', num1
    write(*,*) 'num2:', num2
    write(*,*) 'pi:', pi
    write(*,*) 'name:', name
end program variable_declaration
  • 这里声明了整数变量num1num2,实数变量pi,以及字符变量name,并进行了初始化。

3.2 作用域

局部变量:在子程序内部声明的变量具有局部作用域,仅在该子程序内有效。

subroutine local_variable_example
    implicit none
    integer :: local_num
    local_num = 50
    write(*,*) 'Local variable:', local_num
end subroutine local_variable_example

全局变量:可以通过模块(module)来实现全局变量的效果。

module global_variables
    implicit none
    integer :: global_num
end module global_variables

program global_variable_usage
    use global_variables
    implicit none
    global_num = 100
    write(*,*) 'Global variable:', global_num
end program global_variable_usage
  • module语句:定义一个模块,这里global_variables模块声明了一个全局变量global_num
  • use语句:在主程序中使用该模块,从而可以访问模块中的全局变量。

4. 运算符与表达式

Fortran提供了丰富的运算符,包括算术、关系、逻辑和赋值运算符。

4.1 算术运算符

算术运算符用于数值计算,包括+(加)、-(减)、*(乘)、/(除)和**(乘方)。

program arithmetic_operators
    implicit none
    real :: a, b, result
    a = 5.0
    b = 2.0

    result = a + b
    write(*,*) 'a + b =', result

    result = a - b
    write(*,*) 'a - b =', result

    result = a * b
    write(*,*) 'a * b =', result

    result = a / b
    write(*,*) 'a / b =', result

    result = a ** b
    write(*,*) 'a ** b =', result
end program arithmetic_operators

4.2 关系运算符

关系运算符用于比较两个值,结果为逻辑值(.true..false.)。包括==(等于)、/=(不等于)、<(小于)、>(大于)、<=(小于等于)和>=(大于等于)。

program relational_operators
    implicit none
    integer :: x, y
    logical :: result
    x = 10
    y = 20

    result = x == y
    write(*,*) 'x == y:', result

    result = x /= y
    write(*,*) 'x /= y:', result

    result = x < y
    write(*,*) 'x < y:', result

    result = x > y
    write(*,*) 'x > y:', result

    result = x <= y
    write(*,*) 'x <= y:', result

    result = x >= y
    write(*,*) 'x >= y:', result
end program relational_operators

4.3 逻辑运算符

逻辑运算符用于对逻辑值进行操作,包括.not.(非)、.and.(与)、.or.(或)和.eqv.(等价)。

program logical_operators
    implicit none
    logical :: l1, l2, result
    l1 = .true.
    l2 = .false.

    result = .not. l1
    write(*,*) '.not. l1:', result

    result = l1 .and. l2
    write(*,*) 'l1 .and. l2:', result

    result = l1 .or. l2
    write(*,*) 'l1 .or. l2:', result

    result = l1 .eqv. l2
    write(*,*) 'l1 .eqv. l2:', result
end program logical_operators

4.4 赋值运算符

赋值运算符=用于将右侧表达式的值赋给左侧变量。

program assignment_operator
    implicit none
    integer :: num
    num = 100
    write(*,*) 'num:', num
end program assignment_operator

5. 控制结构

控制结构允许程序根据条件执行不同的代码块或重复执行代码。

5.1 if - then - else结构

program if_else_example
    implicit none
    integer :: num
    num = 15

    if (num > 10) then
        write(*,*) 'The number is greater than 10'
    else
        write(*,*) 'The number is less than or equal to 10'
    end if
end program if_else_example
  • if语句:检查条件num > 10,如果为真,执行then后的代码块;否则执行else后的代码块。

5.2 if - then - else if结构

program if_elseif_example
    implicit none
    integer :: num
    num = 25

    if (num < 10) then
        write(*,*) 'The number is less than 10'
    else if (num < 20) then
        write(*,*) 'The number is between 10 and 19'
    else
        write(*,*) 'The number is 20 or greater'
    end if
end program if_elseif_example
  • 可以使用多个else if来检查多个条件。

5.3 select case结构

program select_case_example
    implicit none
    integer :: grade
    grade = 85

    select case (grade)
        case (90:100)
            write(*,*) 'A'
        case (80:89)
            write(*,*) 'B'
        case (70:79)
            write(*,*) 'C'
        case default
            write(*,*) 'D or lower'
    end select
end program select_case_example
  • select case语句:根据grade的值选择执行相应的case块。case后的范围表示该范围内的值都会执行对应的代码块,case default用于处理其他未匹配的情况。

5.4 do循环

固定次数循环

program do_loop_fixed
    implicit none
    integer :: i
    do i = 1, 5
        write(*,*) 'Iteration', i
    end do
end program do_loop_fixed
  • do语句i从1开始,每次增加1,直到达到5,执行循环体。

条件循环

program do_loop_conditional
    implicit none
    integer :: num
    num = 1

    do while (num <= 5)
        write(*,*) 'Number:', num
        num = num + 1
    end do
end program do_loop_conditional
  • do while语句:只要条件num <= 5为真,就执行循环体,每次循环后num增加1。

6. 数组

数组是相同数据类型的元素的集合。

6.1 一维数组

program one_dimensional_array
    implicit none
    integer, dimension(5) :: numbers
    integer :: i

    numbers = [1, 2, 3, 4, 5]

    do i = 1, 5
        write(*,*) 'Element', i, ':', numbers(i)
    end do
end program one_dimensional_array
  • integer, dimension(5):声明一个包含5个元素的一维整数数组numbers
  • 使用[ ]初始化数组元素,通过numbers(i)访问数组元素。

6.2 多维数组

program multi_dimensional_array
    implicit none
    integer, dimension(2, 3) :: matrix
    integer :: i, j

    matrix = reshape([1, 2, 3, 4, 5, 6], [2, 3])

    do i = 1, 2
        do j = 1, 3
            write(*,*) 'Element(', i, ',', j, '):', matrix(i, j)
        end do
    end do
end program multi_dimensional_array
  • integer, dimension(2, 3):声明一个2行3列的二维整数数组matrix
  • reshape函数:将一维数组[1, 2, 3, 4, 5, 6]重塑为二维数组。通过matrix(i, j)访问二维数组元素。

7. 输入输出

Fortran提供了多种输入输出方式,包括标准输入输出和文件输入输出。

7.1 标准输入输出

输出

program standard_output
    implicit none
    integer :: num
    num = 100
    write(*,*) 'The number is:', num
end program standard_output

输入

program standard_input
    implicit none
    integer :: num
    write(*,*) 'Enter a number:'
    read(*,*) num
    write(*,*) 'You entered:', num
end program standard_input
  • write语句:输出信息到标准输出(屏幕)。
  • read语句:从标准输入(键盘)读取数据,存储到变量num中。

7.2 文件输入输出

文件输出

program file_output
    implicit none
    integer :: i
    integer, parameter :: unit = 10
    open(unit=unit, file='output.txt')

    do i = 1, 5
        write(unit,*) 'Line', i
    end do

    close(unit)
end program file_output
  • open语句:打开一个名为output.txt的文件,unit指定文件单元号为10。
  • write语句:使用文件单元号unit将数据写入文件。
  • close语句:关闭文件。

文件输入

program file_input
    implicit none
    character(len=50) :: line
    integer, parameter :: unit = 10
    open(unit=unit, file='output.txt')

    do
        read(unit,*,end=100) line
        write(*,*) line
    end do

100 close(unit)
end program file_input
  • open语句:打开output.txt文件。
  • read语句:从文件中读取一行数据到line变量,end=100表示读到文件末尾时跳转到标号100处执行close语句关闭文件。

8. 函数与子例程

如前文所述,函数和子例程是Fortran中的重要子程序类型。

8.1 函数

函数返回一个值,常用于计算并返回结果。

function factorial(n) result(fact)
    implicit none
    integer, intent(in) :: n
    integer :: fact, i

    fact = 1
    do i = 1, n
        fact = fact * i
    end do
end function factorial

program function_usage
    implicit none
    integer :: num, result
    num = 5
    result = factorial(num)
    write(*,*) 'Factorial of', num, 'is', result
end program function_usage
  • intent(in):表示参数n是输入参数,在函数内部不会被修改。
  • 函数factorial计算并返回n的阶乘。

8.2 子例程

子例程不返回值,常用于执行特定的操作。

subroutine swap_numbers(a, b)
    implicit none
    integer, intent(inout) :: a, b
    integer :: temp
    temp = a
    a = b
    b = temp
end subroutine swap_numbers

program subroutine_usage
    implicit none
    integer :: num1, num2
    num1 = 10
    num2 = 20

    write(*,*) 'Before swap: num1 =', num1, ', num2 =', num2
    call swap_numbers(num1, num2)
    write(*,*) 'After swap: num1 =', num1, ', num2 =', num2
end program subroutine_usage
  • intent(inout):表示参数ab既是输入参数,又会在子例程中被修改。
  • 子例程swap_numbers交换两个整数的值。

9. 模块

模块用于封装相关的变量、子程序和类型定义,提高代码的组织性和可重用性。

module math_operations
    implicit none

    contains

    function add(a, b) result(sum_value)
        implicit none
        real, intent(in) :: a, b
        real :: sum_value
        sum_value = a + b
    end function add

    function multiply(a, b) result(product)
        implicit none
        real, intent(in) :: a, b
        real :: product
        product = a * b
    end function multiply
end module math_operations

program module_usage
    use math_operations
    implicit none
    real :: x, y, sum_result, product_result
    x = 3.0
    y = 4.0

    sum_result = add(x, y)
    product_result = multiply(x, y)

    write(*,*) 'Sum:', sum_result
    write(*,*) 'Product:', product_result
end program module_usage
  • module语句:定义math_operations模块。
  • contains语句:将模块中的函数定义包含在模块内部。
  • use语句:在主程序中使用该模块,从而可以调用模块中的函数。

10. 指针

指针是一种特殊的变量,它存储了另一个变量的内存地址。

program pointer_example
    implicit none
    integer, target :: num
    integer, pointer :: ptr

    num = 100
    ptr => num

    write(*,*) 'Value of num:', num
    write(*,*) 'Value pointed by ptr:', ptr
end program pointer_example
  • target:声明num为可被指针指向的目标变量。
  • ptr => num:使指针ptr指向变量num,通过指针可以访问和修改目标变量的值。

11. 动态内存分配

Fortran支持动态内存分配,允许在程序运行时根据需要分配和释放内存。

program dynamic_memory_allocation
    implicit none
    integer, allocatable :: array(:)
    integer :: size_array, i

    size_array = 5
    allocate(array(size_array))

    do i = 1, size_array
        array(i) = i * 10
    end do

    do i = 1, size_array
        write(*,*) 'Element', i, ':', array(i)
    end do

    deallocate(array)
end program dynamic_memory_allocation
  • allocatable:声明array为可分配数组。
  • allocate语句:根据size_array的值动态分配数组内存。
  • deallocate语句:释放分配的内存,避免内存泄漏。

通过以上内容,对Fortran的基础语法有了较为全面的了解。从程序结构、数据类型到各种控制结构、数组操作等,这些基础知识是进一步深入学习Fortran编程的基石。在实际应用中,根据具体需求合理运用这些知识,可以开发出高效、可靠的Fortran程序。