w478451384的个人博客分享 http://blog.sciencenet.cn/u/w478451384

博文

C#调用Fortran计算阶乘——第一个C#程序

已有 4892 次阅读 2015-9-17 21:50 |个人分类:C#|系统分类:科研笔记

操作系统:Win10 Professional

IDEVS2015

C#编译环境:.NET Framework 4.5.2

Fortran编译环境:Intel Parallel Studio XE 2015

Fortran生成动态链接库即dll文件(计算部分),C#做界面调用dll(交互界面)。

计算大数阶乘部分参考http://fcode.cn/algorithm-50-1.html.

C#调用Fortran生成的dll要点:

Fortran部分:

1.!DEC$ ATTRIBUTES DLLEXPORT::FFACTORIAL表示生成的dll函数可被外界调用;

2.!DEC$ ATTRIBUTES ALIAS:'FFACTORIAL'::FFACTORIALFortran是大小写不敏感的语言,即ABCDAbCdabcdFortran编译器看来都是一样的,但是其他大多数语言包括C#是大小写敏感的,AaC#中是不同的。Fortran生成的Function或者Subroutine名不管代码中是大写还是小写,最终编译后都是大写的,比如本文中子程序ffactorial在代码中可以写成ffactorial或者FFACTORIAL或者Ffactorial甚至FfAcToRiAl,最终编译后在dll中统一为FFACTORIALVS命令输出dumpbin /exports XXX.dll即可导出函数信息。ALIAS属性可以为函数定义别名,限定其混合书写。

3.!DEC$ ATTRIBUTES STDCALL::FFACTORIALstdcall是函数调用约定的一种,函数调用约定主要约束了两件事:参数从右向左压入堆栈函数被调用者修改堆栈

4.!DEC$ ATTRIBUTES REFERENCE::nLbound, nUbound ,FirstNumber , LastNumber参数传递方式为引用传递。

C#部分:

1.using System.Runtime.InteropServices;增加对动态链接库操作的引用;

2.[DllImport(@"F:\Fortran\FFACTORIAL\FFACTORIAL\Release\FFACTORIAL.dll", CallingConvention = CallingConvention.StdCall)]
       public static extern void FFACTORIAL(ref long a,ref long b,ref double FirstNumber,ref long LastNumber, long[] LongAns);DllImport属性装载传递过来的子例程和相对应的参数;函数调用约定为stdcallref代表参数引用传递。

 


结果演示:

 


 


Fortran部分代码:

 

!nLbound阶乘下界,nUbound阶乘上界(最大32767)

!FirstNumber结果底数部分,LastNumber结果指数部分,ires结果各位具体值

subroutine ffactorial( nLbound, nUbound ,FirstNumber , LastNumber, ires)

!编译功能选项 !DEC$ ATTRIBUTES

!可被外界调用的dll函数
!DEC$ ATTRIBUTES DLLEXPORT::FFACTORIAL

!使用ALIAS(别名)属性指定导出函数名
!DEC$ ATTRIBUTES ALIAS:'FFACTORIAL'::FFACTORIAL

!STD调用方式
!DEC$ ATTRIBUTES STDCALL::FFACTORIAL

!参数传递方式为引用传递(数组默认是引用传递)
!DEC$ ATTRIBUTES REFERENCE::nLbound, nUbound ,FirstNumber , LastNumber
Use, Intrinsic :: ISO_FORTRAN_ENV, only : OUTPUT_UNIT
implicit none
integer(8),parameter  :: pmax = 10**13, len = 10300
integer(8),intent(in) :: nLbound, nUbound
integer(8),intent(out) :: LastNumber, ires(len)
real(8),intent(out)::FirstNumber
integer(8) nL, nU
integer(8) i, j, m, n, cc
character ch*24, CnLbound*5, CnUbound*5
write(CnLbound,'(I5)')nLbound
write(CnUbound,'(I5)')nUbound
ires=0; ires(1)=1
nL = 1; nU = 1
do i = nLbound, nUbound
   ires(nL:nU) = ires(nL:nU) * i
   n = 0
   do j = nL, nU
       if( ires(j)/=0 ) then
           m = ires(j) / pmax
           ires(j+1) = ires(j+1) + m
           ires(j) = ires(j) - pmax*m
           n = 1
       else if( n==0 ) then
       nL = j
       end if
   end do
   if( ires(nU+1) > 0 ) nU = nU + 1
end do
open(OUTPUT_UNIT,file=CnLbound//'_'//CnUbound//'.txt')
write(ch,*) ires(nU)
ch = adjustl(ch)
m = len_trim(ch)  
n = (nU-1)*13+m-1
read(ch(1:m),'(I<m>)')cc
FirstNumber=cc/10.0_16**(m-1)
write(ch,*) n
ch = adjustl(ch)
if( nU > 1 ) then
   write(OUTPUT_UNIT,'(i<m>)',advance='no') ires(nU)
   write(OUTPUT_UNIT,'(<nu-1>i13.13)') ires(nU-1:1:-1)
else
   write(OUTPUT_UNIT,'(i<m>)') ires(nU)
end if
close(OUTPUT_UNIT)
LastNumber=n
end subroutine ffactorial

 


C#代码如下:

 

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.IO;

namespace CF
{
   public partial class Form1 : Form
   {
       public Form1()
       {
           InitializeComponent();
       }

       private void button1_Click(object sender, EventArgs e)
       {
           long a, b;
           long LastNumber = new long();
           long[] LongAns = new long[10300];
           double FirstNumber = new double();
           a = Convert.ToInt32(LowNumber.Text);
           b = Convert.ToInt32(UpNumber.Text);

           FFactorial.FFACTORIAL(ref a, ref b, ref FirstNumber, ref LastNumber, LongAns);

           this.AnswerNumber.Text = Convert.ToString(FirstNumber) + "E" + Convert.ToString(LastNumber);
           int k = 10299;
           for (int i = 10299; LongAns[i] == 0; i = i - 1)
               k = k - 1;
           int j = k;
           for (int i = k; LongAns[i] != 0; i = i - 1)
           {
               this.LongAnswer.Text += Convert.ToString(LongAns[i]);
               j = j - 1;
           }
           for (int i = j; i >= 0; i = i - 1)
               this.LongAnswer.Text += "0000000000000";
       }
   }
   public class FFactorial
   {
       [DllImport(@"F:FortranFFACTORIALFFACTORIALReleaseFFACTORIAL.dll", CallingConvention = CallingConvention.StdCall)]
       public static extern void FFACTORIAL(ref long a,ref long b,ref double FirstNumber,ref long LastNumber, long[] LongAns);
   }
}

 

 

参考文献:

[1] Fcode研讨团队《Fortran求大数阶乘》 http://fcode.cn/algorithm-50-1.html.

[2]C#和Fortran的混合编程http://blog.csdn.net/HanYanBin/article/details/5723101

[3]Fortran95程序设计》彭国伦

[4]C#高级编程(9)

 




https://blog.sciencenet.cn/blog-2827784-921495.html


下一篇:MKL初探——SVD分解
收藏 IP: 27.17.13.*| 热度|

1 宗睿

该博文允许注册用户评论 请点击登录 评论 (1 个评论)

数据加载中...

Archiver|手机版|科学网 ( 京ICP备07017567号-12 )

GMT+8, 2024-5-4 18:39

Powered by ScienceNet.cn

Copyright © 2007- 中国科学报社

返回顶部