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

Fortran条件语句编程技巧

2021-04-063.4k 阅读

1. Fortran条件语句基础

在Fortran编程中,条件语句是控制程序流程的关键工具。它允许程序根据特定条件决定执行哪些代码块,从而实现更加灵活和智能的程序逻辑。Fortran主要有两种基本的条件语句类型:IF - THEN 语句和 SELECT CASE 语句。

1.1 IF - THEN 语句

IF - THEN 语句是最基本的条件判断结构。它的简单形式如下:

IF (logical_expression) THEN
    ! 当逻辑表达式为真时执行的代码块
    statements
END IF

这里的 logical_expression 是一个逻辑条件,它的值要么为真(.TRUE.),要么为假(.FALSE.)。例如,假设我们要判断一个整数 num 是否大于10:

program if_example
    implicit none
    integer :: num
    num = 15
    IF (num > 10) THEN
        print *, 'The number is greater than 10'
    END IF
end program if_example

在这个例子中,num > 10 就是逻辑表达式。由于 num 的值为15,该表达式为真,因此会执行 print 语句,输出 The number is greater than 10

IF - THEN 语句还可以扩展为 IF - THEN - ELSE 结构,用于在逻辑表达式为真和假时执行不同的代码块:

IF (logical_expression) THEN
    ! 当逻辑表达式为真时执行的代码块
    statements1
ELSE
    ! 当逻辑表达式为假时执行的代码块
    statements2
END IF

比如,我们可以根据一个数的正负性输出不同的信息:

program if_else_example
    implicit none
    integer :: num
    num = -5
    IF (num >= 0) THEN
        print *, 'The number is non - negative'
    ELSE
        print *, 'The number is negative'
    END IF
end program if_else_example

在这个程序中,num 的值为 -5,num >= 0 这个逻辑表达式为假,所以会执行 ELSE 后面的代码块,输出 The number is negative

进一步地,IF - THEN - ELSE 结构还能扩展为 IF - ELSE IF - ELSE 形式,用于处理多个互斥条件:

IF (logical_expression1) THEN
    ! 当逻辑表达式1为真时执行的代码块
    statements1
ELSE IF (logical_expression2) THEN
    ! 当逻辑表达式1为假且逻辑表达式2为真时执行的代码块
    statements2
ELSE
    ! 当所有逻辑表达式都为假时执行的代码块
    statements3
END IF

假设我们要根据学生的成绩进行等级评定:

program if_elseif_else_example
    implicit none
    real :: score
    score = 75.0
    IF (score >= 90.0) THEN
        print *, 'Grade: A'
    ELSE IF (score >= 80.0) THEN
        print *, 'Grade: B'
    ELSE IF (score >= 70.0) THEN
        print *, 'Grade: C'
    ELSE IF (score >= 60.0) THEN
        print *, 'Grade: D'
    ELSE
        print *, 'Grade: F'
    END IF
end program if_elseif_else_example

在这个例子中,score 的值为75.0,所以会执行 ELSE IF (score >= 70.0) 后面的代码块,输出 Grade: C

1.2 逻辑运算符

在构建逻辑表达式时,我们经常会用到逻辑运算符。Fortran中的逻辑运算符有:

  • .NOT.:逻辑非,用于取反一个逻辑值。例如,.NOT. (.TRUE.) 的值为 .FALSE..NOT. (.FALSE.) 的值为 .TRUE.
  • .AND.:逻辑与,只有当两个逻辑表达式都为真时,结果才为真。例如,(3 > 2).AND. (5 < 10) 的值为 .TRUE.,因为 3 > 25 < 10 都为真;而 (3 > 2).AND. (5 > 10) 的值为 .FALSE.,因为 5 > 10 为假。
  • .OR.:逻辑或,只要两个逻辑表达式中有一个为真,结果就为真。例如,(3 > 2).OR. (5 > 10) 的值为 .TRUE.,因为 3 > 2 为真;只有当 (3 < 2).OR. (5 > 10) 时结果才为 .FALSE.,因为两个表达式都为假。

