我如何在 Fortran 中处理大整数?

How do I do big integers in Fortran?

我需要生成一些大整数。请参阅下面的示例。

Input   Result    
 40 165580141    
 80 37889062373143906    
120 8670007398507948658051921    
160 1983924214061919432247806074196061    
200 453973694165307953197296969697410619233826

这是我的 Fortran 代码:

program cycle
    use iso_fortran_env
  implicit none
  character(200) :: str
  integer :: n
    integer(kind=int64) :: x1, result, x2, x3

    do n = 40, 500, 40
        x1 = n
        result = 1
        x2 = 0
        x3 = 1
        do 
            if (x1 > 1) then
                x2 = result
                result = result + x3 
                x3 = x2     
                x1 = x1 - 1
            else
                exit
            end if
        end do
        write(str,'(i64)')  result
        print *, n, adjustl(str)
    end do
end program cycle

这是示例输出:

 40 165580141 
 80 37889062373143906 
120 790376311979428689  
160 9217463444206948445 
200 3721511182311577122 

如您所见,它得到了前两个数字,但其余数字超出了 64 位整数的范围。我看过其他问题 (1),但我真的对一种简单的方法很感兴趣,最好是内置在语言本身中。在 Ruby 和 Go 中,我几乎没有遇到什么麻烦。我是否忽略了 Fortran 中明显的东西?我可以在我的代码中使用更好的选择吗?

没有内置的 "big number" 支持,但我们可以先检查是否有更大的整数类型可用(如上面 Francescalus 和许多之前的页面所述(例如 this page) .在我的gfortran-6.1电脑上,编译器似乎支持128位整数类型,所以我可以计算出n=160左右的结果

program cycle
...
integer, parameter :: verylong = selected_int_kind(32)
integer(verylong) :: x1, result, x2, x3

print *, "int32 = ", int32   !! from iso_fortran_env
print *, "int64 = ", int64
print *
print *, "kind..(16) => ", selected_int_kind(16)  !! 8
print *, "kind..(32) => ", selected_int_kind(32)  !! 16
print *, "kind..(40) => ", selected_int_kind(40)  !! -1 (not available)
print *, "kind..(64) => ", selected_int_kind(64)  !! -1 (not available)
print *
print *, "sizeof(x1)       = ", sizeof(x1), "(bytes)"       !! GNU extension
print *, "storage_size(x1) = ", storage_size(x1), "(bits)"  !! F2008
print *, "huge(x1)         = ", huge(x1)                    !! largest integer
...

结果:

 int32 =            4
 int64 =            8

 kind..(16) =>            8
 kind..(32) =>           16
 kind..(40) =>           -1
 kind..(64) =>           -1

 sizeof(x1)       =                    16 (bytes)
 storage_size(x1) =          128 (bits)
 huge(x1)         =  170141183460469231731687303715884105727

 n=          40 res= 165580141
 n=          80 res= 37889062373143906
 n=         120 res= 8670007398507948658051921
 n=         160 res= 1983924214061919432247806074196061
 n=         200 res= 37016692776042937155243383431825151522
 n=         240 res= -159769225356713774587328406036589956191
 ...

虽然没有内置的 "BigInt" 类型,但使用外部库(例如 fmlib linked from this page)是相当简单的。由于各种运算符和赋值重载,您的代码几乎不需要修改。

程序:

1) 下载文件 FMfiles.zip 并提取 FM.95FMZM90.f95FMSAVE.f95

2) 制作库文件为

gfortran -c -O2 FMSAVE.f95 FMZM90.f95 FM.f95
ar rv fmlib.a FM*.o

3) 修改你的代码如下(修改部分用箭头标示)

program cycle
    use FMZM           !<----- a module for handling big numbers
    implicit none
    character(200) :: str
    integer :: n
    type(IM) :: x1, result, x2, x3     !<----- IM = BigInt, FM = BigFloat

    do n = 40, 500, 40
        x1 = n
        result = 1
        x2 = 0
        x3 = 1
        do 
            if (x1 > 1) then
                x2 = result
                result = result + x3 
                x3 = x2     
                x1 = x1 - 1
            else
                exit
            end if
        end do
        str = IM_format( 'i200', result )   !<----- convert BigInt to string
        print *, n, trim( adjustl(str) )    !<----- print huge integers
    end do
end program cycle

4)编译(假设"test.f90"就是上面的代码):

gfortran test.f90 fmlib.a
./a.out

5) 结果

   n result
  40 165580141
  80 37889062373143906
 120 8670007398507948658051921
 160 1983924214061919432247806074196061
 200 453973694165307953197296969697410619233826
 240 103881042195729914708510518382775401680142036775841
 280 23770696554372451866815101694984845480039225387896643963981
 320 5439356428629292972296177350244602806380313370817060034433662955746
 360 1244666864935793005828156005589143096022236302705537193166716344690085611761
 400 284812298108489611757988937681460995615380088782304890986477195645969271404032323901
 440 65172495098135102433647404982700073500075401759827878315356483347951218369680224170989749666
 480 14913169640232740127827512057302148063648650711209401966150219926546779697987984279570098768737999681

我们可以通过注意到 nresult 实际上等于 n = 480fibonacci(n+1), so for example we have fibonacci(481) 来验证结果。