主题:问一个菜菜的问题。
林杰杰
[专家分:8970] 发布于 2007-07-01 09:59:00
都说Fortran长于运算。想问问,Fortran的什么特性使它长于运算呢?正如C语言(不好意思,见识比较少,只懂这个……大家表拍偶。。。[em8])的贴近机器而适合于底层开发一样。Fortran提供了什么与其它语言不同的特性而使它适于运算?
回复列表 (共16个回复)
沙发
DNBR [专家分:400] 发布于 2007-07-01 11:05:00
具体不了解,同问
我只知道它当时就是为了解方程而设计的
fortran就是formula translation 的缩写
板凳
林杰杰 [专家分:8970] 发布于 2007-07-01 11:22:00
[quote]具体不了解,同问
我只知道它当时就是为了解方程而设计的
fortran就是formula translation 的缩写[/quote]
这个以前听过。
就是想知道Fortran提供了些什么措施让它擅长于数值计算。
而且,以前在书上看过到,Fortran的数组是列优先而不是像C语言那样的行优先,这种做法不知道会不会在处理矩阵的时候形成一些人为的障碍?
3 楼
DNBR [专家分:400] 发布于 2007-07-01 11:41:00
数组列优先,使用时自己注意就可以了,
找到一篇文章,也是简单介绍了一下,你看看
到底选择什么样的语言,本身是一类非常具有争议性的问题。曾几何时,在科学计算领
域,就沸沸腾腾地讨论过最好使用什么样的语言。也许我们可以说这是一个见仁见智的
问题,因为我们作为语言的使用者,总是拣自己已经很熟悉的语言,当然总是自己能够
很好驾驭的语言是最好的。但
是具体地针对科学计算来说,由于科学计算问题具有自身的独特的价值标准,在这个价
值标准之下,各种不同的语言还是可以进行客观比较的。
首先我们得把自己面临的任务界定清楚,也就是什么是科学计算问题?
所谓科学计算问题大体上包括如下三个涵义:
● 问题本身以及问题的解答都能够使用数学语言予以精确描述;
● 如果要使用通常的数学方法来给出我们所需要的数值答案,会很麻烦或者根本无法
给出;
● 问题以一定的科学与技术知识作为背景。
我们会看到正是科学计算问题的这种内涵决定了它在选择计算语言时所具有的价值标准。
首先,一个科学计算问题总是要以一个数学计算问题的形式出现,因此描述科学计算问
题的语言应该能够自然地描述数学问题,即要求编程语言和数学语言在表达方式上具有
比较直接自然的对应关系。
然后一个科学计算问题之所以需要使用计算机,那肯定是因为这个问题具有一定的计算
量,那么程序的运行效率往往是选择语言时最重要的考量因素。
正是在这两点上,FORTRAN是现在众多语言当中的绝对胜出者。
在描述数学语言的自然性方面,
FORTRAN可以说比现在还“活”着的任何语言都强。当然在历史上曾经出现过象ALGOL那
样的相当数学化的语言,可惜的是它缺乏市场生存能力,所以就只剩下FORTRAN独美于
今了。FORTRAN擅长描述数学计算,这点应该是几乎没有什么争议的。也正是由于这个
缘故,FORTRAN的易学是公认的
。任何一个科技专业人员,只要对于一个具体问题的数学求解过程有明晰的概念,要把
这个求解过程翻译为FORTRAN语言是非常轻松的。
至于执行速度方面,则常常有些似是而非的说法误导初学者。最典型的一个错误观念就
是“C代码的执行速度最快”。这个说法来源于C语言的特殊性,因为C语言更多的是一种
系统编程语言,对硬件的控制能力很强,在高级语言里面无出其右者,于是给人以C程序
的速度必定最快的印象。但是忘记了这个速度快是来自C语言的系统编程特性,而在做科
学计算时,并不需要过多地涉及到系统内核,因此C语言的长处在科学计算方面可以说并
不能适当地发挥,相反,在数值计算方面,C绝对不是FORTRAN的对手,因为相对于C以
系统编程为目的,FORTRAN是以科学计算为目的的,语言本身在设计之初,就考虑到了
针对科学计算而进行优化,因此FORTRAN生成的可执行代码是高度优化的。
实际的运行效率方面的比较也表明了FORTRAN在科学计算方面的优越性。无论是国内还是
国外,也无论是经典的串行机还是并行矢量机,大量的经验表明,在执行同一个科学计
算任务时,C或C++代码的效率都低于FORTRAN代码。
除了常见的对于C有着高效的迷信之外,还常常有着对于FORTRAN是如何如何落后的偏见
。当然这种偏见是有来源的,那就是曾经功勋卓著的FORTRAN 77在很长一段时间里面,
都缺乏进取心,使得迄今很多人提起FORTRAN,想到的就是在当今时代已经显得非常落后
的FORTRAN77。实质上,FORTRAN标准在进入FORTRAN 90时代之后,特别是现时的
FORTRAN 95版本,可以说只要是对于科学计算有用的特性,C和C++有的,现在
FORTRAN 95绝对不缺,而反过来FORTRAN95所具有的很多针对科学计算的特性,却是C
和C++所不具有的。哪怕是C++最引以为傲的面向对象性质,FORTRAN 2000也将全面引
入。所以说,FORTRAN已经完全赶上了编程语言的潮流。
与程序运行的效能有关的另外一个重要方面,是程序语言能否支持程序的并行运行,在
这点上,可以说FORTRAN表现了它的最大优势,因为FORTRAN 95正是着力于获得并行
计算的能力的一个版本。
由于现代科学计算的规模越来越大,计算并行化是一条不得不走的路线,现代计算机硬
件的发展,也使得并行化具有实际的普及前景,因为不仅专门的大型计算机是并行的,
现在的一般PC都可以拥有多个处理器,因此现代的从事科学计算的用户不得不掌握并行
化计算的编程能力。
但是进行并行化编程所遇到的一个主要问题,就是任何过程编程语言都内在地使用线性
存储模式,也就是一个数组的元素总是被认为按照数组元素的先后顺序而连续地存储在
内存单位里面,这样一种模式就决定了这样的过程编程语言无法真正地实现对并行计算
的描述。而FORTRAN95则完全改观了这种制约,因为在FORTRAN 95里面对于数组以及
数组运算建立了全新的面向并行化计算的概念,诸如纯过程的概念,逐元过程的概念,
FORALL结构等等,都有效地摆脱了线性存储模式的制约,使得FORTRAN95成为描述并
行计算的标准语言,特别是那些专用的数据并行化语言都纷纷采用FORTRAN作为基础语
言,例如高性能FORTRAN(High Performance Fortran),Fortran D,Vienna Fortran,以
及CRAFT等。这样就使得使用FORTRAN95编写的程序可以直接在这些数据并行化语言的
平台上运行,而反过来使用这些专用语言编写的程序也可以毫不困难地转移到FORTRAN
95平台上运行,这样一种局面使得FORTRAN在并行计算领域独领风骚。
综上所述,我们完全可以说FORTRAN 95是进行科学计算的最佳语言,作为需要进行科学
计算的科学与技术领域的工作人员,掌握FORTRAN95远比掌握C,C++等语言要重要得多
,至于那些计算机符号代数与数值计算软件,例如MATHEMATICA,MAPLE,MATLAB,Macsyma,MATHCAD等等,只能说是进行科学计算的教学模型与辅助工具,由于它们都
提供了现成的算法,因此可以使得初学者能够应用于一些简单的场合,真正要用它们来
对付稍微大一点的问题,有经验的用户都知道,那会是一件非常痛苦的强人所难的事情
。因此最终要自由地进行科学计算,则非FORTRAN莫属。
4 楼
林杰杰 [专家分:8970] 发布于 2007-07-01 11:50:00
谢谢楼上的文章。不过我想这篇文章应该是98或者97年的吧?
我无意引起语言之争,只是想说明文章里好像有一个我不大认同的地方。就是这句:
可以说只要是对于科学计算有用的特性,C和C++有的,现在
FORTRAN 95绝对不缺,而反过来FORTRAN95所具有的很多针对科学计算的特性,却是C
和C++所不具有的。哪怕是C++最引以为傲的面向对象性质,FORTRAN 2000也将全面引
入
Fortran2000是否存在我不大清楚,但是我听说过面向对象的Fortran应该是20003才对。而且有一个特质应该是C++特有的,就是模板。而且这篇文章也没有说出“对于科学计算有用的特性”是什么,而这个正是我发此帖的目的。
5 楼
vqimwr [专家分:1320] 发布于 2007-07-01 11:56:00
跟这个类似的问题已经见过无数了,在无数帖子上无数“高手”们将fortran贬得一文不值——仿佛fortran仍然是几十年前的66一样。…………
我的看法:
正如人们对许多事物的哲学看法一样,存在即有理,每种事物的存在是因为有它的市场存在,fortran天生就是用于数值计算的。
拿cpp和fortran来说明一下我的想法:
无数的人崇拜cpp,同时不忘记拿fortran来作对比来贬低一下,让我觉得可笑。
个人的理解其实挺简单,我们来打个比方吧,cpp就是一套瑞士军刀——锋利无比,功能强大、全面,而我们的fortran看来只是厨房里那把用了n多年的老菜刀罢了,然而,同志们,我们相信,当要切菜的时候,我们会选择那把老菜刀,而不是彪悍的军刀的。更何况fortran这把老刀正在更新,已经显露出新的锋芒,多出了一些其它实用而方便的功能。我们看到fortran是一帮古老的语言中不断进步并进步明显的一个。
(另:其实cpp是老得最快的语言中的一个,一统江湖?笑话!)
……………………
不好意思,走题了,楼主谈的是c。c的确是够底层的一个,速度是一流,但是它对数值计算的优化是明显不如fortran的,而针对数值计算的语法与fortran更是相去甚远,很多人都已经在无数论坛中提过——比如复数、矩阵等,另外要提的是fortran向并行计算方向的发展也已经走在众多语言的前面了,…………
所以,请fortran的使用者们放心大胆地用吧,至少不用担心它会在我们还年轻的时候被淘汰。
下面转两个帖子,以前收集的,应该可以解除许多朋友的疑惑吧,^-^
=====================================
进行高效的数值计算,Fortran?C/C++?
据我所知,C/C++ 也可以进行高性能的数值计算!当然,用Java也可以,但是一般人写C/C++ 的(很随便的)风格不适合编译器进行优化,编译得到的目标程序性能低,一般不推荐使用C/C++ 编写计算密集型的程序。
(BTW:C/C++ 擅长的硬件和系统底层操作是另一种意义上的“性能”)
如果想用 C/C++ 编写计算密集型程序的话,就得遵守一套严格的语法规范,而且还得仰仗专门的技术,比如我在前面的帖子中提到的“C++模版元编程技术”。说实在的,如果过分地利用了C++的灵活性,过分追求“自由化”的话,C++ 的数值计算效率甚至不如 Java !
Fortran因为语法更严格、更死板、更罗嗦,有利于编译器的优化,即使是刚学Fortran的人,也能轻松的写出能被编译器充分优化的源程序——没办法,Fortran语言的特性决定了它的源程序就应该能被方便的优化!
6 楼
vqimwr [专家分:1320] 发布于 2007-07-01 11:57:00
到了 Fortran90/95的时代,某些不必要的罗嗦的语法限制被取消了,但是 90/95 语言规范在设计时仍然以数值计算效率为最优先考虑的目标,因此灵活但仍不失严格,效率不减,对矩阵的运算可能还更快。
以 Fortran95 为标准,它比 C/C++、Java 更适合计算密集型程序的理由如下:
1. 简单易学,初学者也可以写出能被充分优化的源程序;
2. 严格的语法定义使编译器可以做出非常高效的优化;
3. 原生支持数组整体运算,在IMSL数学库的支持下可以写出诸如这样的表达式:
Y= A .x. Y ! A矩阵乘以向量Y,然后赋值给Y
Y= A .ix. X + B ! A矩阵的逆乘以向量X,再加上矩阵B,然后赋值给向量Y
4. 如果使用的是数组整体运算,那么编译器可以自动进行SMP并行化;
5. 原生支持复数数据类型及相应的运算;
6. 由于语法严格,编译器可以给出相当有价值的警告信息,便于调试;
7. 历史积淀下来现成的函数库和例程非常非常多,因为Fortran是第一种高级语言;
===========================================================================
Fortran 77, C, C 和 Fortran 90 的比较
[url=http://www.npac.syr.edu/projects/pcrc/cpswt/FOR95/1/f90_1.htm][/url]
[url=http://www.npac.syr.edu/projects/pcrc/cpswt/FOR95/1/f90_3.htm][/url]
三十年来, 从 Fortran 77 开始, Fortran 成为了计算科学的主要语言.在这段时间里, Fortran 的数值能力变得非常稳定而且优于其它计算机语言; 最大的改变来自于不断增长的各种可靠的数值过程库的种类. Fortran 联合(union), 它的使用技巧, 扩充的数值库为计算科学赋予了良好的基础.
可是在过去十几年中, 动态数据结构(特别是动态数组)的重要性不窜上升, UNIX 工作站, 复杂的交互式可视化工具, 以及更近的并行体系结构--Fortran 77 都没有实现--刺激了其它语言作为计算语言的使用, 最明显的一个例子是C. 最近C 也已经引起人们的兴趣, Fortran 通过发展到 Fortran 90来弥补它在现代科学计算方面的不足. 这部分的一个通常的工作是比较四种语言对科学计算的适应性的, 这四种语言是两个C 的代表(C, C ) 和两个Fortran的代表(Fortran 77, Fortran 90). 下面的表格总结了这种比较, 后面的内容试图合理地解释这种等级排序, 从最好(1)到最差(4)..
功能
F77
C
C
F90
数值健壮性
2
4
3
1
数据并行性
3
3
3
1
数据抽象
4
3
2
1
面向对象编程
4
3
1
2
函数型编程
4
3
2
1
平均等级
3.4
3.2
2.2
1.2
1 数值健壮性
Numeric Polymorphism(数值多态性)中是一个给定一个通用名称的几种版本的图形平滑过程的例子. 这里描述的通用能力是作为Fortran 90提供的一种额外的数值健壮性超过Fortran 77和C的特性. Fortran 77, Fortran 90 , 和 C 版本的SMOOTH子过程也在下面给出, 用于比较. (注意, Fortran 90版使用了第4部分描述的并行性)
数值多态性, 加上实际类型的参数, 小数精度选择, 和数字环境变量检查等, 证明了Fortran 90排在这四种语言中的第一位. Fortran 77 列在第二为的原因在于它支持复杂变量, 这在很多计算科学应用中是很重要的. C 把 C 挤出了第三位是由于它在通常领域多态性上的能力.
7 楼
vqimwr [专家分:1320] 发布于 2007-07-01 11:57:00
2 数据并行化部分
在这四种语言中, 只有Fortran 90具有对科学计算有价值的数据并行能力; 其它三种语言在这方面的特性基本上是一样的, 即全都没有. 这解释了四种语言在这个方面的排名.
这里是完成高斯消去的一套Fortran 77 和 C 过程:
*****************************************************************
* 编程决定正确的子过程处理过程: pivot.f , triang.f , 和 back.f. *
* 子过程决定一系列同步方程的解 *
*****************************************************************
*234567
PROGRAM testg
INTEGER IMAX, JMAX
PARAMETER (IMAX = 3, JMAX = 4)
REAL matrix(IMAX, JMAX)
REAL matrix(IMAX)
INTEGER i, j, n
DATA ( ( matrix(i,j), j = 1, JMAX), i = 1, IMAX)
/-1.0, 1.0, 2.0, 2.0, 3.0, -1.0, 1.0, 6.0,
-1.0, 3.0, 4.0, 4.0/
n = IMAX
write(*,*) "The original matrix,",n,"by",n=1,":"
call wrtmat(matrix, n, n 1)
call pivot(matrix, n)
write(*,*) "The matrix after pivoting:"
call wrtmat(matrix, n, n 1)
call triang(matrix, n)
write(*,*) "The matrix after lower triangulation:"
call wrtmat(matrix, n, n 1)
call back(solvec, matrix, n)
write(*,*) "The solution vector after back substitution:"
write(*,*) "********************************************"
write(*,*) (solvec(i), i = 1, n)
write(*,*) "********************************************"
end
********************************************************************
* 子过程决定第一列系数矩阵的最大值, 把最大值所在的行和第一行交换, *
* 处理器然后重复对其他的行和列做这种处理, 对于每一次叠代, 列的位置*
* 和行的位置增加一(即, 第1行-第1列, 然后第2行-第2列, 然后第3行-第 *
* 3列, 等 *
********************************************************************
*234567
SUBROUTINE pivot(matrix, n)
INTEGER i, j, k, n
REAL matrix(n, n 1), maxval, tempval
do 10, j = 1, n
maxval = matrix(j,j)
do 20, i = j 1, n
if (maxval .lt. matrix(i,j)) then
maxval = matrix(i,j)
do 30, k = 1, n 1
tempval = matrix(i,k)
matrix(i,k) = matrix(j, k)
matrix(j,k) = tempval
30 continue
endif
20 continue
10 continue
end
***************************************
* 完成一个输入矩阵的低级分解的子过程 *
***************************************
*234567
SUBROUTINE triang(matrix, n)
INTEGER i, j, k, n
REAL matrix(n, n 1), pivot, pcelem
do 10, j = 1, n
pivot = matrix(j,j)
do 20, k = j 1, n 1
matrix(j,k) = matrix(j,k) / pivot
20 continue
do 30, i = j 1, n
pcelem = matrix(i,j)
do 40, k = j 1, n 1
matrix(i,k) = matrix(i,k) - pcelem * matrix(j,k)
40 continue
30 continue
end
**********************************************************
* 子过程从一个已经经历了低级分解的参数矩阵计算一个解向量 *
**********************************************************
*234567
SUBROUTINE back(solvec, matrix, n)
INTEGER n
REAL solvec(n), matrix(n, n 1), sum
solvec(n) = matrix(n, n 1)
do 10, i = n -1, 1, -1
sum = 0.0
do 20, j = i 1, n
sum = sum matrix(i, j) * solvec(j)
20 continue
solvec(i) = matrix(i, n 1) - sum
10 continue
end
***********************************************************
* 测试子过程bisec.f的程序, bisec.f 决定一个方程(f.f中)的解*
* 可是这个函数确实假设函数-f由两个值支撑. 即在用户给定的终*
* 点之间的解不超过一个 *
***********************************************************
*234567
8 楼
vqimwr [专家分:1320] 发布于 2007-07-01 11:57:00
PROGRAM testbs
REAL xleft, xright
REAL f
EXTERNAL f
write(*,*) "Please enter an initial left and right value:"
read(*,*) xleft, xright
call bisec(f, xleft, xright)
end
这里是同一个算法的C 过程:
/********************************************************
* 决定三个函数(pivot.c, triang.c, back.c)正确处理的程序 *
* 这些函数决定了一系列同步方程的解 *
********************************************************/
#include <stdio.h>
#define IMAX 3
#define JMAX 4
float matrix[IMAX][JMAX] = {
{-1.0, 1.0, 2.0, 2.0 },
{3.0, -1.0, 1.0, 6.0 },
{-1.0, 3.0, 4.0, 4.0 }
};
float solvec[IMAX] = { 0.0, 0.0, 0.0 };
main()
{
void wrt_output(void);
void pivot(void);
void triang(void);
void back(void);
void wrt_vector(void);
(void)printf("The original matrix %d by %d :n", IMAX, JMAX);
(void)wrt_output();
(void)pivot();
(void)printf("The matrix after pivoting:n");
(void)wrt_output();
(void)triang();
(void)printf("The matrix after lower decomposition:n");
(void)wrt_output();
(void)back();
(void)printf("The solution vector after back substitution:n");
(void)wrt_vector();
}
/***********************************************************
* 决定参数矩阵中第一列的最大元素并移动第一列含有最大值的行 *
* 到第一行. 然后重复对其他的行和列做这种处理, 对于每一次叠 *
* 代, 列的位置和行的位置增加一(即, 第1行-第1列, 然后第2行- *
* 第2列, 然后第3行-第3列, 等*
************************************************************/
void pivot()
{
int i, j, k;
float maxval, tempval;
for(j = 1; j < IMAX; j ) {
maxval = matrix[j][j];
for ( i = (j 1); i < IMAX; i ) {
if ( maxval < matrix[i][j] ) {
maxval = matrix[i][j];
for( k = 0; k <= IMAX; k ) {
tempval = matrix[i][k];
matrix[i][k] = matrix[j][k];
matrix[j][k] = tempval;
}
}
}
}
}
/***********************************
* 完成一个输入矩阵的低级分解的函数 *
************************************/
void triang(void)
{
int i, j, k;
float pivot, pcelem;
for ( j = 0; j < IMAX; j ) {
pivot = matrix[j][j];
for ( k = ( j 1 ); k <= IMAX; K ) {
matrix[j][k] = matrix[j][k] / pivot;
}
for ( i = ( j 1 ); i < IMAX; i ) {
pcelem = matrix[i][j];
for ( k = ( j 1 ); k <= IMAX; k ) {
matrix[i][k] = matrix[i][k] - ( pcelem * matrix[j][k] );
}
}
}
}
/*********************************************************
* 子过程从一个已经经历了低级分解的参数矩阵计算一个解向量 *
*********************************************************/
void back(void)
{
int i, j;
float sum;
solvec[IMAX - 1] = matrix[IMAX - 1][JMAX -1];
for ( i = (IMAX -1); i > -1; i--) {
sum = 0.0;
for ( j = (i 1); j < IMAX; j ) {
sum = sum matrix[i][j] * solvec[j];
}
solvec[i] = matrix[i][IMAX] - sum;
}
}
void wrt_output(void)
{
int i, j;
(void)printf("**************************************n");
for ( i = 0; i < IMAX; i ) {
for ( j = 0; j < (JMAX - 1); j ) {
(void)printf("%f", matrix[i][j]);
}
(void)printf("%fn", matrix[i][JMAX - 1]);
}
(void)printf("****************************************n");
}
void wrt_vector(void);
{
(void)printf("*************************************n");
(void)printf("%f", solvec[0]);
(void)printf(" %f", solvec[1]);
(void)printg(" %fn", solvec[2]);
(void)printf("****************************************n");
}
/***********************************************************
* 测试函数bisec.f的程序, bisec.f 决定一个方程(f中)的解 *
* 可是这个函数确实假设函数-f由两个值支撑. 即在用户给定的终 *
* 点之间的解不超过一个 *
************************************************************/
#include <stdio.h>
#include <math.h>
main()
{
void bisec(float init_left_val, float init_right_val);
float f(float value):
float xleft, xright;
char line[100];
(void)printf("Please enter an initial left and right value:");
(void)fgets(line, sizeof(line), stdin);
(void)sscanf(line, "%f %f", &;amp;xleft, &;amp;xright );
(void)bisec(xleft, xright);
return(0);
}
3 数据抽象
Fortran 90有一个非常使用的, 使用简单的数据抽象能力。 C 作为面向对象程序设计的一个重要部分,也有很出色的数据抽象能力. 对于计算科学来说, 很多好处可以从数据抽象中获得, 而不需要面向对象编程的带来的额外的复杂性, 因此Fortran 90 在这个方面有微弱的优势. 在这一点上Fortran 77和C要比 Fortran 90 和 C 逊色许多, 尽管 C 由于对数据结构的支持而在这里的排名在 Fortran 77的前面.
4 面向对象编程
因为Fortran 90 不支持自动继承, C 在这一点上显然领先于其它语言. Fortran 90的多态性(一般的)特性是它具有手工的(而不是自动的)继承能力, 这种能力使它在这一点上领先于C 和 Fortran 77. 同样, C 由于其数据结构方面的能力使得它在这个一般的领域领先于Fortran 77.
5 函数型程序设计
由于缺少递归和数据结构, Fortran 77显然在这方面又一次排在最后. 其它三种语言都具有这些对于函数型程序设计来说是基本的方面. 不过在这三种语言中, 只有Fortran 90允许"lazy evaluation"; 标准C(因此包括C )说明一种函数参数求值和函数本身求值之间的一个"顺序点", 妨碍了函数参数的"lazy evaluation". 因此在这个标准上, Fortran 90理应排在第一位. 多态性在函数性程序设计中同样是重要的, C 在这一点上要比C 好.
9 楼
林杰杰 [专家分:8970] 发布于 2007-07-01 12:43:00
谢谢楼上的。
我也没想要贬谁。合适的才是最好的。
只是。。。没大看懂你的文章。。。
10 楼
林杰杰 [专家分:8970] 发布于 2007-07-01 12:56:00
两个链接打不开。另外,文章里评测,标准是怎么样的呢?如果只是简单评述一下F77咋样C又咋样C++又咋样F90又咋样的,恐怕不那么令人信服。
我来回复