12
\$\begingroup\$

In keeping with using FizzBuzz as an introduction to a language, I present FizzBuzz with a Fortran95 twist:

For multiples of 3, print Fort, and for 5's multiples print Ran. For multiples of both, print FortRan.

Looking especially for style and common practice criticisms. A hint on how to left-justify the values in a standard way would be appreciated too.

The following code is presented in Ideone too:

program fizzbuzz
implicit none
integer ::i

! Loop through integers 1 through 100
! Multiples of 3 print Fort
! Multiples of 5 print Ran
! Multiples of both print FortRan
! 15 is the lowest common multiple of 3, and 5
!    and thus is a shortcut to FortRan

do i=1,100
    if (MODULO(i, 15) == 0) then
        write (*,'(A8)') 'FortRan'
    else if (MODULO(i, 3) == 0) then
        write (*,'(A8)') 'Fort'
    else if (MODULO(i, 5) == 0) then
        write (*,'(A8)') 'Ran'
    else
        write (*,'(I8)') i
    end if
end do

end program fizzbuzz
\$\endgroup\$
4
\$\begingroup\$

I find MODULO() to be jarring, when everything else is written in lowercase. Be consistent.

To left-justify strings in the output, write it using a * format. Since you want to write to standard output, you can simplify it by using print instead.

To left-justify numbers in the output, first convert it to a string, then strip leading spaces.

program fizzbuzz
implicit none
integer ::i
character(len=8) :: str

! Loop through integers 1 through 100
! Multiples of 3 print Fort
! Multiples of 5 print Ran
! Multiples of both print FortRan
! 15 is the lowest common multiple of 3, and 5
!    and thus is a shortcut to FortRan

do i=1,100
    if (modulo(i, 15) == 0) then
        print *, 'FortRan'
    else if (modulo(i, 3) == 0) then
        print *, 'Fort'
    else if (modulo(i, 5) == 0) then
        print *, 'Ran'
    else
        write (str, '(i8)') i
        str = adjustl(str)
        print *, str
    end if
end do

end program fizzbuzz
\$\endgroup\$
  • \$\begingroup\$ You can also format the number to just print as many digits as needed by using the i0 formatting string. I don't think print simplifies the output statements. \$\endgroup\$ – haraldkl Oct 12 '14 at 0:30
2
\$\begingroup\$

As far as I know, there's nothing substantial to improve.

It's clear, and the program is of trivial size. So any ideas about future extensibility are irrelevant.

Nitpicks:

100 is a magic number explained only by a comment, use fizzBuzzLimit or whatever the case convention for fortran is.

The write function looks weird (Disclaimer: I am not a fortran programmer), maybe wrap it in a helper function (do you even have those in fortran?) so your code reads cleaner.

\$\endgroup\$
2
\$\begingroup\$

There is little to criticize. As I commented above, you can also left adjust integers by the i0 format descriptor. I would also intend the main program.

As Fortran actually stands for Formula Translator, I think it would be more appealing to use a split into For and Tran. If you use Trans, you then would even replace the numbers by letters of the numbers values. I also use Doxygen for documentation of Fortran code, and think its syntax is rather unobtrusive. Thus, it usually does not hurt to use it. Finally it is good practice to put functionality into routines, and routines into modules. Though, this might be a little over the top for such a small example, I think it is illustrative to use it her as well. Therefore, here is my suggestion:

!> A module that implements the FizzBuzz series.
module fizzbuzz_module
  use iso_fortran_env, only: output_unit

  implicit none

  private

  public :: write_fizzbuzz

contains

  !> Write a series of fizzbuzz to unit.
  !!
  !! This writes all the numbers from lb to ub to unit, but replaces:
  !! - multiples of 3 by For
  !! - multiples of 5 by Tran
  !! - multiples of both, 5 and 3 by ForTran
  subroutine write_fizzbuzz(ub, lb, unit)
    !> Upper bound up to which the series is to be written.
    integer, intent(in) :: ub

    !> Lower bound, where the series should start, defaults to 1.
    integer, optional, intent(in) :: lb

    !> File unit to write the fizzbuzz series to, defaults to stdout.
    !!
    !! The file has to be opened as formatted file with sequential access
    !! and an allowed action to write.
    integer, optional, intent(in) :: unit

    integer :: i
    integer :: loc_lb
    integer :: loc_unit

    if (present(lb)) then
      loc_lb = lb
    else
      loc_lb = 1
    end if

    if (present(unit)) then
      loc_unit = unit
    else
      loc_unit = output_unit
    end if

    do i=loc_lb,ub
      ! 15 is the lowest common multiple of 3, and 5
      !    and thus is a shortcut to ForTran
      if (modulo(i, 15) == 0) then
          write (loc_unit,'(A7)') 'ForTran'
      else if (modulo(i, 3) == 0) then
          write (loc_unit,'(A3)') 'For'
      else if (modulo(i, 5) == 0) then
          write (loc_unit,'(A4)') 'Tran'
      else
          write (loc_unit,'(I0)') i
      end if
    end do

  end subroutine write_fizzbuzz

end module fizzbuzz_module


!> Small program to illustrate and test the fizzbuzz module.
program test_fizzbuzz
  use fizzbuzz_module, only: write_fizzbuzz

  implicit none

  ! Write a fizzbuzz series from 1 to 100 to stdout:
  call write_fizzbuzz(ub=100)

  ! Write the next 100 entries of the fizzbuzz series to stdout:
  call write_fizzbuzz(lb=101, ub=200)

end program test_fizzbuzz

By using the private statement in the module, you do not export the output_unit to the using program units, but limit the parts that should be visible to those, you explicitly declare as public. The only clause in the use statement also restricts, what you import from the module, but I use it mainly to indicate, where what is coming from.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.