Fortran 编程整理

Fortran编程语法整理

  • 01 Fortran 中的程序单元
    • 1-1 submodule(子模块)
  • 02 子程序与函数
    • 2-1 概述
    • 2-2 函数与子程序特性
      • (1)为函数结果指定不同名称
  • 03 stop命令后跟说明
  • 04 do concurrent
    • 4-1 `do concurrent` 的使用
  • 05 纯过程(pure procedure)
  • 06 Fortran中的elemental 属性
    • 6-1 **`elemental` 关键字的使用**:
    • 6-2 elemental 关键字默认对纯过程使用
  • 07 Fortran函数和子程序中的可选参数
  • 08 Fortran内置模块iso_fortran_env
    • 8-1常见参数和功能
    • 8-2 示例
    • 8-3 总结
    • 8-4 Fortran的内置模块
  • 09 在Fortran中自定义模块
  • 10 Fortran模块中的私有与公有声明
    • 10-1 示例
    • 10-2 解释
    • 10-3 推荐用法
    • 10-4 总结
  • 11 在导入模块时重命名导入的实体
    • 11-1 示例:重命名导入的实体
  • 12 在纯过程中数组不能在声明时直接初始化
  • 13 可分配数组的一些用法
    • 13-1 分配数组a,范围从 is 到 ie
    • 13-2 从另一个数组分配数组
    • 13-3 在赋值时自动分配和重新分配
  • 14 Fortran中的空数组
    • 14-1 空数组的定义和初始化
    • 14-2 空数组的实际应用
  • 15 可分配数组相关用法
    • 15-1 检查分配状态
    • 15-2 捕获数组分配和释放错误
  • 16 索引和切片
    • 16-1 索引和切片数组
  • 17 Fortran内置函数 all
    • 17-1 语法
    • 17-2 返回值
    • 17-3 示例
    • 17-4 实际应用
  • 18 Fortran内置函数pack
    • 18- 1 语法
    • 18-2 示例
    • 18-3 实际应用
  • 参考文献

01 Fortran 中的程序单元

  • main program (主程序) —— 只能从操作系统调用的最高级别程序单元;
  • function (函数) —— 从表达式调用的可执行子函数,并且总是返回单个结果;
  • subroutine (子程序)—— 一种可执行的子程序,可以就地修改多个参数,但不能在表达式中使用;
  • module(模块)—— 变量、函数和子例程定义的不可执行集合;
  • submodule(子模块)—— 扩展现有模块,用于定义只有该模块可以访问的变量和过程定义,对于更复杂的应用程序和库非常有用

1-1 submodule(子模块)

在Fortran中,子模块(submodule)是模块系统的一部分,用于帮助组织和管理大型代码库。子模块允许将模块分成多个部分,这些部分可以独立开发和维护,从而提高代码的可读性和可维护性。

下面是子模块的一些关键点和示例:

关键点

  1. 主模块:定义公共接口、类型和公共变量。
  2. 子模块:实现主模块中定义的接口和包含实际的代码逻辑。
  3. 结构:子模块依赖于主模块,子模块中的任何子程序都必须在主模块中声明。
  4. 可见性:子模块可以访问主模块中的所有公共实体。

示例

# 主模块(Module)
module my_moduleimplicit none! 在这里声明子模块将实现的接口containsprocedure :: my_subroutine
end module my_module
# 子模块(Submodule)
submodule (my_module) my_submoduleimplicit nonecontainssubroutine my_subroutine! 子程序实现print *, "Hello from submodule!"end subroutine my_subroutine
end submodule my_submodule
# 使用子模块
program mainuse my_moduleimplicit nonecall my_subroutine
end program main

详细解释:

  1. 主模块 (Module)

    • module my_module 定义了一个名为 my_module 的主模块。
    • contains 部分,声明了一个子程序 my_subroutine,但没有提供实现。这告诉编译器子程序将在子模块中定义。
  2. 子模块 (Submodule)

    • submodule (my_module) my_submodule 声明了一个名为 my_submodule 的子模块,并指定它从属于 my_module
    • contains 部分,实现了 my_subroutine 子程序。
  3. 主程序 (Main Program)

    • use my_module 使主模块 my_module 中的所有公共实体在主程序中可用。
    • call my_subroutine 调用子模块中的 my_subroutine 子程序。

这种结构允许更好的代码组织和模块化,使得大型Fortran项目更容易管理和维护。

02 子程序与函数

2-1 概述

![[Pasted image 20240522135037.png|500]]

图1 子程序与函数概述
  • Fortran中函数可以接收任意数量的输入参数,但是只能返回一个结果。如果有多个结果需要返回可以使用数组或自定义数据类型。
  • 对于没有副作用的计算,应该使用函数来完成。

在Fortran以及其他编程语言中,副作用(side effect)指的是在函数执行过程中对其外部状态(如全局变量、输入参数、I/O操作等)的修改。没有副作用的函数(即纯函数)只依赖于其输入参数,并且除了返回值外不会对程序的其他部分产生影响。这种函数的输出仅由输入决定,不会改变任何外部状态。

在Fortran中,当提到“在没有副作用时使用函数”时,通常指的是:

  1. 函数仅依赖于输入参数:函数的计算结果完全由传递给它的参数决定,没有依赖或修改外部变量。
  2. 没有修改输入参数:函数不会通过传递的参数修改外部变量的值。
  3. 没有I/O操作:函数不进行输入输出操作(如读取文件或打印输出,打印到屏幕上也是一种副作用)。

2-2 函数与子程序特性

(1)为函数结果指定不同名称

可以使用 result 属性为函数结果指定一个不同的名称,而不是直接使用函数名称:

INTEGER FUNCTION SUM(A, B)INTEGER, INTENT(IN) :: A, BSUM = A + B
END FUNCTION SUM! 指定不同的函数返回名称
INTEGER FUNCTION SUM(A, B) RESULT(RES)INTEGER, INTENT(IN) :: A, BRES = A + B
END FUNCTION SUM

一个函数应该只做一件事。

函数适合于不会产生副作用的计算,而子例程则更适合于需要就地修改变量的情况。但要注意这只是最佳实践,而不是硬性规定,Fortran语法是允许函数中就地修改变量的。

03 stop命令后跟说明

if(grid_size <=  0) stop 'grid_size must be > 0'

04 do concurrent

在Fortran中,concurrent 是用在并行编程中的关键字,通常在 DO CONCURRENT 结构中使用。DO CONCURRENT 结构允许程序员明确表示循环迭代之间可以独立并行执行,从而提高计算效率。

4-1 do concurrent 的使用

基本示例:

program concurrent_exampleimplicit noneinteger :: iinteger, dimension(10) :: array! Initialize the arrayarray = 0! DO CONCURRENT loopdo concurrent (i = 1:10)array(i) = i * iend do! Print the arrayprint *, array
end program concurrent_example

在这个示例中,DO CONCURRENT 循环用于对数组 array 的每个元素进行平方计算。由于每次迭代之间没有数据依赖关系,编译器可以将这些迭代并行化,以提高执行效率。

带条件的并行循环

