real( double ) :: t, phi
t = 5+tan(phi)
I think this should not result in a precision loss, is it?
What about division?
t = 5+tan(phi) / 3 ?
Cheers
-Ralf
Those integers are promoted automatically to real(double) before adding,
an exact operation. The compiler would choose whether it is at compile
or run time. Certain compilers may promote /3 to *1/real(3,double) at
compile time (at full optimization) but would do the same with /3_double.
For add, subtract, multiply and divide if the other operand is an
appropriate REAL kind then an integer will be converted to the
same kind before the operation. There should be no loss.
In days past there were suggestions that some might do the conversion
at run time, but that should not be a problem for any current compiler.
> What about division?
If both arguments are integers then integer division will be done.
Otherwise it should be fine.
> t = 5+tan(phi) / 3 ?
For powers, you normally want an integer for the power if it
is actually integer. That is, use x**3 instead of x**3.0D0.
Also, not that unlike some other languages you still can't
do tan(3) and have an appropriate conversion done for you.
-- glen
However, a formula like:
t = 0.1 + tan(phi)
will result in a loss of precision, if t and phi are double precision.
0.1 is still a single-precision literal and that gets promoted to
double precision with the addition.
So in that case:
t = 0.d0 + tan(phi)
is the correct way to proceed.
Probably better to avoid literals and use parameters instead. Then
the precision can be controlled in one place.
Regards,
Arjen
http://en.wikipedia.org/wiki/Accuracy_and_precision
I would say that the pricision is fine, but the accuracy is not.
The multiplication will be done in double precision with a value
that is not as close to 0.1d0 as it should be. (Assuming binary
hardware.) Small changes in tan(phi) will result in appropriate
small changes in t (precision), but likely the wrong value for t.
> So in that case:
> t = 0.d0 + tan(phi)
> is the correct way to proceed.
> Probably better to avoid literals and use parameters instead. Then
> the precision can be controlled in one place.
For the example given, the accuracy is even worse than for 0.1
due to a typographic error. 0.d0 is not better than 0.1e0 in
this case.
-- glen
No, you are quite right :). I wanted an example with non-integer
values ... and there I go!
Regards,
Arjen
With whole number values, there is no precision loss.
However, you need to be careful to ensure that integer arithmetic is avoided.
What you need to worry about is values containing fractions,
especially things like 0.1 whucg need D0 appended if you
are using double precision (and other appendage for other extended precisions).
Especially important if x is negative.
um, 0.1D0
> However, a formula like:
>
> t = 0.1 + tan(phi)
>
> will result in a loss of precision, if t and phi are double precision.
> 0.1 is still a single-precision literal and that gets promoted to
> double precision with the addition.
That's a good specific example, and one of the more common kinds of
problems. I also think it well illustrates what I consider to be the
most important issue in this area. In particular,
One should learn the rules (they aren't horribly complicated) and pay
deliberate attention to the type and kind of everything. It is ok (in my
estimation) to use some of those rules to make a formula look (and thus
read) a little simpler. I've been known to use things like
2*some_real_expression myself. But it is not ok to shortcut the thinking
part. One should understand what rule allows each notational shortcut
that you might make.
If you get in the habit of making notational shortcuts without thinking
about them, eventually you will screw up - pretty much guaranteed.
The major rules of interest (very informally stated) are
1. Watch out for literal constants, as above. They are not converted (at
least per the standard) until what I'd just summarize as too late. Thus
only shorten literal constants in cases where they are exact. Mostly,
that means integer values. Shortening 3.0d0 to 3 may be ok, depending on
the other rules. Shortening 0.3d0 or 0.3 is not. Some compilers might
"help" you by figuring out what you probably meant in some cases. I
personally regard that "help" as a negative that just hides the problem.
2. Type and kind promotion happens only operation by operation. The
"lowest" type/kind in a particular operation is promoted to the highest.
You can *NOT* just look for the highest type/kind in the whole
expression and assume that will apply everywhere. For example, in
double+single/3, the single/3 operation will be done in single precision
because that is the highest type/kind of its operands. The fact that
there is a double close by in the expression is irrelevant. The addition
will be done in double precision, but the division will not be (at least
per the standard). Likewise in double+tan(2.0), the tan function is the
single precision version, and, as noted elsewhere tan(2) is just
nonstandard (unless you have extended the tan generic yourself).
3. Exponentiation is a special case. real**integer is not promoted (and
you don't want it to be).
4. Particularly watch out for integer division. 1/3 is 0. This isn't
actually a special rule. It is more a consequence of rule 2 above. It
just happens to be a particularly egregious example.
--
Richard Maine | Good judgment comes from experience;
email: last name at domain . net | experience comes from bad judgment.
domain: summertriangle | -- Mark Twain
cheers
-ralf
I think some people like the D0 as a reminder that it is in
double precision.
-- glen