|
|
 |
 |
 |
 |
Fortran Programming Language
|
 |
 |
 |
 |
 |
 |
 |
 |
"typedef" in F95/2003?
I have a program that I want to recompile to use different floating point precisions. A lot of compilers support a command-line option to switch the default real type from single to double or quad, e.g. Intel: -real_size 32,64,128 GNU Fortran: -fdefault-real-4,8 Portand Group: -r4,8,16 Sun F95: -xtypemap=real:32,64 so until now, I have been using the default real kind and compiler switches. However, the time has come to use some of DH Bailey and Yozo Hida's work, which means substituting (for example) type(qd_real) for real in the declarations. If I'm going to go through the code to do this, what I would really like to do is something like "typedef" in C, e.g. something like typedef float my_real for single precision typedef double my_real for double precision typedef qd_real my_real for quad-double precision. All the declarations would use the "my_real" type instead of an explicit type. Can this sort of thing be done in Fortran 95/2003? Thanks, Chip -- Charles M. "Chip" Coldwell "Turn on, log in, tune out"
Chip Coldwell <coldw @frank.harvard.edu> wrote: > I have a program that I want to recompile to use different floating point > precisions. A lot of compilers support a command-line option to switch > the default real type from single to double or quad, e.g. (I won't go into all the fine points of why I generally recommend against using options like that.... since you are asking about moving away from that method anyway.) > If I'm going to go through the code to do this, what I would really like > to do is something like "typedef" in C, e.g. something like > typedef float my_real > for single precision ... > Can this sort of thing be done in Fortran 95/2003?
Not with that syntax, but yes. Are you aware of the kind type parameter facility of f90? That was one of the major new features of f90. It sute simplified my life a lot, as I used to spend lots of tiem converting codes between single and double precision (in days when compilers didn't tend to have have such switches at all). You define a type parameter (which is an integer - some of us don't like that, but that's the way it is). Best to do it in a module, such as module precisions integer, parameter :: my_real = ....an_appropriate value end module precision There are several options for selecting the appropriate value. Often the selected_real_kind intrinsic does just what you want. Or if you know that you want single/double/quad, you can use something like kind(0.0) or kind(0.0d0) or kind(non_portable_quad_literal). Or you can just hard-wire the compiler dependent values. Hard-wiring does require changing the code for different compilers, but it is only a single line of code for the whole program. Elsewhere in the program, do things like subroutine whatever use precisions real(my_real) :: x Note that you do have to say real(my_real) instead of just my_real. Note also that you can then use this kind parameter for other things such as literal constants. For example 1.2345678_my_real is a literal constant of the appropriate kind. -- Richard Maine | Good judgement comes from experience; email: last name at domain . net | experience comes from bad judgement. domain: summertriangle | -- Mark Twain
Richard Maine wrote:
(snip on typedef and Fortran) > Note that you do have to say real(my_real) instead of just my_real. Note > also that you can then use this kind parameter for other things such as > literal constants. For example 1.2345678_my_real is a literal constant > of the appropriate kind.
The most common use for typedef in C is for structure types where it avoids having to say struct in from of a structure type. It seems, then, that having to say real() around a real kind is somewhat the same as having to say struct in from of a struct type. Most of the time it doesn't bother me to say struct, though. Another solution is to use a preprocessor. #define my_real real(my_real) assuming it doesn't do recursive evaluation. -- glen
On Wed, 23 May 2007, Richard Maine wrote: > Not with that syntax, but yes. Are you aware of the kind type parameter > facility of f90?
Yes, and that isn't going to work. Suppose, for example, my compiler supports (in addition to the command line switches) kind type parameters 4, 8 and 16 for real. I.e. real(kind=4) is single precision real(kind=8) is double precision real(kind=16) is quad precision Now, what I want to do is use Yozo Hida's quad-double in place of reals -- that means that all of the variables that are reals in the single precision version become structures in the quad-double version. Because of the operator overloading I can do the following type(qd_real) :: x = qd_one type(qd_real) :: y = qd_zero if (x + y .eq. qd_one) then print *, "Yahoo, it works!" end if etc. etc. The type(qd_real) is implemented as an array of four doubles wrapped by a structure. Actually, it's implemented in C++, but they provide a Fortran interface. For your suggestion to work, I would have to be able to define a *new* type kind parameter for real that the compiler isn't aware of already. I don't think that can be done. Chip -- Charles M. "Chip" Coldwell "Turn on, log in, tune out"
Chip Coldwell <coldw @frank.harvard.edu> wrote: > On Wed, 23 May 2007, Richard Maine wrote: > > Not with that syntax, but yes. Are you aware of the kind type parameter > > facility of f90? > Yes, and that isn't going to work.... > Now, what I want to do is use Yozo Hida's quad-double in place of reals -- > that means that all of the variables that are reals in the single > precision version become structures in the quad-double version..... > The type(qd_real) is implemented as an array of four doubles wrapped by a > structure. Actually, it's implemented in C++, but they provide a Fortran > interface. > For your suggestion to work, I would have to be able to define a *new* > type kind parameter for real that the compiler isn't aware of already. I > don't think that can be done.
Ah. I see. I didn't recognize that as what you were asking for. Yes, that would be useful. In fact, I was once agitating in favor of a typealias facility in f2003 for exactly that reason - so that I could use an intrinsic type where available and a derived type substitute otherwise. Typealias (that's what it was called) was actually in the f2003 draft until pretty late in the process. It got pulled for various reasons. I forget all the details, but I do recall it being pointed out to me that it would not actually have achieved this functionality in practice. Yes, you could declare variables and have defined operators. But there are too many other parts of the language where things would fall apart. Probably the simplest one is literal constants. But there were also a bunch of others. I don't recall all the details (except fot the literal constant thing), but I do recall being convinced that the typealias facility didn't really work for that problem. Perhaps a more complicated facility might have, but the "simple" one that was in the f2003 draft wasn't coming close. -- Richard Maine | Good judgement comes from experience; email: last name at domain . net | experience comes from bad judgement. domain: summertriangle | -- Mark Twain
On Wed, 23 May 2007, Richard Maine wrote: > Yes, you could declare variables and have defined operators. > But there are too many other parts of the language where things would > fall apart. > Probably the simplest one is literal constants.
I don't get it. What falls apart with literal constants as a result of introducing typedef/typealias into the language? Chip -- Charles M. "Chip" Coldwell "Turn on, log in, tune out"
Chip Coldwell <coldw @frank.harvard.edu> wrote: > On Wed, 23 May 2007, Richard Maine wrote: > > Yes, you could declare variables and have defined operators. > > But there are too many other parts of the language where things would > > fall apart. > > Probably the simplest one is literal constants. > I don't get it. What falls apart with literal constants as a result of > introducing typedef/typealias into the language?
How do you write one of these quad precision literal constants? Answer: you don't - not in any way that automatically converts with the typedef. They are structure constructors instead. -- Richard Maine | Good judgement comes from experience; email: last name at domain . net | experience comes from bad judgement. domain: summertriangle | -- Mark Twain
On Wed, 23 May 2007, Richard Maine wrote: > Chip Coldwell <coldw @frank.harvard.edu> wrote: > > On Wed, 23 May 2007, Richard Maine wrote: > > > Yes, you could declare variables and have defined operators. > > > But there are too many other parts of the language where things would > > > fall apart. > > > Probably the simplest one is literal constants. > > I don't get it. What falls apart with literal constants as a result of > > introducing typedef/typealias into the language? > How do you write one of these quad precision literal constants? Answer: > you don't - not in any way that automatically converts with the typedef. > They are structure constructors instead.
I'm still confused. I'm not aware of any requirement that every derived type must be representable as a literal constant, if that's what you meant. If you mean literal constants as intializers of a derived type that has been typedef'd/typealias'd, then the problem is solved in C++ by requiring a constructor that takes a single formal parameter of the same time as the literal constant -- so if you had typedef class qd_real my_real; and the qd_real class contained a constructor that takes a single floating point argument then you could write: my_real foo(void) { my_real one = 1.0; my_real two = 2.0; return one + two; }
and it does what you want. Plus, I can go back later and alter the one line to read typedef double my_real; and it still does what I want after a recompile. You can get nearly the same result by defining assignment operators in Fortran 95, and in fact that is what qd does, except that I can't use the type alias. I can write function foo type(qd_real) :: foo type(qd_real) :: one = 1.0 type(qd_real) :: two = 2.0 foo = 1.0 + 2.0 end function foo But if I want to switch between native data types and derived data types, I have to re-write that function or use a preprocessor as was suggested earlier. Chip -- Charles M. "Chip" Coldwell "Turn on, log in, tune out"
In article <1hyk8on.1ihaepv2jq7c4N%nos@see.signature>, Richard Maine <nos @see.signature> wrote: >Chip Coldwell <coldw @frank.harvard.edu> wrote: >> I have a program that I want to recompile to use different floating point >> precisions. >There are several options for selecting the appropriate value. Often the >selected_real_kind intrinsic does just what you want.
I don't know if this will help Chip, but if you use some compilers that offer quad precision and some that don't, (a situation I'm in from time to time), the following cunning ploy, which I saw here some time ago, will make a REAL(hp) variable higher precision than double if that's available, but double precision if not. INTEGER, PARAMETER :: dp = kind(1d0), & qp = selected_real_kind(precision(1d0)+2), & hp = (dp*(1-sign(1,qp))+qp*(1+sign(1,qp)))/2 -- John Harper, School of Mathematics, Statistics and Computer Science, Victoria University, PO Box 600, Wellington 6140, New Zealand e-mail john.har@vuw.ac.nz phone (+64)(4)463 5341 fax (+64)(4)463 5045
On Wed, 24 May 2007, John Harper wrote: > I don't know if this will help Chip, but if you use some compilers that > offer quad precision and some that don't, (a situation I'm in from time > to time), the following cunning ploy, which I saw here some time ago, > will make a REAL(hp) variable higher precision than double if that's > available, but double precision if not. > INTEGER, PARAMETER :: dp = kind(1d0), & > qp = selected_real_kind(precision(1d0)+2), & > hp = (dp*(1-sign(1,qp))+qp*(1+sign(1,qp)))/2
That's a cute trick, but not really what I'm looking for. My original post was pretty obfuscated by the discussion of default real kinds, etc. What I really want to be able to do is declare variables that are of type my_real, where during one compile my_real is a native real(kind=something) type and during a subsequent recompile my_real is a derived data type (from Hida/Bailey's package). Chip -- Charles M. "Chip" Coldwell "Turn on, log in, tune out"
Chip Coldwell <coldw @frank.harvard.edu> wrote: > On Wed, 23 May 2007, Richard Maine wrote: > > Chip Coldwell <coldw@frank.harvard.edu> wrote: > > > On Wed, 23 May 2007, Richard Maine wrote: > > > > Yes, you could declare variables and have defined operators. > > > > But there are too many other parts of the language where things would > > > > fall apart. > > > > Probably the simplest one is literal constants. > > > I don't get it. What falls apart with literal constants as a result of > > > introducing typedef/typealias into the language? > > How do you write one of these quad precision literal constants? Answer: > > you don't - not in any way that automatically converts with the typedef. > > They are structure constructors instead. > I'm still confused. I'm not aware of any requirement that every derived > type must be representable as a literal constant, if that's what you > meant.
No. I mean that you can't take the same source code, change just the typealias/typedef/whatever, and have the code continue to work. Sure, there are some very limitted cases where you can do that, but the limitations turn out to be too strong to be useful. In practice, you wouldn't be able to do it for most useful codes. > You can get nearly the same result by defining assignment operators in > Fortran 95,
No, you can't. Literal constants appear in other contexts than as the sole thing on the RHS of an assignment. If you do foo = 1.23 then the 1.23 is a single precision constant. Nothing you can do with a defined assignment will change that. If foo is a double or a quad, you'll have just lost precision. And if you do call sub(1.23) then assignment doesn't have anything to do with the question. If the dummy argument is anything other than a single real, then it won't work at all. For another example, your > function foo > type(qd_real) :: foo > type(qd_real) :: one = 1.0 > type(qd_real) :: two = 2.0
Is invalid because initializers don't use defined assignment, even if you have such a thing. If they did use defined assignment, you'd still have the precision problem with most values; 1.0 and 2.0 are not particularly difficult cases that stretch the limits. You are just talking about ways to avoid using quad literal copnstants. That's not the same thing as defining how to write them. Yes, you could probably restrict yourself to writing code that would work. You'd have to be very restrictive - more so than the above example, which as I noted won't work. It was judged that, on the whole, this would work so poorly for this purpose that it would be a disservice to claim that the typealias feature addressed this problem, when most users would find that it wouldn't work for them in practice. If you disagree with that judgement, so be it. -- Richard Maine | Good judgement comes from experience; email: last name at domain . net | experience comes from bad judgement. domain: summertriangle | -- Mark Twain
On Wed, 23 May 2007, Richard Maine wrote: > Chip Coldwell <coldw @frank.harvard.edu> wrote: > > You can get nearly the same result by defining assignment operators in > > Fortran 95, > No, you can't. Literal constants appear in other contexts than as the > sole thing on the RHS of an assignment. If you do > foo = 1.23 > then the 1.23 is a single precision constant.
Right, and "foo" is whatever I've declared it to be. In the case of the quad double types from the Hida/Bailey package, there exists a defined assignment operator for this combination. > Nothing you can do with a defined assignment will change that. If foo is > a double or a quad, you'll have just lost precision.
How do you figure that? If I put a single precision value (the literal constant) into a quad double variable, I've gained precision, right? > And if you do > call sub(1.23) > then assignment doesn't have anything to do with the question. If the > dummy argument is anything other than a single real, then it won't work > at all.
Right, but it could. In C++, if "sub" were declared with a quad double dummy argument, the compiler would generate a temporary quad double variable, assign the single precision value 1.23 to it using the defined assignment operator, and then pass the temporary to the called function. Clearly that's not possible unless "sub" has an explicit interface, so perhaps it's ruled out for Fortran on that basis. > For another example, your > > function foo > > type(qd_real) :: foo > > type(qd_real) :: one = 1.0 > > type(qd_real) :: two = 2.0 > Is invalid because initializers don't use defined assignment, even if > you have such a thing.
Fair enough. Bad example. > You are just talking about ways to avoid using quad literal copnstants. > That's not the same thing as defining how to write them.
In practice, the authors of the library solved this problem by providing functions for assignment to quad double variables from character strings. So put your literal in quotes if you need the full precision to represent its value. However, that is not my point; in fact, this whole discussion has wandered off into the weeds. I'm not worried about precision, or the loss thereof. I'm not arguing about whether or not you need to be able to represent literal constants of an arbitrary derived type. What I am trying to understand is why introducing "typealias" into the language makes coping with literal constants more difficult for the compiler writer. Maybe I'm a little thick about this, but I just don't understand your explanation. > It was judged that, on the whole, this would work so poorly for this > purpose that it would be a disservice to claim that the typealias > feature addressed this problem, when most users would find that it > wouldn't work for them in practice. If you disagree with that judgement, > so be it.
I don't agree or disagree. I simply don't understand the basis for that judgement. Chip -- Charles M. "Chip" Coldwell "Turn on, log in, tune out"
Chip Coldwell wrote: > If you mean literal constants as intializers of a derived type that has > been typedef'd/typealias'd, then the problem is solved in C++ by requiring > a constructor that takes a single formal parameter of the same time as the > literal constant -- so if you had > typedef class qd_real my_real; > and the qd_real class contained a constructor that takes a single floating > point argument then you could write: > my_real foo(void) > { > my_real one = 1.0; > my_real two = 2.0; > return one + two; > } > and it does what you want. Plus, I can go back later and alter the one > line to read > typedef double my_real; > and it still does what I want after a recompile.
Yes. But: my_real one = 1.0/3.0 does not do what you want. Nor, for that matter, does my_real one = 0.1 In both cases, because your literal is of default real type rather than the typedef'ed type, you get degraded precision. Even between just single and double precision, this seems to turn up as a bug in someone's code here about once every other month, at least. - Brooks -- The "bmoses-nospam" address is valid; no unmunging needed.
Chip Coldwell <coldw @frank.harvard.edu> wrote: > On Wed, 23 May 2007, Richard Maine wrote: > > foo = 1.23 > > If foo is a double or a quad, you'll have just lost precision. > How do you figure that? If I put a single precision value (the literal > constant) into a quad double variable, I've gained precision, right?
No! No! No! 100 times no. This is a fundamental error regularly made by new users and corrected here. Precision, like virginity, is never regained once lost. (Though it isn't that good an analogy, as precision isn't such an all-or-nothing thing). You have converted it to a quad precision representation, but that does *NOT* get you a value accurate to quad precision; i.e. it does not have that precision - just that representation. This is *NOT* the same thing. > > And if you do > > call sub(1.23) > > then assignment doesn't have anything to do with the question. > Right, but it could. In C++,...
No, it can't. This is Fortran - not C++. If you want to redo the entire language from ground up, then that's another matter. You'll also break existing codes in the process. That doesn't fit well in Fortran. And even if it did, you are just illustrating the point - that just defining a typealias/typedef is not a simple method of providing the functionality in question. You are proposing redefining other language fundamentals that have implications all over the place. Suddenly typealias isn't such a simple addition any more. I wouldn't claim that it is impossible to make something like typealias work. If I mistakenly impled that, I didn't mean to. However, making it work well for that functionality is not at all simple. If you expect that functionality out of it, then you have to at the very least do huge amounts of work elsewhere in the language. That wasn't going to happen at the time. No way. That wasn't even suggested. This came up quite late in the f2003 process. I think it was in the public review of the FCD. The question at hand was whether to leave it in as is or take it out. > if "sub" were declared with a quad double > dummy argument, the compiler would generate a temporary quad double > variable, assign the single precision value 1.23 to it using the defined > assignment operator, and then pass the temporary to the called function. > Clearly that's not possible unless "sub" has an explicit interface, so > perhaps it's ruled out for Fortran on that basis.
No, that's not the only basis. Argument passing has implications all over the place. For example, you just broke generic resolution - rather badly, I might add - if actual arguments are compatible with any dummy that there is an appropriate assignment for. (Sounds more like PL/I). You've also either done funny things to arguments that aren't intent(in) or you have made the rules for intent(in) argument agreement different from all others. > What I am trying to understand is why > introducing "typealias" into the language makes coping with literal > constants more difficult for the compiler writer.
It doesn't. So that's why you keep having trouble understanding why it does. Difficulty of implementation is not the only criteria for adding things to the language. I don't recall it being particularly a point at all for this feature. Heck, you probably can sort of do it as a user right now without bothering the compiler writers. Just use your favorite macro processor as a preprocessor for your code. The result you'll get is not a lot different from what the proposed typealias feature was. The judgement was that the feature did not achieve the stated goal of making it practical to write code that could easily be converted between intrinsic and derived types. I said nothing at all about implementation difficulty. There were also other issues with typealias, but they were unrelated to this. (And I'm quite tired enough of this discussion that I'm not going to wander off into them, but it was argued that typalias as proposed wasn't going to do those jobs well either). In fact, this wasn't even the main reason typealias was proposed. I've just been concentrating on why this use of type alias didn't provide a basis for keeping it. -- Richard Maine | Good judgement comes from experience; email: last name at domain . net | experience comes from bad judgement. domain: summertriangle | -- Mark Twain
Chip Coldwell wrote: > On Wed, 23 May 2007, Richard Maine wrote: >> No, you can't. Literal constants appear in other contexts than as the >> sole thing on the RHS of an assignment. If you do >> foo = 1.23 >> then the 1.23 is a single precision constant. > Right, and "foo" is whatever I've declared it to be. In the case of the > quad double types from the Hida/Bailey package, there exists a defined > assignment operator for this combination. >> Nothing you can do with a defined assignment will change that. If foo is >> a double or a quad, you'll have just lost precision. > How do you figure that? If I put a single precision value (the literal > constant) into a quad double variable, I've gained precision, right?
The literal "1.23" is equal to the exact value 1.23 plus some error, with that error being on the order of half the precision of a single-precision real variable. Your "foo" variable, on the other hand, as a quad-double, would normally expected to have a maximum numerical error that is substantially smaller than the error in a single-precision real variable. By assigning the literal "1.23" to your quad-double variable, you obtain a result that has substantially larger error (i.e., substantially less precision) than would be expected for a variable of its type. This error propagates through all of the calculations that are done with this variable, and to a rough approximation this will cause a comparable level of error in the final results. Thus, you have "lost precision" in your calculations, compared to what would have happened had you used a literal of the "correct" precision. (Or, conversely, if you look at it from the perspective of what happens if you change the type of "foo" -- you might be expecting to gain precision, but you haven't actually gained any; the error in foo compared to an exact 123/100 is the same as it was when foo was single-precision.) - Brooks -- The "bmoses-nospam" address is valid; no unmunging needed.
Chip Coldwell wrote: > I'm not worried about precision, or the loss thereof. I'm not arguing > about whether or not you need to be able to represent literal constants of > an arbitrary derived type. What I am trying to understand is why > introducing "typealias" into the language makes coping with literal > constants more difficult for the compiler writer. Maybe I'm a little > thick about this, but I just don't understand your explanation.
Richard's point is that, if one cannot type-alias literal constants (that is, one cannot write "1.23" in a way that it is equal to the closest representation of 123/100 for some type-aliased type, without the programmer knowing what the type is aliased to), then being able to type-alias variables does not produce the benefits that he was introducing the feature in order to provide. - Brooks -- The "bmoses-nospam" address is valid; no unmunging needed.
> That's a cute trick, but not really what I'm looking for. My original > post was pretty obfuscated by the discussion of default real kinds, etc. > What I really want to be able to do is declare variables that are of type > my_real, where during one compile my_real is a native real(kind=something) > type and during a subsequent recompile my_real is a derived data type > (from Hida/Bailey's package).
The only way out that I see is to use always use a derived type, even in the case where an intrinsic type would suffice. With an optimizing compiler, the resulting code shouldn't be too different with regard to performance - it's just somewhat more verbose (e.g., structure constructors instead of literals). Jan
On 2007-05-24, Richard Maine <nos@see.signature> wrote: > No! No! No! 100 times no. This is a fundamental error regularly made by > new users and corrected here. Precision, like virginity, is never > regained once lost.
Hmm... that last sentence really seems like a nice quote to use as a signature in my emails or on UseNet... tnx a lot Richard! ;-) Bart -- "Precision, like virginity, is never regained once lost." -- Richard Maine --
>>No! No! No! 100 times no. This is a fundamental error regularly made by >>new users and corrected here. Precision, like virginity, is never >>regained once lost. > Hmm... that last sentence really seems like a nice quote to use > as a signature in my emails or on UseNet... tnx a lot Richard! ;-)
Indeed. Of course, this goes back at least to Ludwig Boltzmann and the concept of increasing entropy, which translates to irreversible computation in this particular case. Jan
On Thu, 24 May 2007, [ISO-8859-1] Jan Vorbrggen wrote: > > That's a cute trick, but not really what I'm looking for. My original post > > was pretty obfuscated by the discussion of default real kinds, etc. What I > > really want to be able to do is declare variables that are of type my_real, > > where during one compile my_real is a native real(kind=something) type and > > during a subsequent recompile my_real is a derived data type (from > > Hida/Bailey's package). > The only way out that I see is to use always use a derived type, even in the > case where an intrinsic type would suffice. With an optimizing compiler, the > resulting code shouldn't be too different with regard to performance - it's > just somewhat more verbose (e.g., structure constructors instead of literals).
Actually, there is another solution, but it's pretty fugly: use implicit typing. IMPICIT TYPE(qd_real) (Q) Chip -- Charles M. "Chip" Coldwell "Turn on, log in, tune out"
On Thu, 24 May 2007, Bart Vandewoestyne wrote: > On 2007-05-24, Richard Maine <nos @see.signature> wrote: > > No! No! No! 100 times no. This is a fundamental error regularly made by > > new users and corrected here. Precision, like virginity, is never > > regained once lost. > Hmm... that last sentence really seems like a nice quote to use > as a signature in my emails or on UseNet... tnx a lot Richard! ;-)
Indeed, props to Richard for a nice turn of phrase. However, at the risk of being overly pedantic, let me point out that in this code: real(kind=16) :: foo foo = 1.23 no precision is *lost* in the assignment. The programmer may believe that he has a quad precision value called "foo" when he really has the single precision value, but he never had more than the single precision value to start with in the literal constant, hence nothing was lost. Yes, it is a trap for the unwary and I can believe that code like this generates lots of traffic for this newsgroup. Digging deeper into pedantry, let me point out that in this code: foo = 0.5 the value of "foo" *is* the quad precision value, not the single precision value. In fact, any integer power of 0.5 and any number exactly expressible as a sum of integer powers of 0.5 will not suffer when it's type is promoted: foo = 0.656 similarly is stored exactly with quad precision in the variable foo. This assumes a binary radix for floating point. IBM just announced a POWER6 CPU that can do decimal floating point, which means in principle one could write a compiler such that any single precision decimal literal constant would be stored as an exact value in a quad precision variable. Not directly relevant, but kinda interesting. Before somebody jumps on me, yes, I know this does not generalize and that when doing error analysis you must propagate the single precision errors through the quad precision variables even if the single precision value is the exact value of a binary floating point number. Chip -- Charles M. "Chip" Coldwell "Turn on, log in, tune out"
Chip Coldwell <coldw @frank.harvard.edu> wrote: > However, at the risk > of being overly pedantic, let me point out that in this code: > real(kind=16) :: foo > foo = 1.23 > no precision is *lost* in the assignment.
I quite agree. The precision is not lost in the assignment. The precision is lost in writing 1.23 instead of 1.23_16. That's why we got on the subject of literal constant syntax. It is the lack of a suitable lteral constant syntax for typealias that causes problems. I think that a comment was once made in teh discussion in J3 (might have even been made by me after I understood the problem - I forget) that typealias doesn't do a good enough job of hiding the underlying definition of the type; you still have to treat it like an intrinsic or derived type, depending which the underlying type is. -- Richard Maine | Good judgement comes from experience; email: last name at domain . net | experience comes from bad judgement. domain: summertriangle | -- Mark Twain
On 24 May, 16:20, Chip Coldwell <coldw@frank.harvard.edu> wrote:
> On Thu, 24 May 2007, Bart Vandewoestyne wrote: > > On 2007-05-24, Richard Maine <nos @see.signature> wrote: > > > No! No! No! 100 times no. This is a fundamental error regularly made by > > > new users and corrected here. Precision, like virginity, is never > > > regained once lost. > > Hmm... that last sentence really seems like a nice quote to use > > as a signature in my emails or on UseNet... tnx a lot Richard! ;-) > Indeed, props to Richard for a nice turn of phrase. However, at the risk > of being overly pedantic, let me point out that in this code: > real(kind=16) :: foo > foo = 1.23 > no precision is *lost* in the assignment. The programmer may believe that > he has a quad precision value called "foo" when he really has the single > precision value, but he never had more than the single precision value to > start with in the literal constant, hence nothing was lost. Yes, it is a > trap for the unwary and I can believe that code like this generates lots > of traffic for this newsgroup. > Digging deeper into pedantry, let me point out that in this code: > foo = 0.5 > the value of "foo" *is* the quad precision value, not the single precision > value. In fact, any integer power of 0.5 and any number exactly > expressible as a sum of integer powers of 0.5 will not suffer when it's > type is promoted: > foo = 0.656 > similarly is stored exactly with quad precision in the variable foo. > This assumes a binary radix for floating point. IBM just announced a > POWER6 CPU that can do decimal floating point, which means in principle > one could write a compiler such that any single precision decimal literal > constant would be stored as an exact value in a quad precision variable. > Not directly relevant, but kinda interesting. > Before somebody jumps on me, yes, I know this does not generalize and that > when doing error analysis you must propagate the single precision errors > through the quad precision variables even if the single precision value > is the exact value of a binary floating point number. > Chip > -- > Charles M. "Chip" Coldwell > "Turn on, log in, tune out"
Here is a simple program program ex02 implicit none integer , parameter :: long=selected_real_kind(15,307) real :: a,b,c real (long) :: la,lb,lc a=1.23 b=0.5 c=0.656 print *,a print *,b print *,c la=1.23 lb=0.5 lc=0.656 print *,la print *,lb print *,lc la=1.23_long lb=0.5_long lc=0.656_long print *,la print *,lb print *,lc end program ex02 here is the output from 3 compilers (Nag, Intel and Lahey) 1.2300000 0.5000000 0.6560000 1.2300000190734863 0.5000000000000000 0.6560000181198120 1.2300000000000000 0.5000000000000000 0.6560000000000000 1.230000 0.5000000 0.6560000 1.23000001907349 0.500000000000000 0.656000018119812 1.23000000000000 0.500000000000000 0.656000000000000 1.23000002 0.500000000 0.656000018 1.230000019073486 0.5000000000000000 0.6560000181198120 1.230000000000000 0.5000000000000000 0.6560000000000000 see richards subseqent post for more information. Ian Chivers
On Thu, 24 May 2007 ian_d_chiv@yahoo.co.uk wrote: > Here is a simple program
Well, I went and gave you a bad example again. I meant for 0.656 = 0.5 + 0.125 + 0.031 that last value was supposed to be 1.0/32.0, but it isn't. Please repeat your experiment with 0.65625 instead. Chip -- Charles M. "Chip" Coldwell "Turn on, log in, tune out"
Chip Coldwell wrote: > On Thu, 24 May 2007 ian_d_chiv @yahoo.co.uk wrote: >> Here is a simple program > Well, I went and gave you a bad example again. I meant for > 0.656 = 0.5 + 0.125 + 0.031 > that last value was supposed to be 1.0/32.0, but it isn't. Please repeat > your experiment with > 0.65625
Actually, your original example -- and Ian's subsequent test program -- is the good example; and the one above using 0.65625 and 0.03125 is the special case. Are you expecting to always do floating point arithmetic with reals that just happen to be exactly representable in base-2? That would be nice. I don't get to pick the numbers I work with so the difference between representation and precision is important. :o) cheers, paulv -- Paul van Delst Ride lots. CIMSS @ NOAA/NCEP/EMC Eddy Merckx
|
 |
 |
 |
 |
|