我正在制作一个将十进制整数转换为二进制表示的程序。这是我的代码:
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。
为什么会这样?
提前致谢。
答案 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