例如,我们要判断一个数是否在某个范围内:

program logical_operator_example
    implicit none
    integer :: num
    num = 15
    IF ((num >= 10).AND. (num <= 20)) THEN
        print *, 'The number is in the range [10, 20]'
    END IF
end program logical_operator_example

这里使用了 .AND. 逻辑运算符来判断 num 是否同时满足大于等于10和小于等于20。

2. 嵌套 IF 语句

嵌套 IF 语句是指在一个 IF 语句的代码块中再包含另一个 IF 语句。这在处理复杂的条件逻辑时非常有用。例如,我们要判断一个年份是否为闰年,并且在闰年的基础上进一步判断是否为世纪闰年(能被400整除的年份):

program nested_if_example
    implicit none
    integer :: year
    year = 2020
    IF (mod(year, 4) == 0) THEN
        IF (mod(year, 100) /= 0.OR. mod(year, 400) == 0) THEN
            print *, year, 'is a leap year'
        ELSE
            print *, year, 'is not a leap year'
        END IF
    ELSE
        print *, year, 'is not a leap year'
    END IF
end program nested_if_example

在这个程序中,首先判断年份是否能被4整除。如果能被4整除,再进一步判断是否为世纪闰年(能被100整除但不能被400整除的年份不是闰年)。如果不能被4整除,则直接判定不是闰年。

嵌套 IF 语句虽然强大,但过多的嵌套会使代码的可读性变差。因此,在使用嵌套 IF 语句时,要尽量保持逻辑清晰,必要时可以使用注释来帮助理解代码的逻辑。例如:

program nested_if_with_comment_example
    implicit none
    integer :: num1, num2, num3
    num1 = 10
    num2 = 20
    num3 = 15
    ! 首先判断num1是否小于num2
    IF (num1 < num2) THEN
        ! 如果num1小于num2,再判断num3是否在num1和num2之间
        IF ((num3 > num1).AND. (num3 < num2)) THEN
            print *, num3, 'is between', num1, 'and', num2
        ELSE
            print *, num3, 'is not between', num1, 'and', num2
        END IF
    ELSE
        print *, num1, 'is not less than', num2
    END IF
end program nested_if_with_comment_example

通过注释,我们可以更清楚地了解每一层 IF 语句的判断目的。

3. SELECT CASE 语句

SELECT CASE 语句用于根据一个变量或表达式的值来选择执行不同的代码块,它适用于处理多个离散值的情况,比 IF - ELSE IF 结构在某些场景下更加简洁和易读。其基本语法如下:

SELECT CASE (selector)
CASE (value1)
    ! 当selector的值等于value1时执行的代码块
    statements1
CASE (value2)
    ! 当selector的值等于value2时执行的代码块
    statements2
CASE DEFAULT
    ! 当selector的值不等于任何指定值时执行的代码块
    statements3
END SELECT

这里的 selector 可以是一个整型、字符型或逻辑型的变量或表达式。value1value2 等是具体的值。例如,我们根据一个整数变量 day 的值来输出对应的星期几:

program select_case_example
    implicit none
    integer :: day
    day = 3
    SELECT CASE (day)
    CASE (1)
        print *, 'Monday'
    CASE (2)
        print *, 'Tuesday'
    CASE (3)
        print *, 'Wednesday'
    CASE (4)
        print *, 'Thursday'
    CASE (5)
        print *, 'Friday'
    CASE (6)
        print *, 'Saturday'
    CASE (7)
        print *, 'Sunday'
    CASE DEFAULT
        print *, 'Invalid day number'
    END SELECT
end program select_case_example

在这个例子中,day 的值为3,所以会执行 CASE (3) 后面的代码块,输出 Wednesday

3.1 多个值匹配

SELECT CASE 语句还支持一个 CASE 块匹配多个值。例如:

program select_case_multiple_values_example
    implicit none
    integer :: num
    num = 2
    SELECT CASE (num)
    CASE (1, 3, 5, 7, 9)
        print *, num, 'is an odd number'
    CASE (2, 4, 6, 8, 10)
        print *, num, 'is an even number'
    CASE DEFAULT
        print *, num, 'is out of range'
    END SELECT
end program select_case_multiple_values_example

这里 CASE (1, 3, 5, 7, 9) 表示当 num 的值为1、3、5、7、9中的任何一个时,执行对应的代码块;CASE (2, 4, 6, 8, 10) 同理。

3.2 范围匹配

对于整型和字符型,SELECT CASE 语句还可以使用范围匹配。例如,对于整型:

program select_case_range_example
    implicit none
    integer :: num
    num = 15
    SELECT CASE (num)
    CASE (1:10)
        print *, num, 'is between 1 and 10'
    CASE (11:20)
        print *, num, 'is between 11 and 20'
    CASE DEFAULT
        print *, num, 'is out of range'
    END SELECT
end program select_case_range_example

在这个例子中,num 的值为15,所以会执行 CASE (11:20) 后面的代码块,输出 15 is between 11 and 20

对于字符型,假设我们要根据一个字符来判断它属于哪个范围:

program select_case_char_range_example
    implicit none
    character(1) :: char
    char = 'C'
    SELECT CASE (char)
    CASE ('A':'C')
        print *, char, 'is in the range A - C'
    CASE ('D':'F')
        print *, char, 'is in the range D - F'
    CASE DEFAULT
        print *, char, 'is out of range'
    END SELECT
end program select_case_char_range_example

这里 char 的值为 'C',所以会执行 CASE ('A':'C') 后面的代码块,输出 C is in the range A - C

4. 条件语句在数组操作中的应用

4.1 筛选数组元素

条件语句在处理数组时非常有用。例如,我们有一个整数数组,想要筛选出其中大于某个阈值的元素。假设我们有一个数组 arr,阈值为50:

program array_filter_example
    implicit none
    integer, dimension(10) :: arr
    integer :: i
    arr = [10, 30, 60, 20, 80, 40, 70, 50, 90, 100]
    do i = 1, size(arr)
        IF (arr(i) > 50) THEN
            print *, arr(i), 'is greater than 50'
        END IF
    end do
end program array_filter_example

在这个程序中,通过 IF 语句遍历数组 arr,当数组元素大于50时,输出该元素。

4.2 根据条件修改数组元素

我们还可以根据条件修改数组元素。例如,将数组中所有奇数元素乘以2:

program array_modify_example
    implicit none
    integer, dimension(5) :: arr
    integer :: i
    arr = [1, 2, 3, 4, 5]
    do i = 1, size(arr)
        IF (mod(arr(i), 2) == 1) THEN
            arr(i) = arr(i) * 2
        END IF
    end do
    print *, 'Modified array:', arr
end program array_modify_example

在这个程序中,使用 IF 语句判断数组元素是否为奇数,如果是奇数,则将其乘以2。最后输出修改后的数组。

4.3 多维数组中的条件操作

对于多维数组,同样可以应用条件语句。假设我们有一个二维数组 matrix,想要找出所有大于100的元素,并将其替换为0:

program multi_dim_array_condition_example
    implicit none
    integer, dimension(3, 3) :: matrix
    integer :: i, j
    matrix = reshape([10, 200, 30, 40, 150, 60, 70, 80, 180], [3, 3])
    do i = 1, size(matrix, 1)
        do j = 1, size(matrix, 2)
            IF (matrix(i, j) > 100) THEN
                matrix(i, j) = 0
            END IF
        end do
    end do
    print *, 'Modified matrix:'
    do i = 1, size(matrix, 1)
        print *, matrix(i, :)
    end do
end program multi_dim_array_condition_example

在这个程序中,通过两层循环遍历二维数组 matrix,使用 IF 语句判断元素是否大于100,如果大于100,则将其替换为0。最后输出修改后的二维数组。

5. 条件语句在函数和子程序中的应用

5.1 函数中的条件返回值