program concurrent_with_conditionsimplicit noneinteger :: iinteger, dimension(10) :: array! Initialize the arrayarray = 0! DO CONCURRENT loop with conditionsdo concurrent (i = 1:10)if (mod(i, 2) == 0) thenarray(i) = i * 2elsearray(i) = i * 3end ifend do! Print the arrayprint *, array
end program concurrent_with_conditions

这个示例展示了带条件语句的 DO CONCURRENT 循环。根据 i 是否为偶数,数组 array 的元素被赋予不同的值。

注意事项:

  1. 独立性DO CONCURRENT 结构的每次迭代必须是独立的,也就是说,每次迭代之间不应有数据依赖性。
  2. 副作用:避免在 DO CONCURRENT 结构中使用具有副作用的操作(如 I/O 操作),因为这可能导致不可预测的行为。
  3. 性能:尽管 DO CONCURRENT 可以显式指示并行性,实际的性能提升仍然依赖于编译器的实现和底层硬件支持。

高级示例:

program concurrent_advancedimplicit noneinteger :: i, jinteger, dimension(5, 5) :: matrix! Initialize the matrixmatrix = 0! DO CONCURRENT nested loopdo concurrent (i = 1:5, j = 1:5)matrix(i, j) = i * jend do! Print the matrixdo i = 1, 5print *, matrix(i, :)end do
end program concurrent_advanced

这个高级示例展示了嵌套的 DO CONCURRENT 循环,用于初始化一个 5x5 的矩阵。每个元素 matrix(i, j) 的值为 i * j

通过使用 DO CONCURRENT,Fortran 程序可以更好地利用多核处理器的并行计算能力,从而提高计算性能。

05 纯过程(pure procedure)

在Fortran中,纯过程(pure procedure)是一类没有副作用的过程。这意味着纯过程不能更改外部变量、不能执行 I/O 操作,也不能调用任何非纯过程。纯过程的主要优点是它们更容易进行并行化和优化,因为编译器可以更好地预测其行为。

纯过程可以是子程序(subroutine)或函数(function)。要声明一个过程为纯过程,可以使用 pure 关键字。
\

纯过程的规则:

  1. 不能改变通过参数传递的任何变量的值。
  2. 不能更改模块、公共或局部变量的值。
  3. 不能执行输入/输出(I/O)操作。
  4. 不能调用非纯过程。

示例:

纯函数(Pure Function)

module math_moduleimplicit none
containspure function add(a, b) result(c)integer, intent(in) :: a, binteger :: cc = a + bend function add
end module math_module

在这个示例中,add 是一个纯函数,它接受两个整数参数 ab,并返回它们的和。因为它不修改任何外部状态,也不执行 I/O 操作,所以它是纯的。

纯子程序(Pure Subroutine)

module math_moduleimplicit none
containspure subroutine swap(a, b)integer, intent(inout) :: a, binteger :: temptemp = aa = bb = tempend subroutine swap
end module math_module

在这个示例中,swap 是一个纯子程序,它交换两个整数参数 ab 的值。尽管它修改了参数的值,但它不修改任何外部状态或执行 I/O 操作,因此它仍然是纯的。

使用纯过程

program mainuse math_moduleimplicit noneinteger :: x, y, zx = 3y = 4z = add(x, y) ! 调用纯函数print *, "Sum:", zcall swap(x, y) ! 调用纯子程序print *, "Swapped values:", x, y
end program main

在这个示例中,我们定义了一个主程序 main,它使用 math_module 中的纯过程。它首先调用纯函数 add 来计算两个整数的和,然后调用纯子程序 swap 来交换两个整数的值。

纯过程的优点:

  1. 可并行化:因为纯过程没有副作用,编译器可以更容易地并行化这些过程。
  2. 优化:纯过程更容易被编译器优化,因为它们的行为是确定的。
  3. 可测试性:纯过程由于没有副作用,更容易进行单元测试。

通过使用纯过程,Fortran程序可以提高代码的可靠性、可维护性和性能。

06 Fortran中的elemental 属性

在Fortran中,elemental 属性用于声明可以对数组的每个元素进行操作的过程(函数或子程序)。带有 elemental 属性的过程可以对标量和数组参数进行统一处理,而无需显式编写循环。这使得代码更简洁,并且可以利用编译器的自动向量化和并行化优化。

6-1 elemental 关键字的使用

elemental 函数

module math_moduleimplicit none
containselemental function square(x) result(y)real, intent(in) :: xreal :: yy = x * xend function square
end module math_module

在这个示例中,square 函数使用了 elemental 关键字,可以对标量或数组的每个元素进行平方计算。

elemental 子程序

module math_moduleimplicit none
containselemental subroutine add_one(x)real, intent(inout) :: xx = x + 1.0end subroutine add_one
end module math_module

在这个示例中,add_one 子程序使用了 elemental 关键字,可以对标量或数组的每个元素加一。

使用 elemental 子程序

program mainuse math_moduleimplicit nonereal :: a, breal, dimension(5) :: array, result_array! 标量操作a = 3.0b = square(a)print *, "Square of a:", b! 数组操作array = [1.0, 2.0, 3.0, 4.0, 5.0]result_array = square(array)print *, "Square of array:", result_array! 对数组应用elemental子程序call add_one(array)print *, "Array after add_one:", array
end program main

在这个示例中:

  1. 对标量 a 调用了 square 函数,并输出结果。
  2. 对数组 array 调用了 square 函数,结果存储在 result_array 中,并输出结果。
  3. 调用了 add_one 子程序,对数组 array 的每个元素加一,并输出修改后的数组。

优点

  1. 简洁:不需要显式编写循环,代码更加简洁易读。
  2. 性能:编译器可以更容易地进行向量化和并行化优化,提高性能。
  3. 通用性:相同的过程可以同时处理标量和数组,提高代码复用性。

通过使用 elemental 关键字,可以简化数组操作的代码,同时利用编译器优化以提高性能。

6-2 elemental 关键字默认对纯过程使用

在Fortran中,elemental 过程必须是纯过程。这是因为 elemental 过程的每个元素操作是独立的,不应该有任何副作用。为了确保这一点,elemental 过程需要符合纯过程的规则。

纯过程的规则复习

  1. 不能改变通过参数传递的任何变量的值(除非它们是 intent(out)intent(inout))。
  2. 不能更改模块、公共或局部变量的值。
  3. 不能执行输入/输出(I/O)操作。
  4. 不能调用非纯过程。

elemental 过程示例

elemental 函数

module math_moduleimplicit none
containselemental pure function square(x) result(y)real, intent(in) :: xreal :: yy = x * xend function square
end module math_module

在这个示例中,square 函数是 elemental 的,并且是纯函数 (pure)。

elemental 子程序:

module math_moduleimplicit none
containselemental pure subroutine add_one(x)real, intent(inout) :: xx = x + 1.0end subroutine add_one
end module math_module

在这个示例中,add_one 子程序是 elemental 的,并且是纯子程序 (pure)。

使用 elemental 过程:

program mainuse math_moduleimplicit nonereal :: a, breal, dimension(5) :: array, result_array! 标量操作a = 3.0b = square(a)print *, "Square of a:", b! 数组操作array = [1.0, 2.0, 3.0, 4.0, 5.0]result_array = square(array)print *, "Square of array:", result_array! 对数组应用elemental子程序call add_one(array)print *, "Array after add_one:", array
end program main

在这个示例中:

  1. 对标量 a 调用了 square 函数,并输出结果。
  2. 对数组 array 调用了 square 函数,结果存储在 result_array 中,并输出结果。
  3. 调用了 add_one 子程序,对数组 array 的每个元素加一,并输出修改后的数组。

结论
为了确保 elemental 过程的每次操作是独立且没有副作用的,Fortran 语言要求 elemental 过程必须是纯过程。这样可以保证 elemental 过程在处理数组时能够安全并行化,并提高代码的可读性和可维护性。

impure elemental 了解一下。

07 Fortran函数和子程序中的可选参数

在Fortran中,子函数(functions)和子程序(subroutines)可以通过使用optional属性来定义可选参数。这样在调用子函数或子程序时选择性地提供这些参数。以下是如何在Fortran中使用可选参数的示例:

子程序中的可选参数

program optional_args_exampleimplicit nonecall example_subroutine(5)call example_subroutine(5, 10)containssubroutine example_subroutine(a, b)integer, intent(in) :: ainteger, optional, intent(in) :: bif (present(b)) thenprint *, "a =", a, ", b =", belseprint *, "a =", a, ", b is not provided"end ifend subroutine example_subroutineend program optional_args_example

子函数中的可选参数

program optional_args_exampleimplicit noneprint *, "Result with one argument: ", example_function(5)print *, "Result with two arguments: ", example_function(5, 10)containsfunction example_function(a, b) result(res)integer, intent(in) :: ainteger, optional, intent(in) :: binteger :: resif (present(b)) thenres = a + belseres = aend ifend function example_functionend program optional_args_example

解释

  1. 子程序中的可选参数:

    • 定义子程序example_subroutine,其中第二个参数b被标记为optional
    • 使用present(b)来检查可选参数b是否被提供。
    • 在调用子程序时,可以只传递一个参数a,也可以传递两个参数ab
  2. 子函数中的可选参数:

    • 定义子函数example_function,其中第二个参数b被标记为optional
    • 同样,使用present(b)来检查可选参数b是否被提供。
    • 在调用子函数时,可以只传递一个参数a,也可以传递两个参数ab

通过这种方式,可以灵活地处理参数的传递,并根据是否提供了可选参数来执行不同的操作。

08 Fortran内置模块iso_fortran_env

Fortran 的内置模块 ISO_FORTRAN_ENV 提供了一些有用的参数和功能,可以用于控制程序的行为和提高代码的可移植性和可维护性。以下是对 ISO_FORTRAN_ENV 模块的一些详细介绍及其常见用途。

8-1常见参数和功能

  1. 数值种类参数:

    • REAL32, REAL64, REAL128:分别对应 32 位、64 位和 128 位的实数类型。
    • INT8, INT16, INT32, INT64:分别对应 8 位、16 位、32 位和 64 位的整数类型。
  2. 字符种类参数:

    • CHARACTER_KINDS:返回一个整数数组,表示可用的字符种类。
  3. 输入/输出参数:

    • INPUT_UNIT:标准输入单元号。
    • OUTPUT_UNIT:标准输出单元号。
    • ERROR_UNIT:标准错误输出单元号。
  4. 文件状态参数:

    • IOSTAT_END:表示文件结束的 IOSTAT 值。
    • IOSTAT_EOR:表示记录结束的 IOSTAT 值。
  5. 常量:

    • ERROR_UNIT:标准错误输出单元的单元号。
    • OUTPUT_UNIT:标准输出单元的单元号。
    • INPUT_UNIT:标准输入单元的单元号。

8-2 示例

以下是使用 ISO_FORTRAN_ENV 模块的一些示例:

示例 1: 使用数值种类参数

program kind_exampleuse iso_fortran_env, only: int32, real64implicit noneinteger(int32) :: ireal(real64) :: xi = 123456789x = 3.141592653589793d0print *, "Integer value: ", iprint *, "Real value: ", xend program kind_example

示例 2: 使用 I/O 参数

program io_exampleuse iso_fortran_env, only: input_unit, output_unit, error_unitimplicit noneinteger :: numprint *, "Please enter a number: "read(input_unit, *) numwrite(output_unit, "('You entered: ', I0)") numif (num < 0) thenwrite(error_unit, "('Error: Negative number entered.')")end ifend program io_example

示例3:打印编译器版本和编译选项

program print_compiler_infouse iso_fortran_envimplicit noneprint *, 'Compiler version: ', compiler_version()print *, 'Compiler options:', compiler_options()
end program print_compiler_info

解释

  1. 数值种类参数:

    • 使用 int32real64 定义整数和实数变量,以确保它们具有特定的位数,这有助于提高代码的可移植性。
  2. 输入/输出参数:

    • 使用 input_unitoutput_uniterror_unit 来处理标准 I/O 操作。这使得代码更具可读性,并且减少了硬编码的单元号。

8-3 总结

ISO_FORTRAN_ENV 模块提供了许多有用的常量和参数,可以帮助编写更具可移植性和可维护性的 Fortran 代码。通过使用这些参数和功能,可以更加轻松地控制数值类型和 I/O 操作,并确保代码能够在不同的平台上运行一致。

8-4 Fortran的内置模块

Fortran 提供了五个内置模块:iso_fortran_enviso_c_bindingieee_arithmeticieee_exceptionsieee_featuresiso_fortran_env 提供了一些有用的过程和参数,iso_c_binding 提供了与 C 语言函数和数据结构接口的功能。后面三个模块提供了特定于浮点运算的功能,一般来说,它们不像前两个模块那样有用

在导入自己不熟悉的模块时,最好加上only关键字,否则有时会出现匪夷所思的问题。

09 在Fortran中自定义模块

![[Pasted image 20240615094150.png|600]]

图2 自定义fortran模块的结构

建议每个源文件只保留一个模块。

10 Fortran模块中的私有与公有声明

在 Fortran 模块中,可以使用 publicprivate 语句来控制模块内数据和子程序的可见性。public 声明的实体可以被模块外部访问,而 private 声明的实体则只能在模块内部使用。这种控制机制有助于封装和信息隐藏,提高代码的可维护性和可靠性。

10-1 示例

以下是一个包含 publicprivate 声明的 Fortran 模块示例:

module my_moduleimplicit none! 默认可见性为 publicpublicprivate :: private_subroutine! 公有变量和子程序integer :: public_variablepublic :: public_subroutine! 私有变量和子程序integer, private :: private_variablecontains! 公有子程序subroutine public_subroutine()print *, "This is a public subroutine."call private_subroutine()end subroutine public_subroutine! 私有子程序subroutine private_subroutine()print *, "This is a private subroutine."end subroutine private_subroutineend module my_moduleprogram testuse my_moduleimplicit none! 访问公有变量和子程序public_variable = 10call public_subroutine()! 尝试访问私有变量和子程序(会导致编译错误)! private_variable = 20! call private_subroutine()end program test

