forcal 发表于 2010-10-7 11:45

Forcal数学库FcMath:以矩阵运算为基础

    FcMath32W.dll是一个Forcal数值计算扩展动态库,该库以线性代数特别是矩阵运算为基础。     在FcMath中的函数是通过二级函数命名空间“math”输出的,所有函数均具有类似“math::array(...)”的格式,都是实数函数。使用!using("math");可简化FcMath中的函数访问。     FcMath32W.dll需要FcData32W.dll的支持。FcData32W.dll要先于FcMath32W.dll加载。     FcMath库的数组是C格式的,元素序号是基于0的。可以使用函数sys::rearray在Forcal数组(C数组格式)和Fortran数组之间进行转换。     一般,若FcMath函数返回一个对象,则在oo函数中将返回临时对象,否则返回一般对象;临时对象由oo函数进行管理,一般对象须用函数delete销毁。故若没有特殊的原因,建议在oo函数中使用FcMath函数!若一般对象没有及时用delete销毁,则其将常驻内存,消耗内存资源;可用FcData的函数DelAllFCD()销毁所有对象,释放内存资源,或者在程序退出时自动销毁所有对象。     FcMath库函数具有内存消耗低、执行效率高、代码简洁、实用性强的特点。     FcMath库中所用的算法或许不是最好的,如果您有好的算法,可以方便地进行替换,提升FcMath的性能。     FcMath库可用于开发极致性能的应用程序,是熟悉C/C++、Fortran的数学爱好者的极佳的练手工具,同时也期望对一般的数值计算用户提供越来越多的方便。
    限于作者水平,期待与朋友们共同完善FcMath!如果您有什么好的算法,任何改进的意见或建议,请与作者联系。
    详细说明:Forcal数值计算扩展动态库FcMath    源代码下载:http://www.forcal.net/xiazai/forcal9/forcal9code.rar

forcal 发表于 2010-10-7 11:48

例子1代码:
!using["math"];
mvar:
oo{                      //一般在oo函数中调用FcMath函数
  a=rand,           //生成6×5矩阵a,用0~1之间随机数初始化
  a.outm(),              //输出矩阵a
  a.subg(neg:3).outm(),  //取矩阵a第4列所有元素组成子矩阵,并输出
  a.subg(3:neg).outm(),  //取矩阵a第4行所有元素组成子矩阵,并输出
  a.subg(3,5:2,3).outm() //取矩阵a第4~6行,3~4列所有元素组成子矩阵,并输出
};
结果:
       0.211319   4.91638e-002       0.144638       0.153259       0.852615
       0.630646       0.927048       0.440308       0.162857       0.556854
        0.43309        0.34552       0.563919       0.937164       0.209641
       0.603271       0.727676       0.130951   5.35736e-002       0.197937
       0.576004       0.747589   1.17645e-002       0.363892       0.280777
       0.646454       0.381088        0.58551        0.26387        0.93692

       0.153259
       0.162857
       0.937164
   5.35736e-002
       0.363892
        0.26387

       0.603271       0.727676       0.130951   5.35736e-002       0.197937

       0.130951   5.35736e-002
   1.17645e-002       0.363892
        0.58551        0.26387


例子2代码:

f(x1,x2,x3,y1,y2,y3)=      //函数定义
{
    y1=x1*x1+x2*x2+x3*x3-1.0,
    y2=2.0*x1*x1+x2*x2-4.0*x3,
    y3=3.0*x1*x1-4.0*x2+x3*x3
};
!using["math","sys"];
mvar:
oo{
  x=array(3),
  x.SA,       //设置初值为1,1,1
  i=netn,   //拟牛顿法解方程
  x.outm(),              //输出结果
  i                      //返回迭代次数
};

结果:
  0.785197       0.496611       0.369923

forcal 发表于 2010-10-7 11:53

效率测试:
simwe的网友lin2009 的matlab代码:
clear all
clc
tic
k = zeros(5,5); % //生成5×5全0矩阵
% 循环计算以下程序段100000次:
for m = 1:100000
    a = rand(5,7);
    b = rand(7,5);%//生成5×7矩阵a,7×5矩阵b,用0~1之间的随机数初始化
    k = k + a * b + a(1:5, 2:6) * b(2:6, 1:5) - a(:, 7) * b(3, :);
end
k
toc

Forcal代码:

运行稍快的代码,比matlab约快10%吧?

!using["math","sys"];
mvar:
t0=clock(),
oo{k=zeros},     //生成5×5矩阵k,初始化为0
i=0,(i<1000 00).while{ //循环计算1000 00次
  oo{
    a=rand, b=rand, //生成5×7矩阵a,7×5矩阵b,用0~1之间的随机数初始化
    k.oset //计算k=k+a*b+a.subg(0,4:1,5)*b.subg(1,5:0,4)-a.subg(neg:6)*b.subg(3:neg)
  },
  i++
},
k.outm(),             //输出矩阵k,然后销毁k
/1000;    //得到计算时间,秒
在我的电脑上运行时间为3.344秒。

