RosettaCodeData/Task/Fusc-sequence/Fortran/fusc-sequence.f
2026-04-30 12:34:36 -04:00

185 lines
5.2 KiB
Fortran

!
! Fusc sequence
! tested with Intel ifx (IFX) 2025.2.1 20250806 on Kubuntu 25.04
! GNU Fortran (Ubuntu 14.2.0-19ubuntu2) 14.2.0 on Kubuntu 25.04
! VSI Fortran x86-64 V8.6-001 on OpenVMS x86_64 V9.2-3
! No Non-standard features used, should compile on any fairly recent Fortran.
! U.B., September 2025
program FuscNumbers
implicit none
integer, parameter :: kInt = 4
integer, parameter :: maxdigs = 6
integer, parameter :: strLen = 20
integer (kind=kInt), allocatable :: fuscMem(:)
integer :: capacity, content ! usage of above container
integer (kind=kInt) :: w,c,t
integer (kind=kINt) :: i, f
integer :: d=0, n=61, digs=1
character (len=strLen) :: sNum(2) ! for formatted output of integer numbers
content = 0
capacity = 1024
call resize (fuscMem, capacity)
call push (0)
call push (1)
w = -1
c = 0
n = 61
write ( *, '("First " , i0, " numbers in the fusc sequence:" )') n
i = 0
do while (i .lt. 61)
f = fusc(i)
if (mod (i, 20) .ne. 0) then
write (*, '(i2, x)', advance='no' ) f
else
write (*, '(i2,x)') f
endif
i = i + 1
end do
write (*, '(/"Fusc numbers with more digits than any previous (1 to 6 digits):")')
write (*, '( " Index Value")')
i = 0
do while (digs <= maxdigs)
f = fusc (i)
if (f .ge. d) then
! show all numbers with commas (if appropriate).
snum(1) = GroupedDigits(i, 10)
snum(2) = GroupedDigits(f,10)
if (digs .gt.1) then
write (*,'(i2, " digits: ", A10,x,A )' ) digs, snum(1), snum(2)
else
write (*,'(i2, " digit : ", A10,x,A )' ) digs, snum(1), snum(2)
endif
if (d .eq. 0) then
d = 10
else
d = d * 10
endif
digs = digs + 1
if (digs .gt. 6) exit
end if
i = i + 1
end do
contains
function fusc (n) result (ret)
integer (kind=kint), intent(in) :: n
integer (kind=kInt) ret
if (n .lt. content) then
ret = fuscMem (1+n)
else
if (iand (n,1_kint) .eq. 0) then ! Even n has bit 0 = zero
ret = fuscMem(1+n/2)
call push (ret) ! Store for future use.
else ! Else its odd.
ret = fuscMem(1+(n-1)/2) + fuscMem(1+(n+2)/2)
call push (ret)
end if
end if
end function fusc
! ---------------------
! memoize another value
! ---------------------
subroutine push (k)
integer (kind=kint), intent (in) :: k
content = content+1
! If we would exceed capacity of array 'Words', we need to increment capacity
if (content .gt. capacity) then
capacity = 2*capacity
call resize (fuscMem, capacity)
end if
fuscMem(content) = k
end subroutine push
! ----------------------------------------------
! Increase allocated size of dynamic array 'var'
! ----------------------------------------------
subroutine resize(var, newSize)
integer (kind=kint), allocatable, intent(inout) :: var(:) ! The array to be increased
integer, intent(in) :: newSize ! The new size of var
integer (kind=kint), allocatable :: tmp(:) ! Temporary storage
integer :: oldSize ! Current array size
integer :: ii ! Loop index
! Copy allocated values to temporary, then allocate var with
! new size and copy back saved values.
! Could be done with move_alloc but this would not be portable to OpenVMS Fortran
if (allocated(var)) then
oldSize = size(var)
else
oldSize = 0
end if
if (newSize .gt. oldSize) then ! only increment
if (oldSize .gt.0) then
allocate(tmp (oldSize))
tmp(:oldSize) = var(:oldSize)
deallocate (var)
end if
allocate(var(newSize))
if (allocated(tmp) .and. allocated (var) ) then
oldSize = min(size(tmp, 1), size(var, 1))
var(:oldSize) = tmp(:oldSize)
deallocate (tmp)
end if
end if
end subroutine resize
! ----------------------------------------------------------------
! Fortran does not have a way to use locales for output.
! Manual insert of separating commas such as 1,345,678 for 1345678
! ----------------------------------------------------------------
function GroupedDigits (n, width) result (outStr)
integer(kind=kint), intent (in) :: n
integer :: width
character (len=width) :: outStr
character (len=2*strLen) :: workStr
integer :: ii, jj, cnt, trueLen
! Write n into a string, then copy the digits to a second string,
! inserting separater after every 3 digits.
write (workStr, '(i0)') n
! Adjust left, then cutoff trailing blanks
workstr = adjustl (workstr)
trueLen = len_trim (workStr)
outStr = ' '
jj = width
cnt = 0
do ii=trueLen, 1, -1 ! Copy backwards for correct grouping.
outStr (jj:jj) = workStr (ii:ii)
jj = jj -1
cnt = cnt + 1
! Insert comma after 3 digits, but only if more digits follow.
if (mod (cnt, 3) .eq. 0 .and. ii .gt. 1 .and. workStr(ii-1:ii-1) .ne. ' ') then
outStr (jj:jj) = ','
jj = jj - 1
endif
end do
end function GroupedDigits
end program FuscNumbers