|
本帖最后由 Labradog 于 2016-9-7 12:46 编辑
各位好,前段时间发过一个python利用f2py调用fortran的帖子,下面回复的@pasuka兄弟建议我用Ctypes或是cffi,后来自己了解了一下,综合对比了一下,确实Ctypes更好用。现在有一个小问题,想跟各位请教一下。Fortran代码如下。
[Fortran] 纯文本查看 复制代码 !*****************************************************
! 随机数模块:
! 通过重载分别定义针对数组以及int的过程
!
!*****************************************************
module rand_m
implicit none
interface randi ! 过程重载
module procedure randi_ar ! 数组
module procedure randi_in ! int
end interface
contains
!****************************************
subroutine randi_ar(int_min,int_max,rand_arr)
! 输入:下界,上界,随机数变量--数组
! 输出:随机数变量--数组
implicit none
integer,intent(in)::int_min
integer,intent(in)::int_max
integer,intent(out),dimension(:)::rand_arr
! 局部变量
real,allocatable,dimension(:)::temp
if (.not. allocated(temp)) allocate(temp(size(rand_arr)))
call random_seed()
call random_number(temp)
rand_arr=abs(int_max-int_min)*temp+min(int_min,int_max)
! 返回rand_arr:随机数组
end subroutine randi_ar
subroutine randi_in(int_min,int_max,rand_int)
! 输入:下界,上界,随机数变量--int
! 输出:随机数变量--int
implicit none
integer,intent(in)::int_min
integer,intent(in)::int_max
integer,intent(out)::rand_int
! 局部变量
real::temp
call random_seed()
call random_number(temp)
rand_int=abs(int_max-int_min)*temp+min(int_min,int_max)
! 返回rand_int:随机数--int
end subroutine randi_in
end module rand_m
module OM_module
use,intrinsic::iso_c_binding
use rand_m
implicit none
contains
subroutine rand_nucle(arr,nucle_num,n1,n2)
!dec$ attributes dllexport,decorate,alias:"rand_nucle" :: rand_nucle
implicit none
integer(kind=c_int),intent(in),value::n1,n2,nucle_num
integer(kind=c_int),intent(out),dimension(n1,n2)::arr
integer::nval=1
integer,allocatable,dimension(:)::temp_index ! 二维数组两个索引,不需要改动
real::i,j
if (.not. allocated(temp_index)) allocate(temp_index(2)) ! 二维数组两个索引,数字2不需要改动
do while (nval<=nucle_num)
call randi(1,n1,temp_index(1))
call randi(1,n2,temp_index(2))
if (arr(temp_index(1),temp_index(2))<=0) then ! 注意一定是小于等于,只有小于会一直执行条件语句
call randi(1,180,arr(temp_index(1),temp_index(2)))
nval=nval+1
end if
end do
deallocate(temp_index)
end subroutine rand_nucle
end module OM_module
!*****************************************************
program test
use OM_module
implicit none
integer,dimension(5,5)::arr
integer::n1,n2,n3
arr=0
n1=5
n2=5
n3=2
write(*,*) arr
write(*,*) "*************"
call rand_nucle(arr,n3,n1,n2)
write(*,*) arr
end program
代码主要是在一个全0二位数组中随机生成几个正整数。
Test之后证明Fortran代码没得问题,不管写的怎么样,反正能实现我的想法。
fortran 命令行编译dll:ifort /dll test.F90 生成test1.dll。
Python代码如下:
[Python] 纯文本查看 复制代码 #! /usr/bin/env python
#coding=utf-8
import numpy as np
from numpy.ctypeslib import load_library,ndpointer
from ctypes import *
# shape of 2d array
n1,n2 = 10,10
n3=3
# create an empty 2d array
data = np.zeros(shape=(n1,n2),dtype='int64',order='f')
flib = load_library("test1.dll","./")
flib.argtypes = [ndpointer(dtype='int64',ndim=2),c_int,c_int,c_int]
flib.rand_nucle(data.ctypes.data,n3,n1,n2)
print "*"*80
print data
从python中传入一个全0二维矩阵,运算完后返回,运行之后矩阵变成了如下图:
显然有两个数字太大了,完全不对。我在Fortran中设定的是1-180之间的正整数,在fortran中test也正常。为何python调用之后成了这个样子,百思不得其解,还请各位帮忙看看。
PS:Fcode兄弟提醒后把Python中int64改成int就OK了,我会继续想怎么让ifort默认int64。改后得到的结果在第二张图片上。
|
|