Fortran x**n vs. x**y
David G. Hough at validgh
dgh
Sat Sep 9 20:29:50 PDT 1995
Like many other, but not all, Fortran compilers, Sun's evaluates x**n by
O(logn) multiplications, and x**y using exp and log. Of course the
results vary between x**n and x**dble(n).
Sun got a bug report on this, to which I responded as follows. I'm interested
in comments from this group.
> Not a bug.
>
> The underlying problem is expressed in Fortran (not in C since x**n has no
> analog there) is that
>
> double precision x, y
> integer n
>
> x= 1.0000003205183601d0
> y= -2147483648.0d0
> n=y
> print *,x,y,' x**y ',x**y
> print *,x,n,' x**n ',x**n
> print *,x-x,y-n,' diff ',x**y-x**n
> end
>
> produces
>
> 1.0000003205184 -2147483648.0000 x**y 1.1795298980653-299
> 1.0000003205184 -2147483648 x**n 1.1795296972117-299
> 0. 0. diff 2.0085364200187-306
>
>
> This is pretty much an inevitable difference in the way x**y and x**n are
> customarily evaluated, by log+exp and by repeated multiplication. x**n is a poor choice for large |n|, as it's usually
> evaluated by repeated multiplication; x**y should be used instead, in the
> program source code. The following expanded example demonstrates the
> deteriorating accuracy due to the rounding accompanying each multiplication:
>
> double precision x, y
> integer n
>
> x= 1.0000003205183601d0
> n=-1
> do 1 i = 1, 32
> y=n
> print *,x,y,' x**y ',x**y
> print *,x,n,' x**n ',x**n
> print *,x-x,y-n,' rel diff ',(x**y-x**n)/x**y
> n=2*n
> 1 continue
> end
>
>
> This should be clearly documented in the Sun Numerical Computation Guide,
> and the reasons explained.
>
> The only alternative is to implement x**n in a more complicated way, switching
> to x**y if appropriate based on a-priori error bounds, or when
> more efficient, but that
> defeats the purpose of x**n.
>
> I suspect the original problem involves interest rates or other exponential
> growth computations. There the appropriate solution is to use
> compound(3m) or annuity(3m) or their Fortran analogs.
>
> Note that if there is any uncertainty at all in x close to 1, when raised to
> a large |n|,
> the relative uncertainty in x**n or x**y will be much greater than
> the relative uncertainty in x. So even the x**n algorithm provides a
> satisfactory backward error analysis.
> But as an extra bonus, we provide x**y which uses
> implicit higher precision to provide a satisfactory forward error analysis,
> which is as good as we can hope for, short of correct rounding. It's slower,
> of course.
>
> The foregoing addresses the differences between x**n and x**y as expressed in
> source code. Just in case the issue is the compiler front end converting
> x**y to a fixed series of multiplications and divisions
> when y is known at compile time to be a fixed integer K,
> we have a more serious problem. That optimization is safe
> enough when y is known at compile time to be -1, 0, 1, or 2,
> and perhaps tolerable for 3 and 4, but should probably be foregone otherwise.
More information about the Numeric-interest
mailing list