10-2 解释

  1. 模块声明:

    • module my_module 声明了一个名为 my_module 的模块。
    • implicit none 禁用隐式变量声明,强制所有变量显式声明。
  2. 默认可见性:

    • public 声明将模块的默认可见性设置为公有。
    • private 声明将 private_subroutine 设置为私有。
  3. 公有和私有变量:

    • public_variable 是公有变量,可以在模块外部访问。
    • private_variable 是私有变量,只能在模块内部访问。
  4. 公有和私有子程序:

    • public_subroutine 是公有子程序,可以在模块外部调用。
    • private_subroutine 是私有子程序,只能在模块内部调用。
    • public_subroutine 中调用了 private_subroutine,这在模块内部是允许的。
  5. 程序块:

    • program test 使用了 my_module 模块。
    • 可以访问和修改 public_variable,并调用 public_subroutine
    • 尝试访问或调用私有变量和子程序会导致编译错误(被注释掉的部分)。

10-3 推荐用法

可以单独使用private或public单词作为语句,这将分别将模块中的所有实体声明为private或public。如果两者都不存在,则假定所有实体都是公共的,除非显式地声明为私有的。可以使用private属性隐藏库内部的变量和过程,这些变量和过程用户不应该访问。一般来说,良好的编程实践是将所有内容声明为私有,并显式地将公共变量和过程声明为私有。

示例

module mod_circleimplicit none! 将所有实体默认声明为私有private! 只公开 circle_area 和 circle_circumference 这两个接口函数public :: circle_area, circle_circumference! 私有常量 πreal, parameter :: pi = 3.141592653589793contains! 公有函数:计算圆的面积real function circle_area(radius)real, intent(in) :: radiuscircle_area = pi * radius * radiusend function circle_area! 公有函数:计算圆的周长real function circle_circumference(radius)real, intent(in) :: radiuscircle_circumference = 2.0 * pi * radiusend function circle_circumferenceend module mod_circleprogram test_circleuse mod_circleimplicit nonereal :: radius, area, circumference! 输入半径print *, "Enter the radius of the circle:"read *, radius! 计算面积和周长area = circle_area(radius)circumference = circle_circumference(radius)! 打印结果print *, "Area of the circle: ", areaprint *, "Circumference of the circle: ", circumferenceend program test_circle

10-4 总结

通过使用 publicprivate 声明,可以有效地控制模块内数据和子程序的可见性。这有助于实现数据的封装和信息隐藏,提高代码的安全性和可维护性。

11 在导入模块时重命名导入的实体

在 Fortran 中,可以通过 use 语句导入模块,并来重命名模块中的实体。这种方法在避免名称冲突以及使代码更加清晰和具有描述性方面非常有用。

11-1 示例:重命名导入的实体

创建一个模块 mod_circle,并在导入时重命名其中的实体。

模块定义 (mod_circle)

module mod_circleimplicit nonepublic :: circle_area, circle_circumferencereal, parameter :: pi = 3.141592653589793contains! 公有函数:计算圆的面积real function circle_area(radius)real, intent(in) :: radiuscircle_area = pi * radius * radiusend function circle_area! 公有函数:计算圆的周长real function circle_circumference(radius)real, intent(in) :: radiuscircle_circumference = 2.0 * pi * radiusend function circle_circumferenceend module mod_circle

使用模块并重命名实体

program test_circleuse mod_circle, only: area => circle_area, circumference => circle_circumferenceimplicit nonereal :: radius, area_value, circumference_value! 输入半径print *, "Enter the radius of the circle:"read *, radius! 计算面积和周长area_value = area(radius)circumference_value = circumference(radius)! 打印结果print *, "Area of the circle: ", area_valueprint *, "Circumference of the circle: ", circumference_valueend program test_circle

解释

  1. 模块定义 (mod_circle):

    • 模块 mod_circle 定义了两个公有函数 circle_areacircle_circumference,分别用于计算圆的面积和周长。
  2. 使用模块并重命名实体:

    • use mod_circle, only: area => circle_area, circumference => circle_circumference
      • use mod_circle 导入 mod_circle 模块。
      • only 子句指定只导入 circle_areacircle_circumference 两个函数。
      • area => circle_area 表示将模块中的 circle_area 函数重命名为 area
      • circumference => circle_circumference 表示将模块中的 circle_circumference 函数重命名为 circumference
  3. 程序块:

    • program test_circle 使用了 mod_circle 模块,并调用了重命名后的 areacircumference 函数。
    • 用户输入圆的半径,程序计算并输出面积和周长。

总结
通过重命名导入的实体,避免名称冲突,并使代码更加清晰和易读。在大型项目中,特别是在多个模块可能具有相同函数名或变量名时,这种方法非常有用,可以帮助组织和管理代码。

12 在纯过程中数组不能在声明时直接初始化

在 Fortran 中,所谓的“纯过程”(pure procedure)是指不会有副作用的过程,即不修改任何全局状态、不进行 I/O 操作等。纯过程一般用于并行计算和高性能计算中,以保证线程安全和可预测性。

在 Fortran 2003 及之后的版本中,纯过程可以使用局部变量进行数组初始化,但不能在声明时直接进行初始化。相反,纯过程中的数组初始化需要在过程中显式进行。下面是一个示例,展示了如何在纯过程中初始化数组。

纯过程中的数组初始化示例

program pure_procedure_exampleimplicit noneinteger, dimension(5) :: arrcall initialize_array(arr)print *, arrcontainspure subroutine initialize_array(a)integer, dimension(:), intent(out) :: ainteger :: ido i = 1, size(a)a(i) = iend doend subroutine initialize_arrayend program pure_procedure_example

在这个示例中:

  1. 主程序 (program pure_procedure_example)

    • 声明了一个长度为 5 的整型数组 arr
    • 调用纯子程序 initialize_array 来初始化数组 arr
  2. 纯子程序 (pure subroutine initialize_array)

    • 该子程序被标记为 pure,表示它不会有副作用。
    • 使用 intent(out) 指定数组 a 为输出参数。
    • 使用一个循环来初始化数组 a 的每个元素。

通过这种方式,我们可以在纯过程中进行数组的初始化,而不会违反纯过程的约束。这样做确保了过程没有副作用,使其可以安全地在并行计算中使用。

  • 隐式保存

好的在过程中的声明语句中添加 save 属性会使声明的变量在过程调用之间保存其值。换句话说,过程会“记住”该保存变量的值。现在,这里有一个转折:如果你在声明语句中初始化一个变量,这将隐式地给声明添加 save 属性。具有 save 属性的变量将在过程调用之间保持其值在内存中。由于这是一个副作用,所以它不能用于纯过程。
不推荐使用 save 属性或依赖隐式保存功能在调用之间保持状态。在主程序和模块中,这是无害的,你可以安全地在声明时初始化。在过程中,建议不要使用隐式保存行为,因为它容易导致代码错误。

13 可分配数组的一些用法

13-1 分配数组a,范围从 is 到 ie

