(j3.2006) Units of measurement in Fortran
Van Snyder
van.snyder
Wed Apr 20 06:21:33 UTC 2011
I was an official reviewer for DoD-1, which became Ada. I tried in
about 1981-1983 to convince DoD to include units in Strawman, then in
Woodenman, then in Tinman, then in Steelman, then in Red, Green, Yellow,
and Blue, then in Ada when it finally had a name. Colonel Whittaker
said "Huh?"
I tried in 1986 to convince X3J3 to add units to Fortran 90.
I tried in 1997 to convince J3 to add units to Fortran 2003.
I tried in 2004 to convince J3 to add units to Fortran 2008.
It is astonishing to me that Fortran, the language whose proponents
claim is the premiere vehicle for computations to support science and
engineering, does not provide support for systems of measurement.
I have completed a draft of a TR to provide units of measurement in
Fortran. I will propose it as a work item for the next revision of
Fortran, either as a TR, or to be incorporated directly into the next
work plan.
I have put the draft in the Tutorials directory on the server. Its name
is Units-TR-7.pdf.
The front matter is five pages. Then one page of boilerplate. Then
fifteen pages of requirements plus one page describing related
functionality not requested. then fourteen pages of proposed edits to
10-007r1.
Dick Hendrickson gave me some useful feedback on an earlier revision.
Additional feedback is welcome.
During the last six or so months, I have read nearly a dozen papers on
the topic of units of measurement in programming languages, going back
to about 1983.
There have been two broad methods proposed:
1. Support for units of measurement are faked by overloading arithmetic
operations, usually by replacing floating-point numbers by derived type
objects ("records" in Pascal or Ada, which were the most common vehicles
addressed by the papers I read).
2. Units of measurement are an intrinsic part of the language.
The advantage of (1) is that it doesn't need changes in the language.
The disadvantages are numerous, and include
1a. An enormous number of procedures if kind type parameters are used
for exponents of the fundamental units.
Consider the seven fundamental units of physical quantities that SI
defines: Length, Time, Mass, Thermodynamic temperature, Electric
current, Amount of a substance, and Luminous Intensity.
In physical problems, one needs the exponent range to be (at least)
-3..3 for length, -2..1 for time, -2..2 for mass, and -1..1 for the
rest. Multiply these out, then multiply by the number of kinds of real
numbers, and you have the number of functions you need in order to
overload unary operators (22,680 or 34,020). Square it and you have
have the number needed in order to overload binary operators
(514,382,400). The result is over two billion for three unary
operators (count exponentiation as unary since the exponent has to be
unitless) and four binary ones (2,057,597,640). If you want to add
radians, which SI doesn't count as a fundamental unit, multiply by a
skosh more than four. If you want fractional exponents, even only ones
that can have a denominator of only either 1 or 2, square it again.
Then explain how the units of the result of exponentiation get computed
by the processor if kind type parameters are used. This doesn't count
assignment or I/O. Add another hundred thousand procedures or so.
Too bad we removed macros from the 2008 work plan.
1b. There is a runtime penalty if components or length type parameters
are used. Yeah, it can be turned off by changing the guts of the
derived type to just the value, and crossing your fingers and hoping
that the compiler optimizes away the functions by inlining them. As
Dijkstra said, this makes as much sense as the hostess on the airplane
telling you to buckle your seatbelt before the airplane is pushed out
from the gate, and then coming around and taking it away after you've
taxied out to the end of the runway and are preparing to take off. The
problem that doomed the Mars Climate Orbiter was a runtime problem.
1c. It's difficult to include I/O processing of units. About as
difficult as faking namelist.
1d. If you want units of measure, which SI calls "dimensions" instead of
units, you need more fields (floating-point ones instead of integers) in
the derived-type object that represents each floating-point number, and
more runtime work. By dimensions, I mean things like meters and feet,
seconds and days, kilograms and pounds,... instead of the more abstract
length, time, mass. This work can't be turned off by deleting the
components because then the distinction between pound-seconds and
Newton-seconds disappears. It also doesn't get optimized away when the
quantities in the operation are the fundamental quantities of your
system (e.g. meters, seconds kilograms), for which the scale factors
happen to be 1.0 and the offsets happen to be 0.0.
1e. If you want units other than physical units, such as dollars or
pound sterling for financial work, you need more components, or more
length or kind type parameters, and more functions. If you want units
that aren't simply powers of fundamental units, for example decibels,
you need yet more.
1f. Nobody does it because of the above problems. Would you like to
write a few hundred functions (or maybe a few thousand) for your
particular application, or would you only use the facility if you had a
library? Do you really expect to have a library of two billion functions?
The advantage of (2) is that it has few of the disadvantages of (1).
Especially the last one. If units of measure were an intrinsic part of
the language, they would be used. The disadvantages of (2) are
2a. It requires changes in the language.
2b. Support for units of measure (i.e. dimensions such as feet and
meters instead of fundamental abstractions such as length) requires
runtime action, but the processor sees that requirement in the
declaration of objects and can optimize it.
More information about the J3
mailing list