Fortran Coder

查看: 8362|回复: 5
打印 上一主题 下一主题

[数理统计] 大数求阶乘Fortran实现初探

[复制链接]

63

帖子

9

主题

0

精华

专家

超凡脱俗

F 币
474 元
贡献
237 点
跳转到指定楼层
楼主
发表于 2018-2-4 20:21:44 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 Jackdaw 于 2018-2-5 09:05 编辑

丁酉年癸丑月丙寅日,遇群友讨论大数阶乘,遂编制代码实现之,与朋友们分享(我不会说我是为了装X的)。
此文分三部分内容,源码+Makefile+测试结果
测试电脑:Ubuntu 16.04.3 LTS  64-bit  CPU: i5-4210M@2.6GHz


源码:
[Fortran] 纯文本查看 复制代码
001module factorial_mod
002  implicit none 
003  private
004  integer    ,parameter   :: id = 4
005  integer(id)             :: num_zeros
006  integer(id),allocatable :: fact(:)
007  integer(id)             :: n = 12000
008  integer(id),parameter   :: n_digit  = 5
009  integer(id),parameter   :: critical = 10**n_digit
010  integer                 :: up
011   
012  public id
013  public factorial
014   
015contains
016   
017  subroutine init() ! 初始化
018    implicit none 
019    allocate( fact(n) )
020    fact = 0
021    fact( 1 ) = 1
022    num_zeros = 0
023    up = 1 
024  end subroutine init
025 
026  subroutine finalize() ! 结束
027    implicit none
028    deallocate(fact)
029  end subroutine finalize
030 
031  integer(id) function digit( a ) ! 几位数
032    implicit none
033    integer(id),value :: a
034    digit = 1
035    do while ( a .ne. 0 )
036      a = a / critical
037      digit = digit + 1
038    end do
039  end function digit
040   
041  subroutine carry_forward() ! 进位
042    implicit none
043    integer(id)  :: i,j
044    integer(id)  :: tmp
045    do j = n , 1 , -1
046      if( fact( j ) .ne. 0 ) exit
047    end do 
048    up = j
049    do i = 1, up
050      if( fact(i).ge.critical ) then 
051        tmp       = mod(fact(i),critical)
052        fact(i+1) = fact(i+1) + fact(i)/critical
053        fact(i)   = tmp
054        if(i .eq. up) up = up+1
055      end if
056    end do  
057  end subroutine carry_forward
058    
059  subroutine carry_back() ! 退位
060    implicit none
061    integer(id) :: i  
062    do i = 1, up
063      if( fact(i) .ne. 0) exit
064    end do 
065    num_zeros = num_zeros + (i - 1) * n_digit
066    fact(1:up-i+1) = fact(i:up)
067    fact(up-i+2:)  = 0 
068    up = up -i +1
069  end subroutine carry_back
070 
071  subroutine display()  ! 打印结果
072    implicit none
073    integer(id) :: i  
074    do i = up, 1, -1
075      write(*,"(i5.5)",advance="no") fact(i)
076      if(mod(up-i+1,35) .eq. 0) write(*,*)
077    end do 
078    write(*,"(a,g0)") " E+",num_zeros
079  end subroutine display
080   
081   
082  subroutine factorial( num ) ! 阶乘
083    implicit none
084    integer(id),intent(in),value :: num
085    integer(id)                  :: i,j,k,npos
086    integer(id),allocatable      :: mod_i(:)
087    integer(id),allocatable      :: tmp_fact(:)
088    integer(id)                  :: tmp
089 
090    call init()
091    if( .not. allocated(tmp_fact) ) allocate( tmp_fact(n) )
092     
093    do i = 2, num 
094      npos = digit(i)
095      if( .not. allocated(mod_i) )allocate( mod_i(npos) )
096      tmp = i
097      do j = 1, npos
098        mod_i(j) = mod(tmp,critical)
099        tmp = tmp / critical
100      end do
101      if(npos .ge. critical ) then ! 非 n_digit 位数
102        tmp_fact = 0
103        do j = 1, npos
104          if(mod_i(j) .eq. 0) cycle
105          k = up 
106          forall (k = 1:up ) tmp_fact(k+j-1) = tmp_fact(k+j-1) + fact(k) * mod_i(j)
107          do k = 1, up
108            if( tmp_fact( k ) .ge. critical) then 
109              tmp           = mod(tmp_fact(k),critical)
110              tmp_fact(k+1) = tmp_fact(k+1) + tmp_fact(k)/critical
111              tmp_fact(k)   = tmp
112            end if
113          end do  
114        end do
115        fact = tmp_fact
116        call carry_forward()       
117        call carry_back()
118      else ! n_digit 位数
119        forall( k = 1:up ) fact(k) = fact(k) * i
120        call carry_forward()        
121        call carry_back()
122      end if 
123      if(npos.ne. digit(i+1) ) deallocate(mod_i)  
124    end do
125     
126    call carry_forward()
127    call carry_back()
128    call display()
129    call finalize()
130    if( allocated(tmp_fact) ) deallocate( tmp_fact )
131  end subroutine factorial
132end module factorial_mod
133 
134 
135program main
136  use factorial_mod
137  implicit none
138  integer(id) :: t(3)
139  integer(id) :: num  
140  write(*,*) "Please input a positive integer number(not greater than 13500):"
141  read(*,*) num
142  call system_clock(t(1),t(3))
143  call factorial(num)
144  call system_clock(t(2),t(3))
145  write(*,"(a,f7.3,a)") " Time :",(t(2)-t(1))*1.0/t(3) ," s"
146end program main