integer :: is = -5, ie = 10 
allocate(a(is  :  ie))

13-2 从另一个数组分配数组

allocate语句的可选参数

  • mold:一个变量或表达式,具有与被分配对象相同的类型。使用mold参数分配数组时,分配的数组会与mold参数指定的数组具有相同的形状和类型,但不会初始化其元素。
  • source:类似于mold,但使用source参数分配数组时,分配的数组不仅会具有相同的形状和类型,还会用source参数指定的数组的值进行初始化。

示例解释

使用mold参数

real, allocatable :: a(:), b(:)
allocate(b(10:20))
allocate(a, mold=b)
a = 0
  • 这里,首先分配了数组b,它的范围是从10到20。
  • 然后使用mold=b分配数组a。此时,数组a会与b具有相同的形状和类型,但不会被初始化。
  • a = 0用于手动初始化数组a的元素。

使用source参数

real, allocatable :: a(:), b(:)
b = [1.0, 2.0, 3.0]
allocate(a, source=b)
  • 这里,首先初始化数组b,包含三个元素:1.0, 2.0和3.0。
  • 然后使用source=b分配数组a。此时,数组a会与b具有相同的形状和类型,并且会用b的值进行初始化。

提示

  • 无论选择哪种分配方式,始终在分配后立即初始化数组。这可以减少在表达式中意外使用未初始化数组的风险,否则可能会得到无意义的结果。

额外说明

  • 从Fortran 2003开始,Fortran提供了一种方便的特性,即在赋值时进行分配(allocation on assignment),这使得显式分配数组变得不那么必要。

13-3 在赋值时自动分配和重新分配

在赋值时自动分配和重新分配(Automatic allocation on assignment)。这是Fortran在处理动态数组时提供的方便功能,可以自动管理数组的大小和分配。

自动分配和重新分配
如果将一个数组赋值给一个可分配的数组变量(allocatable array variable),目标数组变量会根据右侧数组的大小自动进行分配。如果目标数组已经分配过,且当前大小不同于源数组,它将被重新分配以匹配源数组的大小。

示例代码解释
图中的示例展示了如何在赋值过程中自动分配和重新分配数组:

integer, allocatable :: a(:)! 初始化一个空数组
a = [integer::]! 重新分配为大小为1的数组,并赋值为[1]
a = [a, 1]! 重新分配为大小为2的数组,并赋值为[1, 2]
a = [a, 2]! 重新分配为大小为4的数组,并赋值为[1, 2, 2, 4]
a = [a, 2 * a]
  1. a = [integer::]:将a初始化为空数组。
  2. a = [a, 1]:重新分配a,将其大小设置为1,并赋值为[1]
  3. a = [a, 2]:再次重新分配a,将其大小设置为2,并赋值为[1, 2]
  4. a = [a, 2 * a]:将a重新分配为大小为4的数组,并将其赋值为[1, 2, 2, 4]。这一步中,2 * a表示将数组a中的每个元素乘以2,并将结果追加到数组a的末尾。

明显的区别

  • 显式分配(explicit allocation):使用allocate语句明确地分配数组的大小。如果在已分配的对象上再次使用allocate语句,会引发运行时错误。
  • 赋值时分配(allocation on assignment):如果数组已分配且大小不同于源数组的大小,将自动重新分配数组以匹配源数组的大小。

在Fortran中,自动分配和重新分配特性使得开发者不需要显式地调用deallocate来释放现有的数组空间。这个特性简化了内存管理,减少了显式内存管理的复杂性和可能导致的错误。以下是为什么在这种情况下不需要显式调用deallocate的详细解释:

自动重新分配的机制
当你对一个可分配数组(allocatable array)进行赋值操作时,Fortran会自动检查目标数组是否已经分配以及其大小是否合适。如果发现目标数组已经分配且大小不同于新赋值所需的大小,Fortran会自动进行以下操作:

  1. 自动释放当前分配的内存

    • 如果目标数组已经分配并且大小不同,Fortran会自动释放(deallocate)当前数组的内存。
  2. 自动重新分配内存

    • 然后,Fortran会重新分配(allocate)数组,使其大小匹配新的赋值操作所需的大小。
  3. 赋值

    • 最后,Fortran将新值赋给重新分配的数组。

这个过程在赋值语句中是隐式完成的,因此不需要显式调用deallocate

优点和设计意图

  1. 简化代码

    • 自动重新分配特性使代码更加简洁和易读,减少了显式内存管理的代码冗余。
  2. 减少错误

    • 自动管理内存分配和释放,减少了由于手动管理内存而引入的错误,如内存泄漏或重复释放内存。
  3. 提高代码可维护性

    • 代码更加模块化和抽象化,程序员可以专注于业务逻辑,而不是繁琐的内存管理。

自动分配 vs. 显式分配

  • 显式分配

    • 使用allocatedeallocate进行手动内存管理。适用于需要精确控制内存使用的场景。
  • 自动分配

    • 在赋值操作时自动处理内存分配和重新分配。适用于大多数场景,提供了更高层次的内存管理抽象。

自动分配和重新分配功能是Fortran语言设计中的一个重要特性,旨在简化内存管理,提高代码的可靠性和可维护性。通过这个特性,程序员不需要显式调用deallocate来释放内存,因为Fortran会在需要时自动处理这些操作。这种自动化处理不仅减少了编码工作量,还降低了内存管理相关错误的风险。

避免频繁地分配
小心频繁分配!数组在内存中是连续的。这有利有弊。一方面,索引数组是一个快速操作(时间常数,O(1)),因为计算机可以仅根据索引预测元素在内存中的位置。另一方面,插入、追加或删除元素总是会触发整个数组的重新分配!该操作的成本与数组大小成正比(时间线性,O(n))。对于小数组,这可能无关紧要。但是,将一个元素附加到一个包含1亿个元素的数组中,将触发约400 MB的重新分配!如果你不小心,这很容易变成应用程序的性能瓶颈。

14 Fortran中的空数组

在Fortran中,“空数组”指的是一个大小为零的数组。这意味着该数组没有任何元素。空数组在Fortran中的表示和使用非常灵活,可以用于各种情境,如初始化、条件处理和动态调整数组大小。以下是详细的解释和一些示例,展示如何在Fortran中使用空数组。

14-1 空数组的定义和初始化

在Fortran中,可以通过显式赋值或初始化表达式来定义和初始化空数组。

定义空数组
通过显式的分配和声明来定义空数组:

program empty_array_exampleimplicit noneinteger, allocatable :: a(:)! 初始化为空数组a = [integer::]! 打印数组大小print *, 'Size of a:', size(a)  ! 输出: Size of a: 0
end program empty_array_example

在上面的例子中,a被初始化为空数组,其大小为0。

动态分配空数组
也可以通过动态分配的方式创建空数组:

program allocate_empty_arrayimplicit noneinteger, allocatable :: b(:)! 动态分配大小为0的数组allocate(b(0))! 打印数组大小print *, 'Size of b:', size(b)  ! 输出: Size of b: 0
end program allocate_empty_array