在函数中,条件语句可以根据不同的输入返回不同的值。例如,我们定义一个函数 signum,根据输入的实数返回其符号(1表示正数, -1表示负数,0表示0):

function signum(x) result(sign)
    real :: x
    integer :: sign
    IF (x > 0.0) THEN
        sign = 1
    ELSE IF (x < 0.0) THEN
        sign = -1
    ELSE
        sign = 0
    END IF
end function signum

program signum_example
    implicit none
    real :: num
    integer :: result
    num = -5.0
    result = signum(num)
    print *, 'The sign of', num, 'is', result
end program signum_example

在这个例子中,signum 函数根据输入的 x 值,通过 IF - ELSE IF - ELSE 结构返回相应的符号值。

5.2 子程序中的条件执行

在子程序中,条件语句可以控制程序在不同条件下执行不同的操作。例如,我们定义一个子程序 print_status,根据输入的整数判断其状态并输出相应信息:

subroutine print_status(num)
    integer :: num
    IF (num >= 0) THEN
        print *, num, 'is non - negative'
    ELSE
        print *, num, 'is negative'
    END IF
end subroutine print_status

program print_status_example
    implicit none
    integer :: num
    num = 10
    call print_status(num)
    num = -3
    call print_status(num)
end program print_status_example

在这个程序中,print_status 子程序根据输入的 num 值,通过 IF - ELSE 结构输出不同的状态信息。

6. 条件编译

6.1 简介

条件编译是一种在编译阶段根据特定条件决定是否包含某些代码段的技术。在Fortran中,可以使用 #ifdef#ifndef#else#endif 等预处理器指令来实现条件编译。

6.2 示例

假设我们有一个程序,在调试阶段需要输出大量的调试信息,而在发布版本中不需要这些信息。我们可以使用条件编译来实现:

program conditional_compilation_example
    implicit none
    integer :: num
    num = 10
#ifdef DEBUG
    print *, 'Debugging: num =', num
#endif
    ! 正常的程序逻辑
    IF (num > 5) THEN
        print *, num, 'is greater than 5'
    END IF
end program conditional_compilation_example

在编译时,如果定义了 DEBUG 宏(例如使用 gfortran -DDEBUG conditional_compilation_example.f90),则会编译并执行 #ifdef DEBUG#endif 之间的代码,输出调试信息。如果没有定义 DEBUG 宏,则不会编译这部分代码,从而在发布版本中不会产生额外的调试输出。

6.3 多条件分支

条件编译也支持多条件分支,类似于 IF - ELSE IF - ELSE 结构。例如:

program multi_condition_conditional_compilation_example
    implicit none
    integer :: num
    num = 10
#ifdef DEBUG
    print *, 'Debugging: num =', num
#elif defined(TEST)
    print *, 'Testing: num is being tested'
#else
    ! 发布版本的代码
    IF (num > 5) THEN
        print *, num, 'is greater than 5'
    END IF
#endif
end program multi_condition_conditional_compilation_example

这里,如果定义了 DEBUG 宏,会输出调试信息;如果没有定义 DEBUG 但定义了 TEST 宏,则会输出测试信息;如果都没有定义,则执行发布版本的正常逻辑。

7. 优化条件语句的性能

7.1 减少不必要的计算

在逻辑表达式中,要尽量避免不必要的计算。例如,如果一个复杂的函数调用结果在多个地方使用相同的逻辑判断,应该先计算一次并存储结果,而不是每次都重新计算。假设我们有一个复杂函数 complex_function

function complex_function(x) result(res)
    real :: x
    real :: res
    ! 复杂的计算逻辑
    res = x ** 3 + sin(x) + cos(x)
end function complex_function

program optimize_condition_example
    implicit none
    real :: num
    real :: result
    num = 2.0
    result = complex_function(num)
    IF (result > 10.0) THEN
        print *, 'The result of complex function is greater than 10'
    END IF
    IF (result < 20.0) THEN
        print *, 'The result of complex function is less than 20'
    END IF
end program optimize_condition_example