比较好看些的代码,似乎也比matlab稍快吧?
!using["math","sys"];
(:t0,k,i,a,b)=
{
  t0=clock(),
  k=zeros,
  i=0,(i<1000 00).while{
    oo{
      a=rand, b=rand,
      k.=k+a*b+a(0,4:1,5)*b(1,5:0,4)-a(neg:6)*b(3:neg)
    },
    i++
  },
  k.outm().delete(),
  /1000
};
在我的电脑上运行时间为3.579秒。

该例子的理论结果是每个元素均为275000。

我的电脑:Intel Core 2 Duo T5500 1.66G 1G内存。

forcal 发表于 2010-10-7 11:55

继续例子,大家看有什么问题吗?
!using["math"];
mvar:
oo{
  ndgrid,
  a1.outm,
  a2.outm,
  a3.outm,
  a4.outm,
  a=a1+a2+a3+a4,
  a.outm,
  Sum.outm.Sum[].outm.Sum[].outm.Sum[]
};

说明:
linspace(8,12,5):生成一维数组,共5个元素8~12
a1.outm:输出**数组a1,连下标一起输出
Sum:设有m维数组(含矩阵):a(n1,n2,... ...,nm),则Sum(a,i)对第i维求和,返回一个m-1维数组。若a是一维数组、1×k矩阵、k×1矩阵、i<1或者i>m,则Sum函数返回所有数组元素的和。Sum(a)相当于Sum(a,m)。

结果(最终求和结果是1320):

(0,0,0,*)              1.            1.            1.            1.            1.
(0,0,1,*)              1.            1.            1.            1.            1.
(0,1,0,*)              1.            1.            1.            1.            1.
(0,1,1,*)              1.            1.            1.            1.            1.
(0,2,0,*)              1.            1.            1.            1.            1.
(0,2,1,*)              1.            1.            1.            1.            1.
(1,0,0,*)              2.            2.            2.            2.            2.
(1,0,1,*)              2.            2.            2.            2.            2.
(1,1,0,*)              2.            2.            2.            2.            2.
(1,1,1,*)              2.            2.            2.            2.            2.
(1,2,0,*)              2.            2.            2.            2.            2.
(1,2,1,*)              2.            2.            2.            2.            2.

(0,0,0,*)              3.            3.            3.            3.            3.
(0,0,1,*)              3.            3.            3.            3.            3.
(0,1,0,*)              4.            4.            4.            4.            4.
(0,1,1,*)              4.            4.            4.            4.            4.
(0,2,0,*)              5.            5.            5.            5.            5.
(0,2,1,*)              5.            5.            5.            5.            5.
(1,0,0,*)              3.            3.            3.            3.            3.
(1,0,1,*)              3.            3.            3.            3.            3.
(1,1,0,*)              4.            4.            4.            4.            4.
(1,1,1,*)              4.            4.            4.            4.            4.
(1,2,0,*)              5.            5.            5.            5.            5.
(1,2,1,*)              5.            5.            5.            5.            5.

(0,0,0,*)              6.            6.            6.            6.            6.
(0,0,1,*)              7.            7.            7.            7.            7.
(0,1,0,*)              6.            6.            6.            6.            6.
(0,1,1,*)              7.            7.            7.            7.            7.
(0,2,0,*)              6.            6.            6.            6.            6.
(0,2,1,*)              7.            7.            7.            7.            7.
(1,0,0,*)              6.            6.            6.            6.            6.
(1,0,1,*)              7.            7.            7.            7.            7.
(1,1,0,*)              6.            6.            6.            6.            6.
(1,1,1,*)              7.            7.            7.            7.            7.
(1,2,0,*)              6.            6.            6.            6.            6.
(1,2,1,*)              7.            7.            7.            7.            7.

(0,0,0,*)              8.            9.           10.           11.           12.
(0,0,1,*)              8.            9.           10.           11.           12.
(0,1,0,*)              8.            9.           10.           11.           12.
(0,1,1,*)              8.            9.           10.           11.           12.
(0,2,0,*)              8.            9.           10.           11.           12.
(0,2,1,*)              8.            9.           10.           11.           12.
(1,0,0,*)              8.            9.           10.           11.           12.
(1,0,1,*)              8.            9.           10.           11.           12.
(1,1,0,*)              8.            9.           10.           11.           12.
(1,1,1,*)              8.            9.           10.           11.           12.
(1,2,0,*)              8.            9.           10.           11.           12.
(1,2,1,*)              8.            9.           10.           11.           12.

(0,0,0,*)             18.           19.           20.           21.           22.
(0,0,1,*)             19.           20.           21.           22.           23.
(0,1,0,*)             19.           20.           21.           22.           23.
(0,1,1,*)             20.           21.           22.           23.           24.
(0,2,0,*)             20.           21.           22.           23.           24.
(0,2,1,*)             21.           22.           23.           24.           25.
(1,0,0,*)             19.           20.           21.           22.           23.
(1,0,1,*)             20.           21.           22.           23.           24.
(1,1,0,*)             20.           21.           22.           23.           24.
(1,1,1,*)             21.           22.           23.           24.           25.
(1,2,0,*)             21.           22.           23.           24.           25.
(1,2,1,*)             22.           23.           24.           25.           26.