使用空数组
空数组在多种情况下都有用处,例如初始化变量、条件处理和调整数组大小等。

追加元素到空数组
可以使用空数组作为初始数组,并动态追加元素:

program append_to_empty_arrayimplicit noneinteger, allocatable :: a(:)! 初始化为空数组a = [integer::]! 追加元素a = [a, 1]a = [a, 2]a = [a, 3]! 打印数组元素print *, 'Elements of a:', a  ! 输出: Elements of a: 1 2 3
end program append_to_empty_array

检查数组是否为空
可以通过检查数组的大小来确定数组是否为空:

program check_empty_arrayimplicit noneinteger, allocatable :: a(:)! 初始化为空数组a = [integer::]! 检查数组是否为空if (size(a) == 0) thenprint *, 'Array a is empty.'elseprint *, 'Array a is not empty.'end if
end program check_empty_array

14-2 空数组的实际应用

初始化数据
在程序中,初始化数组为空可以简化代码的逻辑,尤其是在处理动态数据时:

program initialize_dataimplicit noneinteger, allocatable :: data(:)! 初始化为空数组data = [integer::]! 读取数据并追加到数组(假设有一个函数get_data来获取数据)docall get_data(data)if (no_more_data()) exitend do! 打印数据print *, 'Data:', data
containssubroutine get_data(arr)integer, allocatable, intent(inout) :: arr(:)integer :: new_value! 假设这里从某个源获取新数据read *, new_value! 追加新数据arr = [arr, new_value]end subroutine get_datalogical function no_more_data()! 假设这里有逻辑判断是否还有数据no_more_data = .false.end function no_more_data
end program initialize_data

空数组在Fortran中是一个重要的概念,用于表示大小为零的数组。通过灵活使用空数组,可以简化初始化、条件处理和动态调整数组大小的逻辑,提高代码的可读性和可维护性。了解如何定义、检查和使用空数组,对于编写高效和可靠的Fortran程序是非常有帮助的。

15 可分配数组相关用法

15-1 检查分配状态

有时,知道变量的分配状态是有用的;也就是说,无论当前是否已分配。为此,可以使用内置的已分配函数。

代码示例

real, allocatable :: a(:)
print *, allocated(a)              ! 将输出 F
allocate(a(10))               
print *, allocated(a)              ! 将输出T
deallocate(a)
print *, allocated(a)              ! 将输出F

尝试分配一个已经分配的变量,或者释放一个没有分配的变量,都会触发一个运行时错误。因此,在显式地分配或释放变量之前,应总是检查分配状态。

15-2 捕获数组分配和释放错误

背景
在Fortran编程中,动态内存分配是常见的操作。分配(allocate)和释放(deallocate)内存时,有时会发生错误,例如:

  • 试图分配超过可用内存的数组
  • 分配已分配的对象
  • 释放已释放的对象

当这些错误发生时,默认情况下,程序将中止运行。然而,Fortran提供了内置的错误处理机制,可以让你在分配失败时执行自定义的错误处理逻辑,而不是直接让程序中止。

内置错误处理机制
allocate语句支持两个可选参数:staterrmsg。通过这些参数,你可以捕获并处理分配失败的错误。

参数解释

  • stat:一个整数参数,用于指示allocate语句的状态。如果分配成功,stat将为零;如果分配失败,stat将为一个非零正整数。
  • errmsg:一个字符串参数,用于存储错误信息。如果发生错误(即stat为非零),errmsg将包含错误信息;否则,errmsg的值未定义。

使用示例
以下是一个示例,展示了如何使用staterrmsg来处理分配失败的情况:

program allocation_exampleimplicit noneinteger, allocatable :: u(:)integer :: statcharacter(len=256) :: errmsg! 试图分配一个非常大的数组allocate(u(1000000000), stat=stat, errmsg=errmsg)if (stat /= 0) then! 分配失败,输出错误信息print *, 'Allocation failed with status:', statprint *, 'Error message:', trim(errmsg)! 根据需求,可以选择退出程序或采取其他措施stopelse! 分配成功,进行后续操作print *, 'Allocation successful.'! 释放数组deallocate(u)end if
end program allocation_example

使用内置错误处理机制有以下好处:

  1. 控制程序行为:你可以决定在分配失败时程序应如何继续运行。例如,可以尝试分配较小的内存块,或者优雅地退出程序,而不是让程序突然中止。
  2. 调试和诊断:通过捕获和输出错误信息,可以更容易地诊断和调试内存分配问题。
  3. 提高程序健壮性:处理错误可以提高程序的健壮性,防止因未处理的错误导致的崩溃或意外行为。

通过使用Fortran的内置错误处理机制,你可以在分配和释放内存时更好地控制程序的行为。这不仅可以帮助你捕获和处理错误,还能提高程序的健壮性和可维护性。

16 索引和切片

16-1 索引和切片数组

单个元素索引
要选择单个元素,可以在括号内使用一个整数索引,例如:

adjclose(1)

这将引用数组adjclose的第一个元素。

切片(选取子数组)
要选择一组元素,可以使用起始索引和结束索引,用冒号分隔,例如:

subset = adjclose(5:10)

这将选择adjclose数组从第5个元素到第10个元素,并将结果赋值给subset。在这种情况下,subset将被自动分配为包含6个元素的数组,对应于adjclose数组从索引5到10的值。

步长切片
可以指定步长来跳过一定数量的元素,例如:

subset = adjclose(5:10:2)

这将选择adjclose数组的第5、第7和第9个元素。

特殊情况

  • 如果stride(步长)未给出,默认为1。
  • 如果start大于endstride大于0,或者start小于endstride小于0,结果为一个空数组。
  • 如果start等于end,则切片包含单个元素,例如a(5:5)是一个包含单个元素的数组,而不是标量。

反转数组

function reverse(array)real, dimension(:), intent(in) :: arrayreal, dimension(size(array)) :: reversereverse = array(size(array):1:-1)
end function reverse

这个函数接受一个实数一维数组作为输入,并返回一个反转顺序的相同数组。可以通过切片操作array(size(array):1:-1)实现数组的反转。

计算股票收益
通过反转数组adjclose,我们可以计算股票在某个时间段内的收益:

adjclose = reverse(adjclose)
gain = adjclose(size(adjclose)) - adjclose(1)

这将数组的顺序反转,使得最早的记录排在最前面。然后,计算数组的最后一个元素和第一个元素之间的差值,表示股票的绝对收益。

使用内置的size函数可以获得数组的大小,以便于引用数组的最后一个元素。

17 Fortran内置函数 all

Fortran的all函数是一个内置的逻辑函数,用于检测数组中所有元素是否都满足特定的条件。它通常与布尔条件一起使用,并返回一个逻辑值(.true..false.)。

17-1 语法

result = all(mask)
result = all(mask, dim)
  • mask:一个逻辑数组或逻辑表达式。
  • dim(可选):一个整数,指定要在其上进行操作的维度。

17-2 返回值

  • 如果不指定dim参数,all函数会返回一个逻辑值,表示数组中所有元素是否都满足条件。
  • 如果指定了dim参数,all函数会返回一个逻辑数组,其中每个元素表示在指定维度上是否所有元素都满足条件。