在这个例子中,先计算一次 complex_function(num) 并存储结果 result,然后在两个 IF 语句中使用这个结果,避免了重复调用 complex_function

7.2 合理安排条件顺序

IF - ELSE IF 结构中,要根据条件的可能性合理安排顺序。将最有可能为真的条件放在前面,可以减少不必要的判断次数,提高程序性能。例如,假设我们要根据学生的成绩分布情况判断等级,大部分学生成绩在60 - 80分之间:

program optimize_condition_order_example
    implicit none
    real :: score
    score = 70.0
    IF ((score >= 60.0).AND. (score < 80.0)) THEN
        print *, 'Grade: C'
    ELSE IF (score >= 80.0) THEN
        print *, 'Grade: B'
    ELSE IF (score >= 90.0) THEN
        print *, 'Grade: A'
    ELSE
        print *, 'Grade: D or F'
    END IF
end program optimize_condition_order_example

在这个例子中,将最有可能满足的条件 (score >= 60.0).AND. (score < 80.0) 放在最前面,这样对于大多数情况,可以快速做出判断,减少后续条件的判断次数。

7.3 使用 SELECT CASE 替代复杂 IF - ELSE IF

当处理多个离散值时,SELECT CASE 语句的性能通常优于 IF - ELSE IF 结构。因为 SELECT CASE 语句在编译时会生成更高效的跳转表,直接跳转到对应的代码块,而 IF - ELSE IF 结构需要依次判断每个条件。例如,根据一个整数变量选择执行不同的操作:

program select_case_performance_example
    implicit none
    integer :: num
    num = 3
    SELECT CASE (num)
    CASE (1)
        ! 执行操作1
        print *, 'Executing operation 1'
    CASE (2)
        ! 执行操作2
        print *, 'Executing operation 2'
    CASE (3)
        ! 执行操作3
        print *, 'Executing operation 3'
    CASE (4)
        ! 执行操作4
        print *, 'Executing operation 4'
    CASE DEFAULT
        print *, 'Invalid number'
    END SELECT
end program select_case_performance_example

相比使用 IF - ELSE IF 结构,SELECT CASE 语句在处理这种离散值选择时性能更好,特别是当离散值数量较多时。

8. 常见错误及解决方法

8.1 逻辑表达式错误

  • 错误描述:在逻辑表达式中,可能会出现运算符使用错误、变量类型不匹配等问题。例如,将 .AND. 误写成 .OR.,或者在需要逻辑值的地方使用了数值类型。
  • 解决方法:仔细检查逻辑表达式,确保运算符的使用正确,并且参与运算的变量类型与逻辑表达式的要求相符。在编写复杂逻辑表达式时,可以逐步构建并测试,确保每个部分的正确性。

8.2 IF - THEN 结构不匹配

  • 错误描述:忘记写 END IF,或者 ELSEELSE IFIF 不匹配。例如,写了多个 ELSE 而没有对应的 IF,或者 END IF 的位置错误。
  • 解决方法:在编写 IF - THEN 结构时,要养成良好的编码习惯,先写好完整的 IF - THEN - END IF 框架,再填充中间的代码块。对于复杂的嵌套 IF 结构,可以使用代码缩进和注释来清晰地标识层次结构,便于检查匹配情况。

8.3 SELECT CASE 语句错误

  • 错误描述:在 SELECT CASE 语句中,selector 的类型与 CASE 中值的类型不匹配,或者 CASE DEFAULT 位置错误。例如,selector 是整型,而 CASE 中使用了字符型的值。
  • 解决方法:确保 SELECT CASE 语句中 selector 的类型与所有 CASE 中值的类型一致。同时,CASE DEFAULT 通常放在最后,但如果有特殊逻辑需要,也可以放在中间,但要注意程序逻辑的清晰性。在编写 SELECT CASE 语句时,仔细检查每个 CASE 块的条件和执行代码,确保逻辑正确。

通过对这些常见错误的了解和掌握解决方法,可以提高Fortran程序中条件语句编写的准确性和可靠性。