Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Posting-Version: Notesfiles hp 2.0 03/25/85; site hpislb.UUCP Path: utzoo!watmath!clyde!burl!ulysses!mhuxr!mhuxt!houxm!vax135!petsd!pesnta!hplabs!hpisla!gore From: gore@hpisla.UUCP (Jacob Gore) Newsgroups: net.lang Subject: Re: What language do you use for scientific programming? Message-ID: <64500002@hpislb.UUCP> Date: Mon, 19-Aug-85 01:57:00 EDT Article-I.D.: hpislb.64500002 Posted: Mon Aug 19 01:57:00 1985 Date-Received: Sun, 25-Aug-85 01:52:30 EDT References: <909@oddjob.UUCP> Organization: HP Instrument Systems Lab - Loveland, CO Lines: 240 ># Written 9:23 pm Aug 12, 1985 by paul@oddjob.UUCP in net.lang > >I've been curious for a while what scientist/engineering types on the net >use for scientific programming. I know the low regard in which fortran is >held by the systems types on the net, but I haven't found anything better >than fortran to use. I'm a "software engineering type" full-time, and "systems type" part time. Still, you might find my reply useful. I'm posting this instead of mailing it to you, as you asked, because it might draw some corrections from folks on the net. THIS IS RATHER LONG, but I think you and people who share your questions will find this interesting. Sorry to throw another language at you (I see somebody's already proposed a LISP), but if I were you, I would try using Ada. Let me try to address your problems a few at a time: >I am learning Pascal and Modula-2, but they have the major >weaknesses of no double precision data type (...), clumsy i/o, and no >exponentiation operator. C shares the last two weaknesses. Ada is quite similar to Pascal and Modula-2. It does have double-precision real types. In fact, you can pretty much specify arbitrary precision, as long as you keep in mind that your program will run faster if there is a hardware data type in your machine that can support the precision that you asked for (otherwise, you could be executing lots of simulation code). Ada follows the philosophy that anything that can be safely put into a library should not be a burden to the compiler. Following this philosophy, I/O is not "built into the language" (which usually means that I/O routines are in the library anyway, but the compiler has to parse calls to those routines differently from calls to user-written routines). DoD (who set the requirements for the language) does require provision of library routines that do minimal I/O, in the manner similar to that of Modula-2, but slightly more convenient. If you are used to formatted I/O, you probably won't like them. However, routines for formatted I/O might be available from whoever sells you the compiler, and if they aren't, you can write them yourself (though most "scientific/engineering types" probably won't want to), and it will fit right in with the supplied libraries. There is a built-in exponentiation operator ('**'), but it is only defined for the** operation (i.e., the power must be integer). Again, a more general '**' operator may be provided in the libraries, and if it's not, you can write your own. You can even call it '**' and use it exactly as you would use the original operator -- Ada figures out from the types of the operands which operator to use. >The advantages of fortran in my opinion are 1. >at least two real precisions, 2. standard and powerful i/o routines, and 3. >very wide availability with great portability (because of the existance of a >standard for the language). Is there any other language which shares these >properties but also has some of the constructs I would like to use (while, >do ... while, case, structures, pointers). Ada is portable. DoD will not let anyone call a compiler "an Ada compiler" unless it follows the standard to the letter. There are some provisions for writing machine-dependent code, but you usually have to go out of your way to use them. These are usually of concern to us "system types." Availability is another matter -- there are not too many compilers around, certainly not as many as there are FORTRAN compilers. Still, there are quite a few, especially for larger machines (VAX and above, and I think even some 68000's). Ada has the programming constructs you want. It has pointers. It has structures (with pitfalls of Pascal structures eliminated). It has some convenient features that neither Pascal nor FORTRAN (nor Modula-2, for that matter) offer, and I'll talk about them after we're done with your questions. >Perhaps the answer is fortran >itself; what new features does the upcoming revision to the fortran standard >have? Yes, FORTRAN-77 has a lot of what you want (perhaps everything), but other people have already posted replies about it, so I won't repeat them. I would still use Ada instead of FORTRAN-77. Did you ask about complex numbers? Most of my "scientific type" friends want complex numbers. Well, the story here is the same as with I/O and exponentiation. Complex numbers are handled by a library package which defines representation of the numbers, as well as the '+', '-' and whatever other operators may be applicable. In fact, it may define a '+' to add a complex to a complex, a complex to a real, a real to a complex. They all have the same name ("+"), but Ada will figure out which one to call from the types of the operands (during compilation). Note that the representation of complex numbers is quite irrelevant with this arrangement: if you decide that for your program will run faster if they are stored as (angle, magnitude) instead of (real, imaginary), you simply change the inside of the library package, and the program that uses it will not be affected. Now for features that you probably haven't thought of since they are not in FORTRAN. Some of these are especially useful if you are writing mathematical (or any other type) libraries for use by other people (customers). As you probably began to suspect from my replies above, it is very easy to write self-contained, complete, and easy-to-use libraries. The features that help this are: (1) Automatic initialization of local data. I've seen people go through a lot of pain to initialize data that routines in a library need for more than just the duration of one routine call. The tricks usually involve checking if a routine is called for the first time, and if so, the data is initialized. Ada does this at compile-time (load-time, technically). By the time the library is loaded into memory, its static data is initialized. (2) Error signalling. In FORTRAN, when a customer calls your routine with bad input parameters (or at the wrong time, etc.), you have two options: (a) Let the program die. (b) Detect that an error is about to occur and set some global flag or a special ERROR parameter. I think method (a) stinks, mostly because the user gets a message like "Floating-point exception in ", instead of something like "The second coefficient cannot be zero, see ". However, it is used quite often because the second method is inconvenient to use: after each call to your library routine, the customer has to check if the flag has been set. Ada provides a third method, which is much more convenient: (c) The library routine signals an error; the user has a section in his/her program that traps selected errors and handles them accordingly. If the user does not provide such an error trap, it is possible to work your own trap in. If neither you nor the user provide a trap for this error, it is trapped by the system and the program stops. The result of the last situation is similar to the result of method (a), but you still can signal a more descriptive message than something like "Division by zero", which is what you would get if the system raised the error instead of your own routine. (3) Meaningful routine names. FORTRAN limits all names to 6 characters; I don't know if FORTRAN-77 still has that restriction. I do not recall reading anything about name length restrictions in the Ada standard, but if there is one, it is *very* generous. In addition to that advantage, Ada allows to call similar routine that take parameters of different types by the same name. This technique is called "overloading the name", and there is nothing negative about it, despite the way it sounds. This extends to the ability to overload existing operators, such as '+' and '**'. (Unlike Algol-68, there is no way to create new operators, only overload the existing ones. Overloaded operators have the same precedence within arithmetic expressions as their counterparts for integers.) (4) Ability to pass parameters by name (instead of just their relative positions within the call) or not to pass them at all. Many statistical library routines have a dozen or two of arguments, most of which the user wants to default to their usual values. In most languages, the best way to do this is to pass some agreed-upon value, usually 0, which will be replaced with the default value by the routine. So the call might look like CALL FUNFNC (1985, 34, 0,0,0,0,0, -23, 0,0,0,0, 1, 0,0,0,0,0,0) In Ada, it would like this: FUNNY_FUCNTION (YEAR:=1985, DISTRICT:=34, PENALTY:=-23, COEFFICIENT:=1); The order of the parameters, when passed by name, does not matter. If you were a customer, which statement would you prefer to use? Well, if you do want to pass values for most of the parameters, you might prefer memorizing their positions to spelling out the name for each of them. But even that is easier to do in Ada: FUNNY_FUNCTION (1985, 34, ,,,,, -23, ,,,, 1, ,,,,,); And there is no confusion over which parameter gets the default value, and which actually gets the value of zero! (5) Ability to pass multi-dimensional arrays, where any dimension can be of any size. The bottom and top index of each dimension get passed automatically. Thus, you can easily write a routine that, for example, multiplies two matrices, without knowing in advance the size of either matrix. (6) Source code savings through generic coding. You can write a routine that operates on data of some generic type (or types), and then create, in a simple declaration, instances of that routine that operate on specific types of data. For example, you could have a generic library called MATRIX_MATH that works on matrices where each element is of type ELEM_TYPE. Then you can create an instance of this library that works on real numbers by declaring (I'm not sure if I remember the exact syntax) REAL_MATRIX : MATRIX_MATH(REAL); and an instance of the same library that works on matrices of complex numbers by declaring COMPLEX_MATRIX : MATRIX_MATH(COMPLEX); Meanwhile, inside the source code for your generic library, all matrix elements are declared to be of type ELEM_TYPE, which will be replaced with REAL during compilation of the first instance and with COMPLEX during the compilation of the second instance. Also during the compilation, all references to operators and functions that take elements of type ELEM_TYPE will be replaced with calls to the appropriate routines (remember overloading?). Other advantages of Ada include: (1) Ability to write modular, yet efficient code. If readability concerns warrant putting a code segment into a separate procedure, but the procedure is to be called from within a frequent loop, the compiler can be told to expand the procedure inline. This way, you do not lose time on procedure calls during execution, and you don't have to sacrifice readability for efficiency. (2) Ability to write parallel programs. Many numerical solutions can utilize parallel programming. This is especially true for solutions that use matrices. Again, I apologize for the length of this posting. I welcome all arguments against what I said (or neglected to say). All flames concerning Ada, though, divert to /dev/null, or its equivalent on your system. Jacob Gore Hewlett-Packard Instrument Systems Lab (until 9/13/85) {ihnp4 or hplabs}!hpfcla!hpisla!gore Northwestern Univ. Comp. Sci. Research Lab (afterwards) 2145 Sheridan Rd Evanston, IL 60201