17-3 示例

以下是一些使用all函数的示例:

示例 1:基本使用

program test_allimplicit nonelogical :: resultlogical, dimension(5) :: arrayarray = [.true., .true., .true., .true., .true.]result = all(array)print *, "All elements are true:", result  ! 输出: All elements are true: Tarray(3) = .false.result = all(array)print *, "All elements are true:", result  ! 输出: All elements are true: F
end program test_all

示例 2:带逻辑表达式

program test_all_expressionimplicit nonelogical :: resultinteger, dimension(5) :: arrayarray = [1, 2, 3, 4, 5]result = all(array > 0)print *, "All elements are positive:", result  ! 输出: All elements are positive: Tarray(3) = -3result = all(array > 0)print *, "All elements are positive:", result  ! 输出: All elements are positive: F
end program test_all_expression

示例 3:多维数组

program test_all_multidimimplicit nonelogical :: resultinteger, dimension(2, 3) :: arrayarray = reshape([1, 2, 3, 4, 5, 6], shape(array))result = all(array > 0)print *, "All elements are positive:", result  ! 输出: All elements are positive: Tresult = all(array > 0, dim=1)print *, "All elements in each column are positive:", result  ! 输出: All elements in each column are positive: T T Tarray(2, 2) = -5result = all(array > 0)print *, "All elements are positive:", result  ! 输出: All elements are positive: Fresult = all(array > 0, dim=2)print *, "All elements in each row are positive:", result  ! 输出: All elements in each row are positive: T F
end program test_all_multidim

17-4 实际应用

在实际应用中,all函数可以用于各种需要检查数组中所有元素是否都满足某个条件的场景。例如,在数据验证、数组比较等操作中,all函数非常有用。

示例 4:数据验证

program validate_dataimplicit nonelogical :: validinteger, dimension(10) :: datadata = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]! 检查所有数据是否都在1到10之间valid = all(data >= 1 .and. data <= 10)if (valid) thenprint *, "Data is valid."elseprint *, "Data is not valid."end if
end program validate_data

Fortran的all函数是一个非常强大的工具,用于检查数组中所有元素是否都满足某个条件。通过all函数,可以简化代码逻辑,提高代码的可读性和可维护性。无论是简单的一维数组还是复杂的多维数组,all函数都能提供有效的解决方案。

18 Fortran内置函数pack

Fortran中的pack函数是一个非常有用的工具,用于从数组中提取满足特定条件的元素,并将这些元素打包到一个新数组中。这个函数在数据筛选和处理方面非常强大,尤其是在处理大型数据集时。

18- 1 语法

result = pack(array, mask [, vector])
  • array:一个要从中提取元素的数组。
  • mask:一个逻辑数组或逻辑表达式,与array的形状相同。它指定了要打包哪些元素。
  • vector(可选):一个数组,用于指定在mask.false.时要填充的默认值。如果省略,则结果数组的大小等于mask.true.值的个数。

返回值
pack函数返回一个一维数组,该数组包含了array中所有满足mask条件的元素。如果指定了vector,结果数组的大小将与vector相同,并在mask.false.的地方填充vector的对应元素。

18-2 示例

以下是几个使用pack函数的示例:
示例 1:基本使用

program test_packimplicit noneinteger, dimension(10) :: array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]logical, dimension(10) :: maskinteger, dimension(:), allocatable :: result! 创建一个掩码,选择偶数元素mask = mod(array, 2) == 0! 使用pack函数提取偶数元素result = pack(array, mask)! 打印结果print *, 'Even elements:', result  ! 输出: Even elements: 2 4 6 8 10
end program test_pack

示例 2:带vector参数

program test_pack_with_vectorimplicit noneinteger, dimension(10) :: array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]logical, dimension(10) :: maskinteger, dimension(10) :: vector = [11, 12, 13, 14, 15, 16, 17, 18, 19, 20]integer, dimension(:), allocatable :: result! 创建一个掩码,选择偶数元素mask = mod(array, 2) == 0! 使用pack函数提取偶数元素,并使用vector填充其他元素result = pack(array, mask, vector)! 打印结果print *, 'Packed elements with vector:', result  ! 输出: Packed elements with vector: 2 4 6 8 10 16 18 20
end program test_pack_with_vector

示例 3:多维数组

program test_pack_multidimimplicit noneinteger, dimension(3, 3) :: array = reshape([1, 2, 3, 4, 5, 6, 7, 8, 9], [3, 3])logical, dimension(3, 3) :: maskinteger, dimension(:), allocatable :: result! 创建一个掩码,选择大于5的元素mask = array > 5! 使用pack函数提取大于5的元素result = pack(array, mask)! 打印结果print *, 'Elements greater than 5:', result  ! 输出: Elements greater than 5: 6 7 8 9
end program test_pack_multidim

18-3 实际应用

数据筛选
pack函数可以用于从数据集中提取满足特定条件的子集,例如:

program filter_dataimplicit noneinteger, dimension(100) :: datalogical, dimension(100) :: maskinteger, dimension(:), allocatable :: filtered_datainteger :: i! 初始化数据data = [(i, i = 1, 100)]! 创建掩码,选择大于50的元素mask = data > 50! 使用pack函数提取大于50的元素filtered_data = pack(data, mask)! 打印结果print *, 'Filtered data:', filtered_data
end program filter_data

条件处理
在处理需要条件判断的数据时,pack函数可以简化代码逻辑:

program condition_handlingimplicit noneinteger, dimension(10) :: array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]logical, dimension(10) :: maskinteger, dimension(:), allocatable :: result! 创建一个掩码,选择奇数元素mask = mod(array, 2) /= 0! 使用pack函数提取奇数元素result = pack(array, mask)! 打印结果print *, 'Odd elements:', result  ! 输出: Odd elements: 1 3 5 7 9
end program condition_handling

Fortran的pack函数是一个强大的工具,用于从数组中提取满足特定条件的元素,并将这些元素打包到一个新数组中。通过使用pack函数,可以简化数据筛选和处理的代码逻辑,提高代码的可读性和效率。无论是处理一维数组还是多维数组,pack函数都能提供有效的解决方案。

参考文献

[1] Curcic M. Modern Fortran: Building efficient parallel applications[M]. Manning Publications, 2020.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/28192.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Docker Jenkins(改错版本)

Devops:它强调开发(Development)和运维(Operations)团队之间的协作.实现更快,更可靠的软件交付部署. JenKins是一个开源的自动化服务器,广泛用于构建,测试和部署软件项目.它是持续集成(CI)和持续交付/部署(CD)的工具.JenKins是实现DevOps实践的重要工具. 前端项目部署一般流程:…

Matlab|基于V图的配电网电动汽车充电站选址定容-可视化

1主要内容 基于粒子群算法的电动汽车充电站和光伏最优选址和定容 关键词&#xff1a;选址定容 电动汽车 充电站位置 仿真平台&#xff1a;MATLAB 主要内容&#xff1a;代码主要做的是一个电动汽车充电站和分布式光伏的选址定容问题&#xff0c;提出了能够计及地理因素和服…

