Fortran 90 - 分段错误

时间:2012-10-08 06:41:33

标签: fortran fortran90

我正在制作一个将十进制整数转换为二进制表示的程序。这是我的代码:

program test
implicit none
integer, dimension(:), allocatable :: binary
integer :: decimalnum, i, initvalue

print*, "Enter decimal number to convert: "
read*,initvalue

decimalnum = initvalue
i = 0

do while (decimalnum > 0)
    if (MOD(decimalnum,2)==0) then
        binary(i) = 0                  ! this is as far as the program executes up to 
        decimalnum = decimalnum / 2
        i = i + 1
    else if (MOD(decimalnum,2)==1) then
        binary(i) = 1
        decimalnum = (decimalnum -1) / 2
        i = i + 1
    end if
end do
end program test

在标记点,它返回错误Segmentation fault并退出代码139。

为什么会这样?

提前致谢。

4 个答案:

答案 0 :(得分:3)

这是将整数i转换为二进制表示的简单方法:

write(*,'(b16)') i

如上所述,这不会写任何前导0。如果您想要领先的0,请尝试

write(*,'(b16.16)') i

当然,前面的代码将二进制表示写入默认输出单元,但使用Fortran的内部写入功能,我可以轻松地将位写入字符变量。例如:

character(len=16) :: bits
...
write(bits,'(b16.16)') i

i的二进制数字写入字符变量bits

现在,如果您真正想要的是创建一个整数数组,每个整数表示二进制表示的一位,那么就像这样

integer, dimension(16) :: bitarray
...
bitarray = 0
...
do ix = 1,len(bits)
    if (bits(ix:ix)=='1') bitarray(ix) = 1
end do

可能会奏效。

答案 1 :(得分:2)

1)你的崩溃发生是因为你只为数组二进制(:)分配了一个元素,并且While循环可能已经移动到i = 2,此时你的数组是索引越界(崩溃)。

2)Fortran有许多直接处理位的内部函数。例如,

a)Bit_Size(var)返回“var”中的位数,因此如果必须使用allocatable,现在就知道预先需要的数组大小了。

b)BTest(iVar,pos)返回.True。如果iVar中pos的位是1

例如,使用上面的其他声明:

Integer     :: n

n = Bit_Size(decimalnum)    

If( Allocated(Binary) ) DeAllocate(Binary)          ! good practice
Allocate( Binary(1:n) )                             ! in general, should get IOStat, just in case

Binary(:) = 0

ForAll(i=1:n, Mask = BTest( decimalnum, i-1 ) ) ! remember, bit intrinsics index from 0
    Binary(i) = 1
End ForAll

...与Do和While相比,这会更有效,并且可能对smp有所帮助(一点点)。 Where / EndWhere结构也可以使用,但我发现ForAll的效率更高。

c)IBits(var,pos,len)从pos开始为len个位提取位,例如,如果你想创建一个“显式”二进制表示,这可能是一种方法。 / p>

等等

3)如果你“真的意味着”将DecimalNum转换为Bin,那么你有(实质性的)附加问题,如果Dec还包括浮点Dec(即Reals),因为Reals的位表示是以指数表示的。我将假设情况并非如此,因为代码/解释更为复杂。

最后,在Fortran中,Nums通常是“签名”Nums,前导位用于确定+ ve(0)或-ve(1)。因此,如果你进入“其他”方向(Bin2Dec),那么更喜欢一个额外的arg(可能是可选的)来控制结果是有符号还是无符号。如果无符号,那么输出var将需要比输入var更大“(例如,如果将无符号1-byt int转换为Fortran int,则必须使用至少2字节int(即输入Integer(1)必须为输出到整数(2))等。

答案 2 :(得分:1)

根据评论,您需要在定义binary数组之前执行一个allocate语句(或者为您分配的内容)。最简单的分配语句形式类似于ALLOCATE(binary(10)),它将使用默认值给出binary数组10个元素(可以使用allocate语句为该数组更改)起始数组索引为1

在使用数组之前,如果不容易知道分配的大小,则有两种基本方法:

  • 执行两次传递,第一次传递只计算需要多少元素,然后分配数组,然后第二次传递实际上分配给相关元素。
  • 将数组分配给初始大小(可能为零),根据需要逐渐增大数组。

在计算时,与分配和评估每项测试的相对开销相关的使用方法决策存在权衡。

在Fortran 90中(至少要继续使用Fortran 95!),增长可分配数组有点复杂(从原始数据到临时数据分配临时复制数据,解除分配原始数据,将原始数据分配给新大小,复制数据来自暂时恢复原来的大小,释放临时)。在Fortran 2003中,这个操作变得微不足道。

答案 3 :(得分:-1)

所以这可能是糟糕的形式,并且肯定是糟糕的运行时(它为每一位复制数组),但这就是我想出来的。它似乎有效。

  program test
      implicit none
      integer, dimension(:), allocatable :: binary
      integer :: decimalnum, i, initvalue, curSize, curBit


      print*, "Enter decimal number to convert: "
      read*,initvalue

      decimalnum = initvalue
      i = 1
      ALLOCATE ( binary(1) )
      curSize = 1

      DO WHILE (decimalnum > 0)
        IF (i > curSize ) THEN
            curSize = curSize * 2
            CALL expandArray( curSize, i-1 )
        END IF

        IF (MOD(decimalnum,2)==0) then
            binary(i) = 0                  ! this is as far as the program executes up to 
            decimalnum = decimalnum / 2
            i = i + 1
        ELSE IF (MOD(decimalnum,2)==1) then
            binary(i) = 1
            decimalnum = (decimalnum -1) / 2
            i = i + 1
        END IF

      end do
      PRINT*, binary


  CONTAINS
      SUBROUTINE expandArray( newSize, oldSize )
          IMPLICIT NONE
          INTEGER, DIMENSION(:), ALLOCATABLE :: temp
          INTEGER :: j, newSize, oldSize
          ALLOCATE( temp(newSize) )
          DO j=1,oldSize
              temp(j) = binary(j)
          END DO
          DEALLOCATE (binary)
          ALLOCATE( binary(newSize) )
          DO j=1,oldSize
              binary(j) = temp(j)
          END DO
          DO j=oldSize+1,newSize
              binary(j) = 0
          END DO
          DEALLOCATE (temp)
      END SUBROUTINE

  END PROGRAM test