1

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

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

4 回答 4

3

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

write(*,'(b16)') i

如所写,这不会写任何前导0s。如果您想要前导0s,请尝试

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

可能会工作。

于 2012-10-08T08:50:02.587 回答
2

1) 发生崩溃是因为您只为数组 binary(:) 分配了 1 个元素,而 While 循环可能已移至 i = 2,此时您的数组的索引超出范围(崩溃)。

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

a) Bit_Size(var) 返回“var”中的位数,所以如果你必须使用可分配的,现在你提前知道所需的数组大小。

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) 从 var 中提取从 pos 开始的位以获得 len 个位数,例如,如果您想创建“显式”二进制表示,这可能是一种方法。

等等等等

3)如果您“真的是指”将 DecimalNum 转换为 Bin,那么如果 Dec 还包括浮点 Dec(即 Reals),那么您将遇到(大量)其他问题,因为 Reals 的位表示是根据指数表示的。我会假设情况并非如此,因为对此的代码/解释要复杂得多。

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

于 2014-06-26T19:22:26.577 回答
1

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

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

  • 做两遍,第一遍简单地计算需要多少个元素,然后分配数组,然后第二遍实际对相关元素进行分配。
  • 将数组分配给初始大小(可能为零),根据需要逐步增长数组。

围绕使用方法的决定与分配相关的相对开销以及计数时每个测试的评估相关,存在权衡。

在 Fortran 90 中(至少是 Fortran 95 的时候了!),增长一个可分配的数组有些复杂(分配一个临时的,将数据从原始复制到临时,释放原始,将原始分配到新的大小,将数据从临时复制回调整原始大小,临时解除分配)。在 Fortran 2003 中,此操作变得微不足道。

于 2012-10-08T08:11:34.107 回答
-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
于 2012-10-08T08:21:44.557 回答