ubantu 计算一个文件夹内的文件数量命令

ubantu 计算一个文件夹内的文件数量命令 在Ubuntu中&#xff0c;你可以使用find命令来计算一个文件夹内的文件数量。以下是一个基本的命令示例&#xff1a; find /path/to/directory -type f | wc -l这里的/path/to/directory是你想要计算文件数量的文件夹的路径。find命令会…

蓝队-溯源技巧

溯源技巧 大致思想 通常情况下&#xff0c;接到溯源任务时&#xff0c;获得的信息如下 攻击时间 攻击 IP 预警平台 攻击类型 恶意文件 受攻击域名/IP其中攻击 IP、攻击类型、恶意文件、攻击详情是溯源入手的点。 通过攻击类型分析攻击详情的请求包&#xff0c;看有没有攻击者…

Web前端网页源代码:深入剖析与实用技巧

Web前端网页源代码&#xff1a;深入剖析与实用技巧 在Web开发的浩瀚领域中&#xff0c;前端网页源代码扮演着至关重要的角色。它不仅是网页的骨架&#xff0c;更是实现各种交互和视觉效果的基石。本文将从四个方面、五个方面、六个方面和七个方面&#xff0c;对Web前端网页源代…

C# OpenCvSharp 矩阵计算-determinant、trace、eigen、calcCovarMatrix、solve

🚀 在C#中使用OpenCvSharp库进行矩阵操作和图像处理 在C#中使用OpenCvSharp库,可以实现各种矩阵操作和图像处理功能。以下是对所列函数的详细解释和示例,包括运算过程和结果。📊✨ 1. determinant - 计算行列式 🧮 定义: double determinant(InputArray mtx); 参数…

web前端网页实例:深度剖析与实践指南

web前端网页实例&#xff1a;深度剖析与实践指南 在数字化时代的浪潮中&#xff0c;web前端网页已成为企业与用户之间的桥梁&#xff0c;承载着信息的传递与交互的重任。本文将通过四个方面、五个方面、六个方面和七个方面的详细剖析&#xff0c;带您深入了解web前端网页实例的…

实在智能应邀出席中国移动科技工作者论坛,分享基于大模型+Agent智能体的“企业大脑”

为大力弘扬科学家精神&#xff0c;激励广大科技工作者践行科技报国、创新为民&#xff0c;争做高水平科技自立自强排头兵&#xff0c;6月6日&#xff0c;中国移动在线营销服务中心&#xff08;以下简称“在线中心”&#xff09;“2024年科技工作者大讲堂暨青年创新创效论坛”于…

Matlab|基于手肘法的kmeans聚类数的精确识别【K-means聚类】

主要内容 在电力系统调度研究过程中&#xff0c;由于全年涉及的风、光和负荷曲线较多&#xff0c;为了分析出典型场景&#xff0c;很多时候就用到聚类算法&#xff0c;而K-means聚类就是常用到聚类算法&#xff0c;但是对于K-means聚类算法&#xff0c;需要自行指定分类数&…

C/C++:指针用法详解

C/C&#xff1a;指针 指针概念 指针变量也是一个变量 指针存放的内容是一个地址&#xff0c;该地址指向一块内存空间 指针是一种数据类型 指针变量定义 内存最小单位&#xff1a;BYTE字节&#xff08;比特&#xff09; 对于内存&#xff0c;每个BYTE都有一个唯一不同的编号…

赶紧转行大模型,预计风口就今年一年,明年市场就饱和了!不是开玩笑

恕我直言&#xff0c;就这几天&#xff0c;各大厂都在裁员&#xff0c;什么开发测试运维都裁&#xff0c;只有大模型是急招人。 你说你不知道大模型是什么&#xff1f;那可太对了&#xff0c;你不知道说明别人也不知道&#xff0c;就是要趁只有业内部分人知道的时候入局&#…

深入理解Python中的多线程与多进程编程

深入理解Python中的多线程与多进程编程 在现代计算中,充分利用多核处理器和并行计算资源变得越来越重要。Python提供了多线程和多进程编程的支持,使开发者能够编写高效的并行程序。本文将深入探讨Python中的多线程与多进程编程,包括基本概念、使用方法以及实际应用场景。 …

String常用方法详解

auth&#xff1a;别晃我的可乐 date&#xff1a;2024年06月16日 比较大小 equals(Object obj): 用于比较字符串内容是否相等。compareTo(String anotherString): 按字典顺序比较两个字符串。 String str1 "hello"; String str2 "world";boolean isEqual …

配置Linux DNS服务器作为自己的windows 的 DNS服务器和 配置遇到的问题

安装DNS 库 和 DNS工具&#xff1a; # bind 是用于创建 dns服务的&#xff0c; bind-utils是用于测试DNS服务的工具 yum -y install bind bind-utils配置主配置文件&#xff1a; # 下载好后就已经有DNS服务&#xff0c;但是需要你自己去配置DNS服务信息# 配置主配置文件 [rootl…

SylixOS下UDP组播测试程序

SylixOS下UDP组播测试 测试效果截图如下: udp组播发送测试程序。 /********************************************************************************************************* ** ** 中国软件开源组织 ** ** …

java中把对象作为参数

在Java中&#xff0c;把对象作为参数传递给方法是一种常见的编程模式。Java是一种面向对象的语言&#xff0c;因此它支持创建对象并使用这些对象作为参数、返回值或存储在变量中。以下是关于在Java中把对象作为参数的详细解释&#xff1a; 1. 为什么要把对象作为参数 数据共享…

使用 Vibration API 进行网页振动效果

Vibration API 是一种简单的 JavaScript API&#xff0c;可以让网页通过振动设备&#xff08;如手机&#xff09;的振动功能来提供触觉反馈。这在创建更加互动和沉浸式的用户体验时非常有用。本文将介绍如何在网页中使用 Vibration API 实现振动效果。 什么是 Vibration API&a…

什么叫做刚性兑付

在中国&#xff0c;传统的银行理财产品通常承诺固定的收益&#xff0c;投资者购买理财产品时&#xff0c;往往期望到期后能够按照约定的收益率获得回报&#xff0c;这种现象被称为“刚性兑付”。然而&#xff0c;随着金融市场的发展和监管政策的调整&#xff0c;为了降低金融系…

vue的安装配置并创建项目

npm 工具的安装 安装node.js之后&#xff0c;npm工具会自动安装到系统环境中 网址:https://nodejs.org/en vue的安装 安装vue并创建项目 npm create vuelatest 进入项目之后&#xff0c;然后启动npm run dev 解决方法&#xff1a; npm install -g create-vite 再次启动 通…

13.泛型、trait和生命周期(下)

目录 6. 生命周期与引用有效性6.1 生命周期引入6.2 得到长度最大的String值6.3 生命周期标注语法1&#xff09;说明2&#xff09;普通标注示例3&#xff09;函数参数中的生命周期标注 6.4 深入理解生命周期6.5 结构体定义中的生命周期标注6.6 生命周期省略 6.7 方法定义中的生命…