|
 |
 |
 |
 |
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
|
 |
 |
 |
 |
|