Makefile:



[Bash shell] 纯文本查看 复制代码
01#!/bin/bash
02FC = gfortran
03FF = -static -O2
04SC = factorial.f90
05XX = x.out
06 
07$(XX) :
08        $(FC) $(FF) $(SC) -o $(XX)
09          
10clean:         
11        rm -rf *.mod *.txt $(XX)



测试结果:


分别为10、  100、 300、  1000的阶乘


10000的阶乘(0.224秒)
ps:屏幕太小放不下了













分享到:  微信微信
收藏收藏1 点赞点赞2 点踩点踩
天下英雄出我辈,一入江湖岁月催。

鸿图霸业谈笑间,不胜人生一场醉。

955

帖子

0

主题

0

精华

大师

F 币
188 元
贡献
77 点

规矩勋章元老勋章新人勋章水王勋章热心勋章

QQ
沙发
发表于 2018-2-4 22:23:33 | 只看该作者
牛逼牛逼
回复

使用道具 举报

490

帖子

4

主题

0

精华

大宗师

F 币
3298 元
贡献
1948 点

水王勋章元老勋章热心勋章

板凳
发表于 2018-2-24 11:06:59 | 只看该作者

63

帖子

9

主题

0

精华

专家

超凡脱俗

F 币
474 元
贡献
237 点
地板
 楼主| 发表于 2018-4-6 10:02:41 | 只看该作者
pasuka 发表于 2018-2-24 11:06
lz为啥不考虑用FFT变换加速整数相乘呢?
http://numbers.computation.free.fr/Constants/Algorithms/repres ...

直接算的,没考虑什么其他的算法,我试试这个
天下英雄出我辈,一入江湖岁月催。

鸿图霸业谈笑间,不胜人生一场醉。

2

帖子

1

主题

0

精华

入门

F 币
93 元
贡献
40 点
5#
发表于 2018-4-12 21:54:49 | 只看该作者
牛叉
回复

使用道具 举报

21

帖子

4

主题

0

精华

熟手

F 币
149 元
贡献
78 点

规矩勋章爱心勋章

6#
发表于 2018-6-20 20:27:06 | 只看该作者
你为何这么吊
您需要登录后才可以回帖 登录 | 极速注册

本版积分规则

捐赠本站|Archiver|关于我们 About Us|小黑屋|Fcode ( 京ICP备18005632-2号 )

GMT+8, 2025-4-15 19:14

Powered by Discuz! X3.4

© 2013-2025 Comsenz Inc.

快速回复 返回顶部 返回列表