(0,0,*)            100.          105.
(0,1,*)            105.          110.
(0,2,*)            110.          115.
(1,0,*)            105.          110.
(1,1,*)            110.          115.
(1,2,*)            115.          120.

(0,*)            205.          215.          225.
(1,*)            215.          225.          235.

(0,*)            645.
(1,*)            675.

1320.

forcal 发表于 2010-10-7 11:56

在matlab中,纯for循环速度最慢。而一半for循环+一半向量化的速度最快,Forcal中也是如此:
!using["math","sys"];
mvar:
(:p1,p2,p3,a,b)=
{
  oo{
    a=array.rand(),
    b=array.rand(),
    p1=array,
    p2=array,
    p3=array,
    t0=clock(),
    ndgrid(a,b,&A,&B),
    p1.=A+B
  },
  printff{"\r\nndgrid: {1,r}",/1000},
  lena=FCDLen(a),
  lenb=FCDLen(b),
  t0=clock(),
  m = lenb-1, (m>=0).while{
    oo{p2(m,neg) = a+rn},
    m--
  },
  printff{"\r\nfor1: {1,r}",/1000},
  t0=clock(),
  m = lenb-1, (m>=0).while{
    n = lena-1, (n>=0).while{
      //p3(m,n) = a(n)+b(m),  //用这句还要慢一些
      A(p3,m,n) = A(a,n)+A(b,m),
      n--
    },
    m--
  },
  printff{"\r\nfor2: {1,r}",/1000}
};

结果:
ndgrid: 3.2001e-002
for1: 1.4999e-002
for2: 1.86

forcal 发表于 2010-10-7 11:58

一段程序的Forcal实现:

//用C++代码描述为:
s=0.0;
for(x=0.0;x<=1.0;x=x+0.0011)
{
   for(y=1.0;y<=2.0;y=y+0.0009)
   {
     s=s+cos(1-sin(1.2*x^(y/2)+cos(1-sin(1.2*y^(x/2)))));
   }
}

1、**数组求和函数Sum

!using["math","sys"];
mvar:
t=clock(),
oo{
  ndgrid,
  Sum
};
/1000;
结果:
1008606.64947441
0.625   //时间

2、求和函数sum

f(x,y)=cos(1-sin(1.2*x^(y/2)+cos(1-sin(1.2*y^(x/2)))));
sum["f",0,1,0.0011,1,2,0.0009];
结果:
1008606.64947441
0.719   //时间

3、while循环

mvar:
t=sys::clock();
s=0,x=0,
while{x<=1,  //while循环算法;
   y=1,
   while{y<=2,
       s=s+cos(1-sin(1.2*x^(y/2)+cos(1-sin(1.2*y^(x/2))))),
       y=y+0.0009
      },
   x=x+0.0011
},
s;
/1000;
结果:
1008606.64947441
0.734   //时间

qbist 发表于 2010-10-7 14:56

好深奥!~~~~

forcal 发表于 2010-10-8 21:09

本帖最后由 forcal 于 2010-10-8 21:10 编辑

好深奥!~~~~
qbist 发表于 2010-10-7 14:56 http://www.madio.net/static/image/common/back.gif
先了解一下,以备不时之需,有问题可以交流哦,呵呵。

qbist 发表于 2010-10-9 15:54

回复 forcal 的帖子


    嗯!!!

forcal 发表于 2010-10-13 18:52

改进了FcMath中的矩阵乘算法,不知与matlab还有多大差距,朋友们可帮助测一下。

以下是FcMath中的矩阵乘与徐士良算法库XSLSF(普通的C/C++算法)中的矩阵乘的效率比较:

1、FcMath中的矩阵乘
!using["math","sys"];
(:a,b,k,t0)=
oo{
  a=rand, b=rand,
  t0=clock(),
  k=a*b,  //矩阵乘
  k.outm()
},
/1000;
结果:
        238.447        247.837        247.065        248.105        247.058
        244.123        249.925        247.553        243.981        250.016
        236.387        252.025        245.651        248.866        248.866
2.219 秒

2、XSLSF(普通的C/C++算法)中的矩阵乘
!using["math","sys","XSLSF"];
(:a,b,k,t0)=
oo{
  a=rand, b=rand, k=array,
  t0=clock(),
  rmul,  //矩阵乘
  k.outm()
},
/1000;
结果:
        262.121        247.583        260.529        259.548        258.328
        255.413        246.563        254.356        250.548        251.509
        256.152        247.725        259.444        250.827        249.816
10.563 秒

页: [1]
查看完整版本: Forcal数学库FcMath:以矩阵运算为基础