6
\$\begingroup\$

This is my first step into Fortran. The program aims to provide a simple way of calculating numbers. Just looking for improvements in general.

program Calc
    real :: a, b, additionAnswer, subtractionAnswer, multiplicationAnswer, divisionAnswer
    print *, "George Gibson's Calc"
    print *, "Type the first number: "
    read *, a
    print *, "Type the second number: "
    read *, b
    additionAnswer = a + b
    subtractionAnswer = a - b
    multiplicationAnswer = a * b
    divisionAnswer = a / b
    print *, a, " + ", b, " = ", additionAnswer
    print *, a, " - ", b, " = ", subtractionAnswer
    print *, a, " * ", b, " = ", multiplicationAnswer
    print *, a, " / ", b, " = ", divisionAnswer
    read *
end program Calc
\$\endgroup\$
3
\$\begingroup\$

Functions

A more "Fortrany" way to do this might be to put calculations in their own functions,

program Calc
   implicit none
   ...
    print *, a, " + ", b, " = ", AddTwoNums(a,b)
    print *, a, " - ", b, " = ", SubTwoNums(a,b)
    print *, a, " * ", b, " = ", MultTwoNums(a,b)
    print *, a, " / ", b, " = ", DivTwoNums(a,b)
 contains
    pure function AddTwoNums(a,b) result(c)
       real, intent(in) :: a,b
       real :: c
       c = a + b
    end function AddTwoNums
    ...
 end program

where the ellipses (...) mean I'm skipping over the other details. The pure specifier gives details to the compiler that can optimize/vectorize it in some cases (probably not much it can do here, but for some more complex cases it might be useful).

Output

You might also want to specify formats for the output. Since you're using single-precision, you probably want to output the first 6-7 decimal digits,

print '(f12.6,a3,f12.6,a3,f12.6)', a," + ", b, " = ", AddTwoNums(a,b)

The f12.6 means it's a floating-point type number with 12 total digits and 6 after the decimal, a3 means it is a character string of length 3 (you can make this one simply a and let the compiler figure it out).

Precision

Single precision is nice, but you can do better; and there's a few ways how:

-ISO_FORTRAN_ENV (needs Fortran 2008 or later compiler)
Within this big module is the real32, real64, and real132 types

Kind type parameters to specify a REAL type with a storage size of 32, 64, and 128 bits. It is negative if a target platform does not support the particular kind. (Fortran 2008 or later.)

and would be used as

program Calc
   use iso_fortran_env
   real(kind=real64) :: a, b
   ...

-ISO_C_BINDING (need Fortran 2003 or later compiler)
This module is for improved compatibility with C programs/functions. Within it are C_double and C_long_double types that will match the equivalent C types. This would be used as

program Calc
   use iso_c_binding
   real(kind=c_double) :: a, b
   ...

-Kind specifier (part of the 1990 standard)
This is the default way to specify the precision without useing a module. This is done as

program Calc
   integer, parameter :: wp = selected_real_kind(15,307)
   real(kind=wp) :: a, b
   ...

where wp is typically short for "working precision" (some people choose to append an underscore in case they want to use wp as a variable). The first number in selected_real_kind is the decimal precision and the second number is the exponent range (-307 to +307). You are also not restricted to using integers associated with any particular precision (single or double) here, you can choose to use selected_real_kind(10,40), for instance. Fortran 2003 standards specify that absent values for the precision & radix are assumed to be zero.

Comments

This is general and not specific to Fortran, but I'm a big fan & proponent of comments. Even when it's absolutely trivial & blatantly obvious what is being done on the line below, it benefits you (as practice for the more complex computations) and potential future readers (so that they know what is being done & why).

\$\endgroup\$
1
\$\begingroup\$

The most important omission in your program is an implicit none statement. I'd claim the program to be erroneous because of that. For any little more complex application it will become difficult to keep track of your variables, and you might end up with subtle changes in the behavior. Thus, the strong advice to always use the implicit none statement. I'd also use some more line breaks and not put all variables on a single line. Personally, I prefer the write(* ,* ) notation over print, but that's probably just personal style.

I am not quite sure, what the last read is for?

So, here is a suggestion:

program Calc

    implicit none

    real :: a, b
    real :: additionAnswer, subtractionAnswer
    real :: multiplicationAnswer, divisionAnswer

    write(*,*) "George Gibson's Calc"
    write(*,*) "Type the first number: "
    read(*,*) a

    write(*,*) "Type the second number: "
    read(*,*) b

    additionAnswer = a + b
    subtractionAnswer = a - b
    multiplicationAnswer = a * b
    divisionAnswer = a / b

    write(*,*) a, " + ", b, " = ", additionAnswer
    write(*,*) a, " - ", b, " = ", subtractionAnswer
    write(*,*) a, " * ", b, " = ", multiplicationAnswer
    write(*,*) a, " / ", b, " = ", divisionAnswer
end program Calc
\$\endgroup\$

Your Answer

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