Path: utzoo!yunexus!geac!syntron!jtsv16!uunet!seismo!sundc!pitstop!sun!quintus!ok From: ok@quintus.uucp (Richard A. O'Keefe) Newsgroups: comp.lang.fortran Subject: Re: Fortran 88 Parameterized Data Types Keywords: fortran Message-ID: <566@quintus.UUCP> Date: 25 Oct 88 00:44:40 GMT Article-I.D.: quintus.566 References: <2066@unmvax.unm.edu> Sender: news@quintus.UUCP Reply-To: ok@quintus.UUCP (Richard A. O'Keefe) Organization: Quintus Computer Systems, Inc. Lines: 100 In article <2066@unmvax.unm.edu> brainerd@unmvax.unm.edu (Walt Brainerd) writes: >Each intrinsic data type (REAL, INTEGER, LOGICAL, and CHARACTER) has a >parameter, called its KIND, associated with it. A KIND is intended to >designate a machine representation for a particular data type. >There is an intrinsic function SELECTED_REAL_KIND that produces the >smallest kind value whose representation has at least a certain precision >and range. For example SELECTED_REAL_KIND (8, 70) will produce a kind >(if there is one) that has at least 8 decimal digits of precision and >allows values between 10 ** -70 and 10 ** +70. >For the integer data type, things are pretty much the same, except that there >is only argument for the SELECTED_INT_KIND intrinsic. For example, >SELECTED_INT_KIND (5) produces an integer type allowing representation >of all integers between 10 ** -5 and 10 ** +5. This is very PL/I-ish. DECLARE I DECIMAL FIXED(5,0); There are several things I dislike about this proposal. I'll concentrate on the integer case, because that is simpler. (1) It is too easy to make things machine-dependent when you didn't really mean to. For example, INTEGER(KIND=1) I instead of INTEGER(KIND=SELECTED_INT_KIND(6)) I Let's face it, the latter is so clumsy that people using one specific machine are likely to regard the former as more readable. It would be tempting for a vendor to provide INTEGER(KIND=1) == INTEGER*1 INTEGER(KIND=2) == INTEGER*2 INTEGER(KIND=4) == INTEGER*4 to make it easy for people to convert programs to the new style, and they are likely to stick with that translation. Having used COBOL, with COMPUTATIONAL-1, COMPUTATIONAL-2, and so on, it is difficult for me to regard this KIND= proposal with anything other than distrust and loathing. (2) Like PL/I, this notation does not let you say what you really mean. For example, suppose I want an integer which can represent numbers in the range 0..120 (factorial 6). If I could say INTEGER(LOW=0,HIGH=120) that would convey my intention precisely, and a compiler might notice that 7 or 8 bits will suffice. But if I have to say INTEGER(KIND=SELECTED_INT_KIND(3)) -- 2 is too small -- the compiler has to find a type big enough to hold -1000..1000. Now I might want to say more than this; for example I really might want to say INTEGER(LOW=0, HIGH=120, DIVISOR=2) But an interval is a good compromise, and saying SUBROUTINE FOO(N, A, B) PARAMETER (NMAX = 3000) INTEGER (LOW = 0, HIGH = NMAX) N INTEGER (LOW = 0, HIGH = NMAX*NMAX) K looks like a good idea to me. (I can think of one computer where a Fortran compiler would benefit from having a more precise idea of the subscript range of an array than "16 bits".) It cannot be significantly more complex to support LOW=..HIGH=.. parameters for INTEGER than one KIND=.., the compiler has only to determine SELECTED_INT_KIND(CEILING(LOG10(MAX(ABS(LOW),ABS(HIGH))))) or whatever. (3) Which brings me to my third point, which is that because the KIND= notation requires the programmer to do this calculation (and offhand I'm not sure it's right), it facilitates error. In the example above, we would have to write INTEGER (KIND = SELECTED_INT_KIND(4)) N INTEGER (KIND = SELECTED_INT_KIND(7)) N but the temptation is to think that the 4 must be doubled, giving 8. That might be too big for some machines. (3000**2 = 9000000, which fits in 9 decimal digits.) Worse, because the argument of SELECTED_ INT_KIND is in terms of the decimal logarithm of the numbers, there is a temptation to leave out that step, as I did. If you want your program to keep on working when the bounds change, you have to write INTEGER (KIND = SELECTED_INT_KIND(CEILING(LOG10(NMAX)))) N INTEGER (KIND = SELECTED_INT_KIND(CEILING(2*LOG10(NMAX)))) K It is *much* better to have the compiler do this calculation! And isn't it particularly silly to force the programmer to do base-10 logarithms in his head when the machine is binary? Summary: The INTEGER(KIND=...) notation is more difficult to use than a Pascal- or Ada-like INTEGER(LOW=...,HIGH=...) notation and is more likely to help programmers introduce errors and unintended machine-dependence. Perhaps the genuine numerical analysts reading this newsgroup would care to comment on the REAL(...) proposal. My limited experience suggests that it would be easier to specify expressions and say "this type needs to be able to represent numbers this big, and to distinguish numbers with relative difference this small". For example, REAL (BOUND = NMAX**6, RELERR = NMAX**-3) Now it is possible to write expressions which convert this to number of decimal digits (rather a silly thing to do when computers are base 16 [IBM 370], base 8 [Unisys A-series], or base 2 [most]) and decimal exponent range, but it is rather hairy, and the compiler can do that more easily than I can.